You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.3 KiB
92 lines
2.3 KiB
3 years ago
|
import os
|
||
|
import sys
|
||
|
import struct
|
||
|
import time
|
||
|
import unittest
|
||
|
|
||
|
sys.path = ["./py"] + sys.path
|
||
|
|
||
|
import cbox
|
||
|
|
||
|
global Document
|
||
|
global Transport
|
||
|
Document = cbox.Document
|
||
|
Transport = cbox.Transport
|
||
|
|
||
|
# Make sure playback doesn't start prematurely
|
||
|
Transport.stop()
|
||
|
|
||
|
song = Document.get_song()
|
||
|
|
||
|
# Delete all the tracks and patterns
|
||
|
song.clear()
|
||
|
|
||
|
# Add the first track
|
||
|
trk = song.add_track()
|
||
|
|
||
|
# Create a binary blob that contains zero MIDI events
|
||
|
emptyblob = bytes()
|
||
|
|
||
|
# Create a new empty pattern
|
||
|
empty_pattern = song.pattern_from_blob(emptyblob, 16)
|
||
|
|
||
|
# This will be the length of the pattern (in pulses). It should be large enough
|
||
|
# to fit all the events
|
||
|
pattern_len = 10 * 24 * 2
|
||
|
|
||
|
# Add an instance (clip) of the empty pattern to the track
|
||
|
clip1 = trk.add_clip(pattern_len, 0, 16, empty_pattern)
|
||
|
|
||
|
# Add another instance after it
|
||
|
clip2 = trk.add_clip(2 * pattern_len, 0, 16, empty_pattern)
|
||
|
|
||
|
# Create a binary blob that contains the MIDI events
|
||
|
pblob = bytes()
|
||
|
for noteindex in range(20):
|
||
|
# note on
|
||
|
pblob += cbox.Pattern.serialize_event(noteindex * 24, 0x90, 36+noteindex*3, 127)
|
||
|
# note off
|
||
|
pblob += cbox.Pattern.serialize_event(noteindex * 24 + 23, 0x90, 36+noteindex*3, 0)
|
||
|
|
||
|
# Create a new pattern object using events from the blob
|
||
|
pattern = song.pattern_from_blob(pblob, pattern_len)
|
||
|
|
||
|
# Update all attributes of the second clip, rearranging the order
|
||
|
clip2.set_pattern(pattern)
|
||
|
clip2.set_pos(0)
|
||
|
clip2.set_offset(0)
|
||
|
clip2.set_length(pattern_len)
|
||
|
|
||
|
# Verify that the clips have been reordered
|
||
|
clips = [o.clip for o in trk.status().clips]
|
||
|
assert clips == [clip2, clip1]
|
||
|
|
||
|
# Stop the song at the end
|
||
|
song.set_loop(pattern_len, pattern_len)
|
||
|
|
||
|
# Set tempo - the argument must be a float
|
||
|
Transport.set_tempo(160.0)
|
||
|
|
||
|
# Send the updated song data to the realtime thread
|
||
|
song.update_playback()
|
||
|
|
||
|
# Flush
|
||
|
Transport.stop()
|
||
|
|
||
|
print ("Song length (seconds) is %f" % (cbox.Transport.ppqn_to_samples(pattern_len) * 1.0 / Transport.status().sample_rate))
|
||
|
|
||
|
# The /master object API doesn't have any nice Python wrapper yet, so accessing
|
||
|
# it is a bit ugly, still - it works
|
||
|
|
||
|
# Start playback
|
||
|
Transport.play()
|
||
|
print ("Playing")
|
||
|
|
||
|
while True:
|
||
|
# Get transport information - current position (samples and pulses), current tempo etc.
|
||
|
master = Transport.status()
|
||
|
print (master.pos_ppqn)
|
||
|
# Query JACK ports, new USB devices etc.
|
||
|
cbox.call_on_idle()
|
||
|
time.sleep(0.1)
|