@@ -6,7 +6,6 @@ struct Channel {
66 volume : u8 ,
77 note_period : u16 ,
88 sample_position : neotracker:: Fractional ,
9- first_pass : bool ,
109 effect : Option < neotracker:: Effect > ,
1110}
1211
@@ -23,6 +22,9 @@ pub struct Player<'a> {
2322 position : u8 ,
2423 line : u8 ,
2524 finished : bool ,
25+ /// This is set when we get a Pattern Break (0xDxx) effect. It causes
26+ /// us to jump to a specific row in the next pattern.
27+ pattern_break : Option < u8 > ,
2628 channels : [ Channel ; 4 ] ,
2729}
2830
@@ -46,6 +48,7 @@ impl<'a> Player<'a> {
4648 clock_ticks_per_device_sample : neotracker:: Fractional :: new_from_sample_rate (
4749 sample_rate,
4850 ) ,
51+ pattern_break : None ,
4952 channels : [
5053 Channel :: default ( ) ,
5154 Channel :: default ( ) ,
@@ -61,7 +64,17 @@ impl<'a> Player<'a> {
6164 T : core:: fmt:: Write ,
6265 {
6366 if self . ticks_left == 0 && self . samples_left == 0 {
64- // yes it is time for a new line
67+ // It is time for a new line
68+
69+ // Did we have a pattern break? Jump straight there.
70+ if let Some ( line) = self . pattern_break {
71+ self . pattern_break = None ;
72+ self . position += 1 ;
73+ self . line = line;
74+ }
75+
76+ // Find which line we play next. It might be the next line in this
77+ // pattern, or it might be the first line in the next pattern.
6578 let line = loop {
6679 // Work out which pattern we're playing
6780 let Some ( pattern_idx) = self . modfile . song_position ( self . position ) else {
@@ -77,67 +90,71 @@ impl<'a> Player<'a> {
7790 self . position += 1 ;
7891 continue ;
7992 } ;
93+ // There was no need to go the next pattern, so produce this
94+ // line from the loop.
8095 break line;
8196 } ;
8297
8398 // Load four channels with new line data
84- let _ = write ! ( out, "{:03} {:06} " , self . position, self . line) ;
99+ let _ = write ! ( out, "{:03} {:06}: " , self . position, self . line) ;
85100 for ( channel_num, ch) in self . channels . iter_mut ( ) . enumerate ( ) {
86101 let note = & line. channel [ channel_num] ;
102+ // Do we have a new sample to play?
87103 if note. is_empty ( ) {
88- let _ = write ! ( out, "-- ---- ----|" ) ;
104+ let _ = write ! ( out, "--- - ----|" ) ;
89105 } else {
90- // 0 means carry on previous note
91- let sample = self . modfile . sample_info ( note. sample_no ( ) ) ;
92- if let Some ( sample) = sample {
93- ch. note_period = note. period ( ) ;
106+ if let Some ( sample) = self . modfile . sample_info ( note. sample_no ( ) ) {
94107 if note. period ( ) != 0 {
95- ch. volume = sample. volume ( ) ;
96- ch. sample_num = note. sample_no ( ) ;
97- ch. sample_position = neotracker:: Fractional :: default ( ) ;
98- ch. first_pass = true ;
108+ ch. note_period = note. period ( ) ;
99109 }
110+ ch. volume = sample. volume ( ) ;
111+ ch. sample_num = note. sample_no ( ) ;
112+ ch. sample_position = neotracker:: Fractional :: default ( ) ;
100113 }
101114 let _ = write ! (
102115 out,
103- "{:02} {:04x} {:04x}|" ,
104- note. sample_no( ) ,
116+ "{:3x} {:02}{:03x}|" ,
105117 note. period( ) ,
118+ note. sample_no( ) ,
106119 note. effect_u16( )
107120 ) ;
108- ch. effect = None ;
109- match note. effect ( ) {
110- e @ Some (
111- neotracker:: Effect :: Arpeggio ( _)
112- | neotracker:: Effect :: SlideUp ( _)
113- | neotracker:: Effect :: SlideDown ( _)
114- | neotracker:: Effect :: VolumeSlide ( _) ,
115- ) => {
116- // we'll need this for later
117- ch. effect = e;
118- }
119- Some ( neotracker:: Effect :: SetVolume ( value) ) => {
120- ch. volume = value;
121- }
122- Some ( neotracker:: Effect :: SetSpeed ( value) ) => {
123- if value <= 31 {
124- self . ticks_per_line = u32:: from ( value) ;
125- self . third_ticks_per_line = u32:: from ( value / 3 ) ;
126- } else {
127- // They are trying to set speed in beats per minute
128- }
129- }
130- Some ( neotracker:: Effect :: SampleOffset ( n) ) => {
131- let offset = u32:: from ( n) * 256 ;
132- ch. sample_position = neotracker:: Fractional :: new ( offset) ;
133- }
134- Some ( e) => {
135- // eprintln!("Unhandled effect {:02x?}", e);
136- }
137- None => {
138- // Do nothing
121+ }
122+ ch. effect = None ;
123+ match note. effect ( ) {
124+ e @ Some (
125+ neotracker:: Effect :: Arpeggio ( _)
126+ | neotracker:: Effect :: SlideUp ( _)
127+ | neotracker:: Effect :: SlideDown ( _)
128+ | neotracker:: Effect :: VolumeSlide ( _) ,
129+ ) => {
130+ // we'll need this for later
131+ ch. effect = e;
132+ }
133+ Some ( neotracker:: Effect :: SetVolume ( value) ) => {
134+ ch. volume = value;
135+ }
136+ Some ( neotracker:: Effect :: SetSpeed ( value) ) => {
137+ if value <= 31 {
138+ self . ticks_per_line = u32:: from ( value) ;
139+ self . third_ticks_per_line = u32:: from ( value / 3 ) ;
140+ } else {
141+ // They are trying to set speed in beats per minute
139142 }
140143 }
144+ Some ( neotracker:: Effect :: SampleOffset ( n) ) => {
145+ let offset = u32:: from ( n) * 256 ;
146+ ch. sample_position = neotracker:: Fractional :: new ( offset) ;
147+ }
148+ Some ( neotracker:: Effect :: PatternBreak ( row) ) => {
149+ // Start the next pattern early, at the given row
150+ self . pattern_break = Some ( row) ;
151+ }
152+ Some ( _e) => {
153+ // eprintln!("Unhandled effect {:02x?}", e);
154+ }
155+ None => {
156+ // Do nothing
157+ }
141158 }
142159 }
143160 let _ = writeln ! ( out) ;
@@ -179,12 +196,9 @@ impl<'a> Player<'a> {
179196 ch. note_period += u16:: from ( n) ;
180197 }
181198 Some ( neotracker:: Effect :: VolumeSlide ( n) ) => {
182- let xxxx = n >> 4 ;
183- let yyyy = n & 0x0F ;
184- if xxxx != 0 {
185- ch. volume = ( ch. volume + xxxx) . min ( 63 ) ;
186- } else if yyyy != 0 {
187- ch. volume = ch. volume . saturating_sub ( yyyy) ;
199+ let new_volume = ( ch. volume as i8 ) + n;
200+ if ( 0 ..=63 ) . contains ( & new_volume) {
201+ ch. volume = new_volume as u8 ;
188202 }
189203 }
190204 _ => {
@@ -201,35 +215,36 @@ impl<'a> Player<'a> {
201215 let mut left_sample = 0 ;
202216 let mut right_sample = 0 ;
203217 for ( ch_idx, ch) in self . channels . iter_mut ( ) . enumerate ( ) {
204- if ch. note_period == 0 {
218+ if ch. sample_num == 0 || ch . note_period == 0 {
205219 continue ;
206220 }
207221 let current_sample = self . modfile . sample ( ch. sample_num ) . expect ( "bad sample" ) ;
208222 let sample_data = current_sample. raw_sample_bytes ( ) ;
209- if sample_data. len ( ) == 0 {
223+ if sample_data. is_empty ( ) {
210224 continue ;
211225 }
212226 let integer_pos = ch. sample_position . as_index ( ) ;
213- let sample_byte = sample_data[ integer_pos] ;
214- let mut channel_value = sample_byte as i8 as i32 ;
215- // max channel vol (64), sample range [ -128,127] scaled to [-32768, 32767]
227+ let sample_byte = sample_data. get ( integer_pos) . cloned ( ) . unwrap_or_default ( ) ;
228+ let mut channel_value = ( sample_byte as i8 ) as i32 ;
229+ // max channel vol (64), sample range [-128,127] scaled to [-32768, 32767]
216230 channel_value *= 256 ;
217231 channel_value *= i32:: from ( ch. volume ) ;
218232 channel_value /= 64 ;
233+ // move the sample index by a non-integer amount
219234 ch. sample_position += self
220235 . clock_ticks_per_device_sample
221236 . apply_period ( ch. note_period ) ;
222-
223- let new_integer_pos = ch . sample_position . as_index ( ) ;
224- let limit = if ch. first_pass {
225- current_sample. sample_length_bytes ( )
226- } else {
227- current_sample . repeat_length_bytes ( )
228- } ;
229- if new_integer_pos >= limit {
230- ch. sample_position =
231- neotracker :: Fractional :: new ( current_sample . repeat_point_bytes ( ) as u32 ) ;
232- ch. first_pass = false ;
237+ // loop sample if required
238+ if current_sample . loops ( ) {
239+ if ch. sample_position . as_index ( )
240+ >= ( current_sample. repeat_point_bytes ( ) + current_sample . repeat_length_bytes ( ) )
241+ {
242+ ch . sample_position =
243+ neotracker :: Fractional :: new ( current_sample . repeat_point_bytes ( ) as u32 ) ;
244+ }
245+ } else if ch. sample_position . as_index ( ) >= current_sample . sample_length_bytes ( ) {
246+ // stop playing sample
247+ ch. note_period = 0 ;
233248 }
234249
235250 if ch_idx == 0 || ch_idx == 3 {
@@ -238,6 +253,7 @@ impl<'a> Player<'a> {
238253 right_sample += channel_value;
239254 }
240255 }
256+
241257 (
242258 left_sample. clamp ( -32768 , 32767 ) as i16 ,
243259 right_sample. clamp ( -32768 , 32767 ) as i16 ,
0 commit comments