File size: 8,552 Bytes
ac73ca8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
"""
LOGOS Playback Interpreter - Main Integration (SPCW Cake/Bake Protocol)
State-based reconstruction engine with persistent canvas state
"""

import sys
import os
import logging

# Optional UI dependencies (PyQt5). If missing, print guidance and exit gracefully.
try:
    from PyQt5.QtWidgets import QApplication, QFileDialog, QPushButton, QHBoxLayout
    from PyQt5.QtCore import QTimer
except ImportError as e:
    print("PyQt5 is required for main.py (legacy PyQt viewer).")
    print("Install with: pip install PyQt5")
    print("Alternatively, use the Tk launcher: python logos_launcher.py")
    sys.exit(1)

from stream_interpreter import StreamInterpreter, ChunkType
from playback_window import PlaybackWindow, StreamHarmonizer
from display_interpreter import LogosDisplayInterpreter, Mode

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('logos_interpreter.log'),
        logging.StreamHandler(sys.stdout)
    ]
)

logger = logging.getLogger('Main')


def binary_stream_generator(file_path, chunk_size=512):
    """
    Generator that yields 512-byte chunks from binary file
    
    Args:
        file_path: Path to binary file
        chunk_size: Size of each chunk (must be 512 for SPCW)
    
    Yields:
        bytes: 512-byte chunks
    """
    if chunk_size != 512:
        raise ValueError("SPCW protocol requires 512-byte chunks")
    
    with open(file_path, 'rb') as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            
            # Pad incomplete chunks to 512 bytes
            if len(chunk) < chunk_size:
                chunk = chunk + b'\x00' * (chunk_size - len(chunk))
            
            yield chunk


def create_sample_binary_file(output_path, num_atoms=100):
    """
    Create a sample binary file for testing
    Generates varied patterns including harmonized and non-harmonized heat codes
    
    Args:
        output_path: Path to output file
        num_atoms: Number of 512-byte atoms to generate
    """
    import numpy as np
    from stream_interpreter import GLOBAL_SCALAR_PRIME
    
    logger.info(f"Creating sample binary file: {output_path} ({num_atoms} atoms)")
    
    with open(output_path, 'wb') as f:
        for i in range(num_atoms):
            # Create 512-byte atom
            atom = bytearray(512)
            
            # Set heat code (first 4 bytes)
            if i % 3 == 0:
                # Create harmonized heat code (residue == 0)
                # Find a value that mod GLOBAL_SCALAR_PRIME == 0
                harmonized_value = (i * GLOBAL_SCALAR_PRIME) % (2**32)
                atom[0:4] = harmonized_value.to_bytes(4, byteorder='big')
            else:
                # Create non-harmonized heat code (residue != 0)
                non_harmonized_value = (i * 12345 + 1) % (2**32)
                atom[0:4] = non_harmonized_value.to_bytes(4, byteorder='big')
            
            # Fill wave payload (remaining 508 bytes) with patterns
            if i % 3 == 0:
                # META: Structured pattern (geometric)
                pattern = np.arange(508, dtype=np.uint8)
                atom[4:] = pattern.tobytes()
            else:
                # DELTA: Chaotic pattern (heat/noise)
                pattern = np.random.randint(0, 256, size=508, dtype=np.uint8)
                atom[4:] = pattern.tobytes()
            
            f.write(bytes(atom))
    
    logger.info(f"Sample file created: {output_path}")


