@ -62,7 +62,7 @@ class ArpeggiatorEngine(QObject):
NOTE_SPEEDS = {
" 1/32 " : 1 / 32 , " 1/32T " : 1 / 48 , " 1/16 " : 1 / 16 , " 1/16T " : 1 / 24 ,
" 1/8 " : 1 / 8 , " 1/8T " : 1 / 12 , " 1/4 " : 1 / 4 , " 1/4T " : 1 / 6 ,
" 1/2 " : 1 / 2 , " 1/2T " : 1 / 3 , " 1/1 " : 1 , " 2/1 " : 2 , " 4/1 " : 4
" 1/2 " : 1 / 2 , " 1/2T " : 1 / 3 , " 1/1 " : 1 , " 2/1 " : 2 , " 2/1T " : 4 / 3 , " 4/1" : 4 , " 4/1T " : 8 / 3
}
def __init__ ( self , channel_manager : MIDIChannelManager , synth_router : SynthRouter ,
@ -284,10 +284,20 @@ class ArpeggiatorEngine(QObject):
self . step_duration = note_duration / beats_per_second
def calculate_delay_step_duration ( self ) :
""" Calculate time between delay steps based on tempo and delay timing """
""" Calculate time between delay steps based on tempo and delay timing relative to note speed """
beats_per_second = self . tempo / 60.0
delay_note_duration = self . NOTE_SPEEDS [ self . delay_timing ]
self . delay_step_duration = delay_note_duration / beats_per_second
# Get current note speed duration
current_note_duration = self . NOTE_SPEEDS [ self . note_speed ]
# Get delay timing duration
delay_timing_duration = self . NOTE_SPEEDS [ self . delay_timing ]
# Calculate delay as multiple of note speed
delay_multiplier = delay_timing_duration / current_note_duration
# Calculate actual delay step duration
self . delay_step_duration = ( current_note_duration * delay_multiplier ) / beats_per_second
def schedule_delays ( self , channel : int , note : int , original_volume : int ) :
""" Schedule delay/echo repeats for a note """
@ -423,17 +433,46 @@ class ArpeggiatorEngine(QObject):
elif self . pattern_type == " random_chord " :
self . current_pattern = self . _generate_random_chord_pattern ( )
# Apply user pattern length by truncating or repeating the pattern
# Apply user pattern length intelligently based on pattern type
if self . current_pattern :
original_pattern = self . current_pattern . copy ( )
if len ( self . current_pattern ) > self . user_pattern_length :
# Truncate pattern to user length
self . current_pattern = self . current_pattern [ : self . user_pattern_length ]
elif len ( self . current_pattern ) < self . user_pattern_length :
# Repeat pattern to fill user length
while len ( self . current_pattern ) < self . user_pattern_length :
remaining_steps = self . user_pattern_length - len ( self . current_pattern )
self . current_pattern . extend ( original_pattern [ : remaining_steps ] )
# For directional patterns, adapt the pattern to fit the length
if self . pattern_type in [ " up_down " , " down_up " ] and self . user_pattern_length > = 4 :
# For up_down with 4 steps: take first half up, second half down
scale_notes = self . _generate_scale_notes ( )
half_length = self . user_pattern_length / / 2
if self . pattern_type == " up_down " :
# First half: up progression
up_part = scale_notes [ : half_length ] if len ( scale_notes ) > = half_length else scale_notes * ( ( half_length / / len ( scale_notes ) ) + 1 )
up_part = up_part [ : half_length ]
# Second half: down progression
down_part = list ( reversed ( scale_notes ) ) [ : half_length ] if len ( scale_notes ) > = half_length else list ( reversed ( scale_notes ) ) * ( ( half_length / / len ( scale_notes ) ) + 1 )
down_part = down_part [ : half_length ]
self . current_pattern = up_part + down_part
elif self . pattern_type == " down_up " :
# First half: down progression
down_part = list ( reversed ( scale_notes ) ) [ : half_length ] if len ( scale_notes ) > = half_length else list ( reversed ( scale_notes ) ) * ( ( half_length / / len ( scale_notes ) ) + 1 )
down_part = down_part [ : half_length ]
# Second half: up progression
up_part = scale_notes [ : half_length ] if len ( scale_notes ) > = half_length else scale_notes * ( ( half_length / / len ( scale_notes ) ) + 1 )
up_part = up_part [ : half_length ]
self . current_pattern = down_part + up_part
else :
# For other patterns, use the original logic
if len ( self . current_pattern ) > self . user_pattern_length :
# Truncate pattern to user length
self . current_pattern = self . current_pattern [ : self . user_pattern_length ]
elif len ( self . current_pattern ) < self . user_pattern_length :
# Repeat pattern to fill user length
while len ( self . current_pattern ) < self . user_pattern_length :
remaining_steps = self . user_pattern_length - len ( self . current_pattern )
self . current_pattern . extend ( original_pattern [ : remaining_steps ] )
self . pattern_length = len ( self . current_pattern )
self . pattern_position = 0