Browse Source

Added drift checking, 3 second sequence with click on sequence start

There is a consistent one to three frames of sequence drift which I need to fix
master
Macoy Madson 6 years ago
parent
commit
b9877af798
  1. 58
      sequencer.py

58
sequencer.py

@ -46,7 +46,7 @@ def chooseDevice(devices, searchString):
def testIO():
#synthOutPort = chooseDevice(mido.get_output_names(), 'LMMS')
# synthOutPort = chooseDevice(mido.get_output_names(), 'LMMS')
synthOutPort = chooseDevice(mido.get_output_names(), 'OP-1')
keyboardInPort = chooseDevice(mido.get_input_names(), 'CH345')
@ -62,7 +62,9 @@ def testIO():
def simpleSequencer():
#synthOutPort = chooseDevice(mido.get_output_names(), 'LMMS')
debugTiming = False
# synthOutPort = chooseDevice(mido.get_output_names(), 'LMMS')
synthOutPort = chooseDevice(mido.get_output_names(), 'OP-1')
keyboardInPort = chooseDevice(mido.get_input_names(), 'CH345')
@ -74,11 +76,21 @@ def simpleSequencer():
frameRate = (60 / 240) / 4
# Prevent the program from locking up if the frame rate gets too bad
maximumCatchupTime = 0.25
timeRoomForError = 0.0001
sequence = []
# Start with a click
sequence = [(mido.Message(
'note_on', note=60, velocity=64, time=0.0), 0.0), (mido.Message(
'note_off', note=60, velocity=127, time=0.1), 0.1)]
sequenceLastStartTime = 0.0
sequenceTimeLength = 1.0
sequenceTimeLength = 3.0
sequenceLastNotePlayedTime = 0.0
sequenceFirstStartTime = 0.0
sequenceDriftStartTime = 0.0
sequenceNumTimesPlayed = 0
sequenceNumTimesMeasureDrift = 4
lastTime = time.time()
timeAccumulated = 0.0
try:
@ -91,10 +103,12 @@ def simpleSequencer():
lastTime = currentTime
timeAccumulated += frameDelta
print(frameDelta)
if debugTiming:
print(frameDelta)
while timeAccumulated >= frameRate:
print('Updated')
if debugTiming:
print('Updated')
# Poll input
message = keyboardIn.poll()
@ -105,31 +119,55 @@ def simpleSequencer():
message = keyboardIn.poll()
# Play sequencer notes if it's time
# TODO: sort notes by time
# TODO: sort notes by time, out messages work strangely
for note in sequence:
# TODO: this comparison should have a margin of error equal
# to the frame rate
if note[1] <= sequenceTime and note[1] >= sequenceLastNotePlayedTime:
synthOut.send(note[0])
sequenceLastNotePlayedTime = max(sequenceLastNotePlayedTime, note[1])
sequenceLastNotePlayedTime = max(
sequenceLastNotePlayedTime, note[1])
if not sequenceFirstStartTime:
sequenceFirstStartTime = currentTime
# Restart sequence if necessary
if sequenceTime >= sequenceTimeLength:
# TODO: Minimize drift over time
if sequenceNumTimesPlayed % sequenceNumTimesMeasureDrift == 0:
print('Sequence played ' + str(sequenceNumTimesPlayed)
+ ' times; drifted ' +
str((currentTime - sequenceFirstStartTime)
- (sequenceTimeLength * sequenceNumTimesPlayed)) + ', drifted '
+ str((currentTime - sequenceDriftStartTime)
- (sequenceTimeLength * sequenceNumTimesMeasureDrift))
+ ' this ' + str(sequenceNumTimesMeasureDrift) + ' drift frame')
sequenceDriftStartTime = currentTime
sequenceLastStartTime = currentTime
sequenceLastNotePlayedTime = 0.0
sequenceNumTimesPlayed += 1
timeAccumulated -= frameRate
timeAccumulated = max(0.0, timeAccumulated)
sleepTime = frameRate - timeAccumulated - timeRoomForError
if sleepTime > 0:
print('Sleep ' + str(sleepTime))
if debugTiming:
print('Sleep ' + str(sleepTime))
time.sleep(sleepTime)
finally:
print('Resetting synth due to exception')
synthOut.reset()
#synthOut.panic()
""" Sometimes notes hang because a note_off has not been sent. To (abruptly) stop all sounding
notes, you can call:
outport.panic()
This will not reset controllers. Unlike reset(), the notes will not be turned off
gracefully, but will stop immediately with no regard to decay time.
http://mido.readthedocs.io/en/latest/ports.html?highlight=reset """
# synthOut.panic()
if __name__ == '__main__':
# testOutput()

Loading…
Cancel
Save