On Wed, Dec 11, 2024 at 11:42:57AM +0100, Jeanette C. wrote: > Is there a better, hopefully simple, way to play these clicks?
If you're building a sequencer anyway, just output the metronome clicks as one additional track. i.e. just a repeating sequence of note on/off events to be rendered by a synth. Or you could use the JackSignal class from zita-jacktools to play the ticks. Giant overkill but it will work. JackSignal allows to play and/or capture Jack audio from/to numpy buffers. It's meant to do automated audio measurements with all signals generated and/or analysed in Python. The example below receives MIDI clock (using the Aseqmidi class) and outputs a tick every quarter note. In this case the two tick sounds are generated in Python, but you could as well input them from files (using zita-audiotools). When S.process () is called, output will start at the next Jack period boundary, so with -p 256 you'd have +/- 2.7 ms jitter. Note that if the metronome is a separate program (like the one below), it also needs to handle song position messages to be in sync with the sequencer. #!/usr/bin/python from zita_alsamidi.aseqmidi import * from zita_jacktools.jacksignal import * from time import sleep from math import pi, sin import numpy as np # Play sound # def playsound (): global K # Beat counter if S.get_state () != JackSignal.SILENCE: return # Still playing previous one... # Enable one of the two waveforms. if K == 0: S.set_output_gain (0, 1.0) S.set_output_gain (1, 0.0) else: S.set_output_gain (0, 0.0) S.set_output_gain (1, 1.0) # Start playback. S.process () # Handle 4/4 signature. K += 1 if K == 4: K = 0 # Midi message handler # def handler (args): global C # Clock counter if args [1][0] == 36: # 36 = SND_SEQ_EVENT_CLOCK C += 1 if C == 24: playsound () C = 0 # Generate a 'ping' waveform. # def genping (freq, rate, size): D = np.zeros ((size,), dtype = np.float32) w = 2 * pi * freq / rate a = 0.3 m = pow (0.01, 1.0 / size) for i in range (size): D [i] = a * sin (i * w) a *= m return D S = JackSignal ("Metronome") if S.get_state () < 0: print ("Can't create JackSignal") exit (1) name, rate, frag = S.get_jack_info () # Should be short enough so they don't overlap. size = int (0.15 * rate) D1 = genping (880, rate, size) D2 = genping (440, rate, size) S.create_output (0, 'out-1') S.create_output (1, 'out-2') S.silence () # Connect Jack outputs... # S.connect_output (0, '...') # S.connect_output (1, '...') S.set_output_data (0, D1) S.set_output_data (1, D2) C = 0 # Clock message counter. K = 0 # Beat counter M = Aseqmidi ("Metronome", handler) sleep (10000) -- FA _______________________________________________ Linux-audio-dev mailing list -- linux-audio-dev@lists.linuxaudio.org To unsubscribe send an email to linux-audio-dev-le...@lists.linuxaudio.org