@@ -150,11 +150,12 @@ def note_name(semitone, octave)
150150end
151151
152152octave = 4
153+ transpose = 0
153154waveform = Board ::PWMAudio ::SQUARE
154155waveform_idx = 1
155156
156157draw_title = lambda do
157- title = " audio demo octave #{ octave } #{ WAVEFORM_NAMES [ waveform_idx ] . downcase } "
158+ title = " audio demo octave #{ octave } transpose #{ sprintf ( "%+d" , transpose ) } #{ WAVEFORM_NAMES [ waveform_idx ] . downcase } "
158159 DVI ::Text . put_string ( 0 , 0 , title . ljust ( cols ) [ 0 , cols ] , BAR_ATTR )
159160end
160161
@@ -198,7 +199,7 @@ def note_name(semitone, octave)
198199DVI ::Text . clear ( TEXT_ATTR )
199200draw_title . call
200201draw_keyboard . call
201- help = " 1-4 waveform arrows/pad octave Esc quit"
202+ help = " 1-4 wave ^v octave <> transpose Esc quit"
202203DVI ::Text . put_string ( 0 , command_row , help . ljust ( cols ) [ 0 , cols ] , BAR_ATTR )
203204DVI ::Text . commit
204205
@@ -217,9 +218,10 @@ def note_name(semitone, octave)
217218 key = keyboard . read_char
218219 break if key == Keyboard ::CTRL_C || key == Keyboard ::ESCAPE
219220
220- previous_setting = [ octave , waveform ]
221+ previous_setting = [ octave , transpose , waveform ]
221222
222- # Octave shift via pad (edge detection) or cursor keys
223+ # Octave shift via pad (edge detection) or cursor keys; left/right
224+ # transposes in semitones.
223225 left_pad . read
224226 if left_pad . up? && !prev_octave_up
225227 octave = octave + 1 if octave < 7
@@ -234,6 +236,10 @@ def note_name(semitone, octave)
234236 octave = octave + 1 if octave < 7
235237 elsif key . match? ( :down )
236238 octave = octave - 1 if octave > 1
239+ elsif key . match? ( :left )
240+ transpose = transpose - 1 if transpose > -11
241+ elsif key . match? ( :right )
242+ transpose = transpose + 1 if transpose < 11
237243 end
238244 end
239245
@@ -258,8 +264,8 @@ def note_name(semitone, octave)
258264 end
259265 end
260266
261- # Retune held notes right away when the octave or waveform changes.
262- prev_note_keycodes = nil if [ octave , waveform ] != previous_setting
267+ # Retune held notes right away when the setting changes.
268+ prev_note_keycodes = nil if [ octave , transpose , waveform ] != previous_setting
263269
264270 if keycodes != prev_keycodes
265271 # Trigger drums on newly pressed keys (edge detection on the raw
@@ -306,7 +312,7 @@ def note_name(semitone, octave)
306312 3 . times do |ch |
307313 kc = note_keycodes [ ch ]
308314 if kc
309- semitone = NOTE_KEYCODES [ kc ]
315+ semitone = NOTE_KEYCODES [ kc ] + transpose
310316 freq = note_frequency ( semitone , octave )
311317 audio . tone ( ch , freq , waveform : waveform , volume : volume )
312318 else
@@ -315,7 +321,7 @@ def note_name(semitone, octave)
315321 end
316322
317323 if note_keycodes . length > 0
318- names = note_keycodes . map { |kc | note_name ( NOTE_KEYCODES [ kc ] , octave ) }
324+ names = note_keycodes . map { |kc | note_name ( NOTE_KEYCODES [ kc ] + transpose , octave ) }
319325 DVI ::Text . put_string ( 0 , PLAYING_ROW , " playing: #{ names . join ( " + " ) } " . ljust ( cols ) [ 0 , cols ] , PLAYING_ATTR )
320326 else
321327 DVI ::Text . clear_line ( PLAYING_ROW , TEXT_ATTR )
@@ -325,8 +331,8 @@ def note_name(semitone, octave)
325331 dirty = true
326332 end
327333
328- # The title bar carries the octave and waveform state.
329- title_state = "#{ octave } /#{ waveform_idx } "
334+ # The title bar carries the octave, transpose and waveform state.
335+ title_state = "#{ octave } /#{ transpose } / #{ waveform_idx } "
330336 if title_state != prev_title
331337 draw_title . call
332338 prev_title = title_state
0 commit comments