def process_stream(file_path=None, mode=Mode.STREAMING):
    """Main stream processing function with state-based reconstruction"""
    # Initialize stream interpreter (for classification)
    stream_interpreter = StreamInterpreter(
        min_fidelity=256,
        max_fidelity=1024,
        global_scalar_prime=9973
    )
    
    # Initialize display interpreter (state reconstruction engine)
    display_interpreter = LogosDisplayInterpreter(mode=mode)
    
    harmonizer = StreamHarmonizer()
    
    # Setup PyQt application
    app = QApplication(sys.argv)
    
    # Create playback window with display interpreter reference
    window = PlaybackWindow(
        display_interpreter=display_interpreter,
        window_width=None,
        window_height=None
    )
    window.show()
    
    # Get file path
    if file_path is None:
        # Check if sample file exists
        sample_path = 'sample_logos_stream.bin'
        if os.path.exists(sample_path):
            file_path = sample_path
            logger.info(f"Using existing sample file: {file_path}")
        else:
            # Create sample file
            create_sample_binary_file(sample_path, num_atoms=500)
            file_path = sample_path
            logger.info(f"Created sample file: {file_path}")
    
    if not file_path or not os.path.exists(file_path):
        logger.error("No valid file path provided")
        window.status_label.setText("Error: No file selected")
        return
    
    # Process stream chunks
    stream_gen = binary_stream_generator(file_path, chunk_size=512)
    chunk_count = 0
    
    def process_next_chunk():
        """Process next chunk from stream"""
        nonlocal chunk_count
        try:
            chunk = next(stream_gen)
            chunk_count += 1
            
            # Step 1: Process through stream interpreter (classification)
            stream_result = stream_interpreter.process_chunk(chunk)
            
            # Step 2: Feed to display interpreter (state reconstruction)
            display_interpreter.process_atom(
                stream_result['atom_data'],
                stream_result['chunk_type']
            )
            
            # Step 3: Update viewport display
            window.update_display()
            
            # Step 4: Handle synchronization
            meta_markers = stream_interpreter.get_synchronization_markers()
            if meta_markers and stream_result['chunk_type'].value == "META":
                harmonizer.register_meta_marker(meta_markers[-1])
                sync_result = harmonizer.synchronize_buffers(
                    audio_chunk=chunk if stream_result['chunk_type'].value == "META" else None,
                    video_chunk=chunk,
                    data_chunk=chunk,
                    meta_markers=meta_markers
                )
            
            # Schedule next chunk processing
            # In streaming mode: 10 FPS (100ms delay)
            # In download mode: as fast as possible (1ms delay)
            delay = 100 if mode == Mode.STREAMING else 1
            QTimer.singleShot(delay, process_next_chunk)
            
        except StopIteration:
            logger.info(f"Stream processing complete. Processed {chunk_count} atoms.")
            
            # In download mode, export full fidelity frame
            if mode == Mode.DOWNLOAD:
                try:
                    full_frame = display_interpreter.get_full_fidelity_frame()
                    export_path = file_path.replace('.bin', '_export.png')
                    full_frame.save(export_path)
                    logger.info(f"Full fidelity frame exported to: {export_path}")
                    window.status_label.setText(
                        f"Processing complete! Exported to {export_path}"
                    )
                except Exception as e:
                    logger.error(f"Export failed: {e}")
                    window.status_label.setText(f"Stream processing complete ({chunk_count} atoms)")
            else:
                window.status_label.setText(f"Stream processing complete ({chunk_count} atoms)")
    
    # Start processing
    mode_str = "STREAMING" if mode == Mode.STREAMING else "DOWNLOAD"
    logger.info(f"Starting LOGOS Playback Interpreter - {mode_str} Mode")
    logger.info(f"Processing file: {file_path}")
    QTimer.singleShot(100, process_next_chunk)
    
    # Run application
    sys.exit(app.exec_())


if __name__ == "__main__":
    import sys
    file_path = sys.argv[1] if len(sys.argv) > 1 else None
    
    # Check for mode argument
    mode = Mode.STREAMING  # Default
    if len(sys.argv) > 2:
        if sys.argv[2].lower() == 'download':
            mode = Mode.DOWNLOAD
            logger.info("Running in DOWNLOAD mode (full fidelity export)")
        else:
            logger.info("Running in STREAMING mode (real-time viewport)")
    
    process_stream(file_path, mode=mode)