@@ -382,6 +382,7 @@ class row_actions:
382382 location : object = None
383383 jmp_to_order : int = - 1
384384 flow_fx : list = field (default_factory = list )
385+ ctx : object = None
385386 pre_fx : list = field (default_factory = list )
386387 ins : object = None
387388 vol : object = None
@@ -496,10 +497,10 @@ def convert_row(row, channel):
496497 out = row_actions ()
497498
498499 if is_empty (row ):
499- return out . jmp_to_order , []
500+ return out
500501
501502 out .location = nss_loc (location_order , location_channel , location_row )
502- out .flow_fx = factory .ctx ()
503+ out .ctx = factory .ctx ()
503504
504505 # note
505506 location_pos = (0 ,3 )
@@ -565,7 +566,7 @@ def convert_row(row, channel):
565566 out .fx .append (pan_op )
566567 # groove
567568 elif fx == 0x09 :
568- out .fx .append (groove (fxval ))
569+ out .flow_fx .append (groove (fxval ))
569570 # jump to order
570571 elif fx == 0x0b :
571572 out .jmp_to_order = fxval
@@ -574,7 +575,7 @@ def convert_row(row, channel):
574575 out .jmp_to_order = 256
575576 # speed
576577 elif fx == 0x0f :
577- out .fx .append (speed (fxval ))
578+ out .flow_fx .append (speed (fxval ))
578579 # FM OP1 level
579580 elif fx == 0x12 :
580581 out .fx .append (op1_lvl (fxval ))
@@ -658,17 +659,12 @@ def convert_row(row, channel):
658659 else :
659660 row_warn ("unsupported FX" )
660661
661- all_ops = [o if isinstance (o , list ) else [o ] if o else [] for o in
662- (out .location , out .flow_fx , out .pre_fx , out .ins , out .vol , out .fx , out .note , out .post_fx )]
663- flattened_ops = sum (all_ops , [])
664-
665- return out .jmp_to_order , flattened_ops
666-
662+ return out
667663
668664
669665
670666cached_nss = {}
671- def raw_nss (m , p , bs , channels , compact ):
667+ def raw_nss (m , p , bs , channels , compact , capture ):
672668 global location_order , location_row
673669
674670 # a cache of already parsed rows data
@@ -682,6 +678,12 @@ def row_to_nss(func, pat, pos):
682678 cached_nss [idx ] = func (location_data , pat .channel )
683679 return cached_nss [idx ]
684680
681+ def row_actions_to_nss (a ):
682+ all_ops = [o if isinstance (o , list ) else [o ] if o else [] for o in
683+ (a .location , a .flow_fx , a .ctx , a .pre_fx , a .ins , a .vol , a .fx , a .note , a .post_fx )]
684+ flattened_ops = sum (all_ops , [])
685+ return flattened_ops
686+
685687 # unoptimized nss opcodes generated from the Furnace song
686688 nss = []
687689
@@ -749,36 +751,25 @@ def row_to_nss(func, pat, pos):
749751 opcodes = []
750752 location_order , location_row = order , index
751753
752- # FM channels
753- for channel in f_channels :
754- j , f_opcodes = row_to_nss (convert_row , order_patterns [channel ], index )
755- if channel in selected_f :
756- opcodes .extend (f_opcodes )
757- jmp_to_order = max (jmp_to_order , j )
758- # SSG channels
759- for channel in s_channels :
760- j , s_opcodes = row_to_nss (convert_row , order_patterns [channel ], index )
761- if channel in selected_s :
762- opcodes .extend (s_opcodes )
763- jmp_to_order = max (jmp_to_order , j )
764- # ADPCM-A channels
765- for channel in a_channels :
766- j , a_opcodes = row_to_nss (convert_row , order_patterns [channel ], index )
767- if channel in selected_a :
768- opcodes .extend (a_opcodes )
769- jmp_to_order = max (jmp_to_order , j )
770- # ADPCM-B channel
771- for channel in b_channel :
772- j , b_opcodes = row_to_nss (convert_row , order_patterns [channel ], index )
773- if channel in selected_b :
774- opcodes .extend (b_opcodes )
775- jmp_to_order = max (jmp_to_order , j )
754+ # Get all the NSS opcodes produced by all the tracks for the current row
755+ all_actions = [row_to_nss (convert_row , order_patterns [c ], index ) for c in range (14 )]
756+
757+ # If needed, capture missing flow_fx from filtered channels and
758+ # make sure those fx are not lost by reinjecting them into
759+ # a channel that is part of the NSS output
760+ if capture :
761+ flows = [a .flow_fx for i , a in enumerate (all_actions ) if a .flow_fx and i not in channels ]
762+ all_actions [channels [0 ]].flow_fx .extend (sum (flows ,[]))
776763
777764 # all channels are processed for this pos.
778- # add all generated opcodes plus a time sync
779- pattern_opcodes .extend (opcodes + [wait_n (1 )])
765+ # add all generated opcodes for all channels in a flat,
766+ # plus a time sync to denote the end of row
767+ # pattern_opcodes.extend(opcodes + [wait_n(1)])
768+ channels_opcodes = [row_actions_to_nss (a ) for i , a in enumerate (all_actions ) if i in channels ]
769+ pattern_opcodes .extend (sum (channels_opcodes , []) + [wait_n (1 )])
780770
781771 # stop processing further rows if a JMP fx was used
772+ jmp_to_order = next ((a .jmp_to_order for a in all_actions if a .jmp_to_order != - 1 ), - 1 )
782773 if jmp_to_order != - 1 :
783774 break
784775
@@ -1557,9 +1548,10 @@ def remove_empty_streams(channels, streams):
15571548tempo_injected = False
15581549def generate_nss_stream (m , p , bs , ins , channels , stream_idx ):
15591550 compact = stream_idx >= 0
1551+ capture_flow_fx = stream_idx == 0
15601552
15611553 dbg ("Convert Furnace patterns to unoptimized NSS opcodes" )
1562- nss = raw_nss (m , p , bs , channels , compact )
1554+ nss = raw_nss (m , p , bs , channels , compact , capture_flow_fx )
15631555
15641556 # insert a tempo opcode on the first track that is used in the Furnace module
15651557 global tempo_injected
0 commit comments