Nils
3 years ago
4 changed files with 150 additions and 9 deletions
@ -0,0 +1,110 @@ |
|||
#! /usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
NUMBER_OF_INSTRUMENTS = 240 |
|||
""" |
|||
2021-11-13 Benchmark: |
|||
NumberOfInstruments,StartInSeconds,QuitInSeconds |
|||
30, 5, 3 |
|||
60, 10, 6 |
|||
120, 21, 12 |
|||
240, 42, 25 |
|||
|
|||
Conclusion: Linear time. |
|||
""" |
|||
|
|||
from calfbox import cbox |
|||
|
|||
import atexit |
|||
from datetime import datetime |
|||
|
|||
#Capture Ctlr+C / SIGINT and let @atexit handle the rest. |
|||
import signal |
|||
import sys |
|||
def signal_handler(sig, frame): |
|||
sys.exit(0) #atexit will trigger |
|||
signal.signal(signal.SIGINT, signal_handler) |
|||
|
|||
|
|||
def cmd_dumper(cmd, fb, args): |
|||
#print ("%s(%s)" % (cmd, ",".join(list(map(repr,args))))) |
|||
pass |
|||
|
|||
def stopSession(): |
|||
"""This got registered with atexit in the nsm new or open callback above. |
|||
will handle all python exceptions, but not segfaults of C modules. """ |
|||
print() |
|||
print("Starting Quit through @atexit, stopSession") |
|||
starttime = datetime.now() |
|||
#Don't do that. We are just a client. |
|||
#cbox.Transport.stop() |
|||
#print("@atexit: Calfbox Transport stopped ") |
|||
cbox.stop_audio() |
|||
print("@atexit: Calfbox Audio stopped ") |
|||
cbox.shutdown_engine() |
|||
print("@atexit: Calfbox Engine shutdown ") |
|||
endtime = datetime.now() - starttime |
|||
print (f"Shutdown took {endtime.seconds} seconds for {NUMBER_OF_INSTRUMENTS} instruments") |
|||
|
|||
cbox.init_engine() |
|||
cbox.start_audio(cmd_dumper) |
|||
atexit.register(stopSession) #this will handle all python exceptions, but not segfaults of C modules. |
|||
|
|||
scenes = {} |
|||
jackAudioOutLefts = {} |
|||
jackAudioOutRights = {} |
|||
outputMergerRouters = {} |
|||
routerToGlobalSummingStereoMixers = {} |
|||
lmixUuid = cbox.JackIO.create_audio_output('left_mix', "#1") #add "#1" as second parameter for auto-connection to system out 1 |
|||
rmixUuid = cbox.JackIO.create_audio_output('right_mix', "#2") #add "#2" as second parameter for auto-connection to system out 2 |
|||
cboxMidiPortUids = {} |
|||
sfzSamplerLayers = {} |
|||
instrumentLayers = {}\ |
|||
|
|||
|
|||
print (f"Creating {NUMBER_OF_INSTRUMENTS} instruments") |
|||
starttime = datetime.now() |
|||
|
|||
for i in range(NUMBER_OF_INSTRUMENTS): |
|||
scenes[i] = cbox.Document.get_engine().new_scene() |
|||
scenes[i].clear() |
|||
|
|||
#instrumentLayer = scenes[i].status().layers[0].get_instrument() |
|||
sfzSamplerLayers[i] = scenes[i].add_new_instrument_layer(str(i), "sampler") #"sampler" is the cbox sfz engine |
|||
scenes[i].status().layers[0].get_instrument().engine.load_patch_from_string(0, "", "", "") #fill with null instruments |
|||
|
|||
jackAudioOutLefts[i] = cbox.JackIO.create_audio_output(str(i) +"_L") |
|||
jackAudioOutRights[i] = cbox.JackIO.create_audio_output(str(i) +"_R") |
|||
|
|||
outputMergerRouters[i] = cbox.JackIO.create_audio_output_router(jackAudioOutLefts[i], jackAudioOutRights[i]) |
|||
outputMergerRouters[i].set_gain(-3.0) |
|||
#instrumentLayer = sfzSamplerLayers[i].get_instrument() |
|||
instrumentLayers[i] = scenes[i].status().layers[0].get_instrument() |
|||
instrumentLayers[i].get_output_slot(0).rec_wet.attach(outputMergerRouters[i]) #output_slot is 0 based and means a pair. Most sfz instrument have only one stereo pair. #TODO: And what if not? |
|||
|
|||
routerToGlobalSummingStereoMixers[i] = cbox.JackIO.create_audio_output_router(lmixUuid, rmixUuid) |
|||
routerToGlobalSummingStereoMixers[i].set_gain(-3.0) |
|||
instrument = sfzSamplerLayers[i].get_instrument() |
|||
instrument.get_output_slot(0).rec_wet.attach(routerToGlobalSummingStereoMixers[i]) |
|||
|
|||
#Create Midi Input Port |
|||
cboxMidiPortUids[i] = cbox.JackIO.create_midi_input(str(i) + "midi_in") |
|||
cbox.JackIO.set_appsink_for_midi_input(cboxMidiPortUids[i], True) #This sounds like a program wide sink, but it is needed for every port. |
|||
cbox.JackIO.route_midi_input(cboxMidiPortUids[i], scenes[i].uuid) #Route midi input to the scene. Without this we have no sound, but the python processor would still work. |
|||
|
|||
#Actually load the instrument |
|||
programNumber = 0 |
|||
#program = instrumentLayers[i].engine.load_patch_from_tar(programNumber, "bug.tar", f'Saw{1}.sfz', f'Saw{i+1}') #tar_name, sfz_name, display_name |
|||
program = instrumentLayers[i].engine.load_patch_from_string(programNumber, ".", "", "<group> <region> sample=*saw") #fill with null instruments |
|||
print (f"[{i}]", program.status()) |
|||
instrumentLayers[i].engine.set_patch(1, programNumber) #1 is the channel, counting from 1. #TODO: we want this to be on all channels. |
|||
|
|||
endtime = datetime.now() - starttime |
|||
print (f"Creation took {endtime.seconds} seconds for {NUMBER_OF_INSTRUMENTS} instruments") |
|||
|
|||
print() |
|||
print("Press Ctrl+C for a controlled shutdown.") |
|||
print() |
|||
|
|||
while True: |
|||
cbox.call_on_idle(cmd_dumper) |
@ -0,0 +1,39 @@ |
|||
#! /usr/bin/env python3 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from calfbox import cbox |
|||
|
|||
def cmd_dumper(cmd, fb, args): |
|||
print ("%s(%s)" % (cmd, ",".join(list(map(repr,args))))) |
|||
|
|||
cbox.init_engine() |
|||
cbox.start_audio(cmd_dumper) |
|||
|
|||
outportname = "CboxSendPattern" |
|||
cboxMidiOutUuid = cbox.JackIO.create_midi_output(outportname) #Add a named midi out port |
|||
cbox.JackIO.rename_midi_output(cboxMidiOutUuid, outportname) #For good measure. |
|||
outputScene = cbox.Document.get_engine().new_scene() #Create a new scene that will play the pattern. The pattern is not saved in the scene, it is not a track or so. |
|||
outputScene.clear() #For good measure. |
|||
outputScene.add_new_midi_layer(cboxMidiOutUuid) #Connect the scene to our midi output port. Without this there will be no midi out. |
|||
|
|||
|
|||
# Send 8 pitches 0x90 with velocity 0 |
|||
# Create a binary blob that contains the MIDI events |
|||
pblob = bytes() |
|||
for pitch in range(0,8): |
|||
# note on |
|||
pblob += cbox.Pattern.serialize_event(1, 0x90, pitch, 0) #tick in pattern, midi, pitch, velocity |
|||
# Create a new pattern object using events from the blob |
|||
allNoteOnZeroPattern = cbox.Document.get_song().pattern_from_blob(pblob, 0) #0 ticks. |
|||
|
|||
|
|||
print ("\nThis example sends midi events from a pattern without any tracks. Rolling transport or not doesn't matter.") |
|||
print("Ready!") |
|||
counter = 0 #To add delay |
|||
while True: |
|||
cbox.call_on_idle(cmd_dumper) |
|||
if counter > 10**5 * 4 : |
|||
print ("Send pattern") |
|||
outputScene.play_pattern(allNoteOnZeroPattern, 150.0) #150 tempo |
|||
counter = 0 |
|||
counter += 1 |
Loading…
Reference in new issue