I am working on a small virtual organ program, where I have multiple MIDI controller keyboards which can be connected to one or more synthesizer channels to emit various sounds simultaneously.
At this point, I am able to read events from a single MIDI
controller and send the events to the correct synthesizer channel
(I'm using Timidity at the moment).
I would like to read keypresses from the computer keyboard and
use those to adjust which synthesizers receive which MIDI events.
In other words, I press a note on my MIDI controller and the note
plays a sound on the synthesizer I have set up. When I press the
letter 'a' on my computer keyboard, I would like to add another
synthesizer, so that subsequent notes played on the MIDI
controller send events to the original synthesizer and to a new
synthesizer.
I was able to build a script to read in events from the computer
keyboard (via the module Term::ReadKey). I read these keypresses
in a react block with a whenever:
react {
whenever key-pressed(:!echo) {
# Eventually will connect or disconnect a synthesizer for the
relevant MIDI controller.
# Currently just prints out the key that was pressed.
given .fc {
when 'q' { done }
default { .raku.say }
}
}
}
The MIDI events are being read via the module Audio::PortMIDI in
a loop block:
my $pm = Audio::PortMIDI.new;
my $stream = $pm.open-input($input-device-number, 32);
my $voice = $pm.open-output($output-device-number, 32);
# Read events from the MIDI controller and write to the synthesizer.
loop {
if $stream.poll {
my @notes = $stream.read(1);
$voice.write(@notes);
}
}
I'm struggling to figure out how to combine the react block for
the computer keyboard events and the loop block for the MIDI
events. I would like to be able to accept events from both
devices concurrently.
It seems like I might need to turn the loop into a Supply of some
kind, but I'm not sure how I would go about doing that. If I
understand correctly, once it is a supply, I could add it to the
react block as another whenever event.
I have found examples of how to create a Supply using a loop and
a Promise that is kept after a specific amount of time
(https://stackoverflow.com/questions/57486372/concurrency-react-ing-to-more-than-one-supply-at-a-time),
but I have not found anything that is polling from a data stream.
My attempt of polling the stream in a whenever block errors out,
without me ever pressing a key, which makes it seem like it is
trying to read when there are no keypress events available.
whenever so $stream.poll {
my @notes = $stream.read(1);
...
}
Type check failed for return value; expected Str but got Any (Any)
in sub with-termios at
/home/kolibrie/.raku/sources/C758559420AEADF99B8D412BDFADA739CAC14C2A
(Term::ReadKey) line 20
in block at
/home/kolibrie/.raku/sources/C758559420AEADF99B8D412BDFADA739CAC14C2A
(Term::ReadKey) line 51
Any insights would be greatly appreciated.
-kolibrie
signature.asc
Description: PGP signature
