Helloooow, Do you think we can have the top right led of the launchpads, under the logo, blink to the beat ? Green red red red Green red red red ?
I’m trying to write a driver to use the Akai APC 40, I’m starting as a mixer, then moving on to pad integration. I was able to get basic debugging working using vs code connecting to my zynthian remotely, but I don’t ever see the zynthian_ctrldev_manager or my device definition even loading. I’ve set breakpoints in the files, zynthian_ctrldev_manager.py and my ctrldev/zynthian_ctrldev_akai_apc40_mixer.py, but they never trigger. I’m sure I’m probably missing something basic. Is there some setting to enable the ctrldev manager or something?
Ctrldev_manager is always enabled and tries to autoinit a matching driver of each type (zynpad and mixer) when possible. If the ID string of a connected device match the ID strings from a driver, the driver is initialized for mixer or zynpad, depending on the driver type. I’ve not tested to put together mixer & zynpad functionality in the same driver. It should be possible but you could find problems or limitations. The driver model is being currently improved to allow greater flexibility. Meanwhile, focus in a single type first, mixer or zynpad.
Regards,
I’ve just got a basic driver working for the launch pad controls on the APC40 - you can see the code here in case that gives you any leads for the mixer side of things: GitHub - lyserge/zynthian-apc40: Akai APC40 controller driver for Zynthian
p.s. thanks @jofemodo for putting this subsystem together! Hopefully this will open up a whole lot of hardware compatibility
Thanks @jofemodo and @lyserge! Lyserge, I’ll be taking a look at your implementation of the the apc40 to zynpad. Thanks for getting me started!
Thanks again for the link, it absolutely helped me get started! I was able to use your code and get an implementation of both the zynmixer and zynpad working on the APC40 mkI - there’s still a couple of bugs but it’s mostly working - GitHub - zhagan/zynthian-controller-drivers: To how
Hi!
I’m working on a controller device driver for the Akai APC Key 25 mk2:
Is there someone else working on it? If so, we may join forces. Otherwise, I’ll update as soon as I have anything working
Best regards!
UPDATE: Mixer volumes ready! I can control the first 8 channels directly with knobs 1 to 8, and channels 9-15 with knobs 1 to 7 + SHIFT. The shifted knob 8 is for main chain (master volume).
UPDATE 2: Mixer pan working! Pressing SHIFT will lit the selected function for the knobs (currently Volume or Pan), and using the Knob Ctrl buttons you can change the function. Pan (balance) knobs works as volume does.
UPDATE 3: Now I have the mute/solo buttons ready! They are controlled by the Track buttons (button row below the pad matrix). Pressing each one of these buttons will toggle the current selected function for the corresponding chain. As there are only 8 buttons, I’ve implemented a bank function: pressing SHIFT + LEFT/RIGHT will change between bank 0 (chains 1-8) and bank 1 (chains 9-16). The triggered action is selected by the Soft Keys (button column to the right of the pad matrix). Pressing SHIFT + MUTE/SOLO will change the action. Also, the Track buttons will lit if the corresponding function is active in the given channel.
I think the mixer functionality is complete. I’ll give a try to the Zynpad
Hi again!
I’ve a problem: when I press any control key (which are handled by midi_event
, returning True
) the event is propagated to the selected chain, and if it is a MIDI one, it produces a note. How can I control (avoid) this behaviour? Any clue?
It shouldn’t happen. When a driver is loaded for a device, the device (MIDI port), this is disconnected from the chains. Are you using latest testing branch?
You should see this logging message when your device driver is loaded and enabled:
logging.info(“Setting-up {} in slot {}”.format(self.dev_id, self.idev))
Could you tell me what’s the exact logging message you get?
Also, how many MIDI devices use the controller? Have separated MIDI devices for control and playing?
Regards,
Are you using latest testing branch?
Yes, I’m using the ‘testing’ branch, and I’ve updated everything as well.
Could you tell me what’s the exact logging message you get?
Yep, is this:
INFO:zynthian_ctrldev_manager.setup: Setting-up APC_Key_25_mk2_MIDI_2 in slot 2
Also, how many MIDI devices use the controller? Have separated MIDI devices for control and playing?
Yes, it has two devices, called port 0 and 1, which are MIDI 1 and MIDI 2. Port 0 is used only for the keybed (white and black keys) and for the sustain button. The rest of the buttons, and also the LEDs are in port 1 (MIDI 2).
Thanks for the response!
Could you send your driver’s code? I would review it.
Yes, of course! How can I send it?
UPDATE: I’ve reduced the code to a minimal example, and it still happens. This is the code:
from zyngui.zynthian_ctrldev_manager import zynthian_ctrldev_base
class zynthian_ctrldev_akai_apc_key25_mk2(zynthian_ctrldev_base):
dev_ids = ["APC_Key_25_mk2_MIDI_2"]
dev_zynmixer = True
def init(self): pass
def end(self): pass
def refresh(self, force=False): pass
def midi_event(self, ev):
print(f"midi {ev:06x}")
return True
UPDATE 2: I’ve edited the “Capture MIDI from” setting of a chain, and removed every source (as you said, ‘Key 25 MIDI 2’ is disabled and I can not enable it). Then, the chain does not receive events from MIDI 1 (or any other source), but is still receiving events from MIDI 2
Could you send the output of this command?
jack_lsp -cA
Thanks
Copy/paste it here, If you can’t, send by email to fernandoARROBAzynthianDOTorg
Regards
Yes. After a reboot, with a single chain, this is the result:
system:playback_1
alsa_pcm:hw:Device:in1
zynmixer:output_a
system:playback_2
alsa_pcm:hw:Device:in2
zynmixer:output_b
system:midi_capture_1
in-hw-2-0-0-APC-Key-25-mk2-MIDI-1
ZynMidiRouter:dev0_in
system:midi_capture_2
in-hw-2-0-1-APC-Key-25-mk2-MIDI-2
ZynMidiRouter:dev1_in
system:midi_playback_1
out-hw-2-0-0-APC-Key-25-mk2-MIDI-1
ZynMidiRouter:dev0_out
system:midi_playback_2
out-hw-2-0-1-APC-Key-25-mk2-MIDI-2
ZynMidiRouter:dev1_out
ttymidi:MIDI_in
ZynMidiRouter:dev2_in
ttymidi:MIDI_out
ZynMidiRouter:dev2_out
a2j:Midi Through [14] (capture): Midi Through Port-0
ZynMidiRouter:dev3_in
a2j:Midi Through [14] (playback): Midi Through Port-0
ZynMidiRouter:dev3_out
ZynMidiRouter:ch0_out
synthv1-00:in
ZynMidiRouter:ch1_out
ZynMidiRouter:ch2_out
ZynMidiRouter:ch3_out
ZynMidiRouter:ch4_out
ZynMidiRouter:ch5_out
ZynMidiRouter:ch6_out
ZynMidiRouter:ch7_out
ZynMidiRouter:ch8_out
ZynMidiRouter:ch9_out
ZynMidiRouter:ch10_out
ZynMidiRouter:ch11_out
ZynMidiRouter:ch12_out
ZynMidiRouter:ch13_out
ZynMidiRouter:ch14_out
ZynMidiRouter:ch15_out
ZynMidiRouter:main_out
zynsmf:midi_in
ZynMidiRouter:mod_out
ZynMidiRouter:midi_out
ZynMaster:midi_in
ZynMidiRouter:net_out
ZynMidiRouter:step_out
zynseq:input
ZynMidiRouter:ctrl_out
ZynMidiRouter:dev0_out
system:midi_playback_1
ZynMidiRouter:dev1_out
system:midi_playback_2
ZynMidiRouter:dev2_out
ttymidi:MIDI_out
ZynMidiRouter:dev3_out
a2j:Midi Through [14] (playback): Midi Through Port-0
ZynMidiRouter:dev4_out
ZynMidiRouter:dev5_out
ZynMidiRouter:dev6_out
ZynMidiRouter:dev7_out
ZynMidiRouter:dev8_out
ZynMidiRouter:dev9_out
ZynMidiRouter:dev10_out
ZynMidiRouter:dev11_out
ZynMidiRouter:dev12_out
ZynMidiRouter:dev13_out
ZynMidiRouter:dev14_out
ZynMidiRouter:dev15_out
ZynMidiRouter:dev0_in
system:midi_capture_1
ZynMidiRouter:dev1_in
system:midi_capture_2
ZynMidiRouter:dev2_in
ttymidi:MIDI_in
ZynMidiRouter:dev3_in
a2j:Midi Through [14] (capture): Midi Through Port-0
ZynMidiRouter:dev4_in
ZynMidiRouter:dev5_in
ZynMidiRouter:dev6_in
ZynMidiRouter:dev7_in
ZynMidiRouter:dev8_in
ZynMidiRouter:dev9_in
ZynMidiRouter:dev10_in
ZynMidiRouter:dev11_in
ZynMidiRouter:dev12_in
ZynMidiRouter:dev13_in
ZynMidiRouter:dev14_in
ZynMidiRouter:dev15_in
ZynMidiRouter:net_in
ZynMidiRouter:seq_in
zynsmf:midi_out
ZynMidiRouter:step_in
zynseq:output
ZynMidiRouter:ctrl_in
ZynMaster:midi_in
ZynMidiRouter:midi_out
ZynMaster:midi_out
zynmixer:input_moduia
zynmixer:input_moduib
zynmixer:output_moduia
zynmixer:output_moduib
zynmixer:input_01a
synthv1-00:Out_L
zynmixer:input_01b
synthv1-00:Out_R
zynmixer:input_02a
zynmixer:input_02b
zynmixer:input_03a
zynmixer:input_03b
zynmixer:input_04a
zynmixer:input_04b
zynmixer:input_05a
zynmixer:input_05b
zynmixer:input_06a
zynmixer:input_06b
zynmixer:input_07a
zynmixer:input_07b
zynmixer:input_08a
zynmixer:input_08b
zynmixer:input_09a
zynmixer:input_09b
zynmixer:input_10a
zynmixer:input_10b
zynmixer:input_11a
zynmixer:input_11b
zynmixer:input_12a
zynmixer:input_12b
zynmixer:input_13a
zynmixer:input_13b
zynmixer:input_14a
zynmixer:input_14b
zynmixer:input_15a
zynmixer:input_15b
zynmixer:input_16a
zynmixer:input_16b
zynmixer:input_17a
audioplayer:out_01a
zynseq:metronome
zynmixer:input_17b
audioplayer:out_01b
zynseq:metronome
zynmixer:return_a
zynmixer:return_b
zynmixer:output_a
system:playback_1
zynmixer:output_b
system:playback_2
zynmixer:send_a
zynmixer:send_b
zynseq:input
ZynMidiRouter:step_out
zynseq:output
ZynMidiRouter:step_in
zynseq:metronome
zynmixer:input_17a
zynmixer:input_17b
audioplayer:in
audioplayer:out_01a
zynmixer:input_17a
audioplayer:out_01b
zynmixer:input_17b
zynsmf:midi_out
ZynMidiRouter:seq_in
zynsmf:midi_in
ZynMidiRouter:main_out
synthv1-00:in
ZynMidiRouter:ch0_out
synthv1-00:in_L
synthv1-00:in_R
synthv1-00:Out_L
zynmixer:input_01a
synthv1-00:Out_R
zynmixer:input_01b
How did you update? From webconf? Command line?
Regards
I updated from the webconf, and also, I did an apt upgrade
.
Could you try adding this:
lib_zyncore.zmip_set_route_extdev(self.idev - 1, 0)
to your init function?
This call should “unroute” the input device from the chains and it’s called from the “setup” function in the base class. I don’t understand why the device is still routed to the chains in your setup!
You can get the current routing by calling this.
lib_zyncore.zmop_get_route_from(izmop, izmip)
- izmop is the chain index (well, indeed is the router’s output port index)
- izmip is the device index (again, it’s the router’s input port index)
Some thing like this will help debugging:
for i in range(17):
routed = lib_zyncore.zmop_get_route_from(i, self.idev-1)
logging.debug(f"Routed to izmop {i} => {routed}")
The routes should be set to 0 for all izmop from 0 to 16.
Regards,
Ok, I put that line inside the init function, and I printed the routes immediately after, and everything seems fine (all returns 0). BUT, I also put the print in midi_event
, and there, channels from 0 to 15 get routed (zmop_get_route_from
returns 1), and only channel 16 get 0.
Something between init
and midi_event
is changing the routing…
UPDATE: If I set the route again the first time midi_event
is called, then it stops sending events, and it keeps that way.
UPDATE 2: I’ve added a print inside the C function zmip_set_route_extdev
, recompiled, and tested again. It is called only once, in the ctrldev’s setup()
; the re-routing must be donde elsewhere.