"""
MIDI playback state management.
"""
from collections import defaultdict
from dataclasses import dataclass, field
from typing import Literal, Optional
from mido import MidiFile
from PySide6.QtCore import QThread, QTimer
from jdxi_editor.midi.channel.channel import MidiChannel
from picomidi.constant import Midi
@dataclass
[docs]
class MidiPlaybackState:
"""State container for MIDI file playback."""
[docs]
active_notes: dict = field(default_factory=lambda: defaultdict(set))
[docs]
buffered_msgs: list = field(default_factory=list)
[docs]
buffer_end_time: float = 0.0
[docs]
channel_selected: Literal[
MidiChannel.DIGITAL_SYNTH_1,
MidiChannel.DIGITAL_SYNTH_2,
MidiChannel.ANALOG_SYNTH,
MidiChannel.DRUM_KIT,
] = MidiChannel.DIGITAL_SYNTH_1
[docs]
events: list = field(default_factory=list)
[docs]
event_index_current: int = 0
[docs]
event_index: Optional[int] = None
[docs]
event_buffer: list = field(default_factory=list)
[docs]
file: Optional[MidiFile] = None
[docs]
file_duration_seconds: float = 0.0
# New attributes for playback state
[docs]
suppress_control_changes: bool = field(default=True)
[docs]
suppress_program_changes: bool = field(
default=False
) # False = send PCs so inserted PCs are heard
[docs]
custom_tempo_force: bool = field(default=False)
[docs]
custom_tempo: int = field(
default=Midi.tempo.BPM_162_USEC
) # Default custom tempo in microseconds
[docs]
tempo_initial: int = field(default=Midi.tempo.BPM_120_USEC)
[docs]
tempo_at_position: int = field(default=Midi.tempo.BPM_120_USEC)
[docs]
timer: Optional[QTimer] = field(default=None)
# end of new attributes
[docs]
muted_tracks: set[int] = field(default_factory=set)
[docs]
muted_channels: set[int] = field(default_factory=set)
[docs]
playback_thread: Optional[QThread] = None
[docs]
playback_paused_time: Optional[float] = None
[docs]
playback_start_time: Optional[float] = None
[docs]
playback_paused: bool = False
[docs]
def __post_init__(self) -> None:
if self.custom_tempo_force:
self.tempo_at_position = self.custom_tempo # Use custom tempo if forced
else:
self.tempo_at_position = Midi.tempo.BPM_120_USEC # Default of 120 bpm