I think the simplest way to turn that into a Supply is to use the `supply` keyword
my $pm = Audio::PortMIDI.new; my $input = supply { my $stream = $pm.open-input($input-device-number, 32); DONE { $stream.close; } loop { emit $stream.read(1); } } react { whenever key-pressed(:!echo) { given .fc { when 'q' { done } default { .raku.say } } } my $voice = $pm.open-output($output-device-number, 32); whenever $input { $voice.write(|$_); } } On Fri, Jan 1, 2021 at 12:31 PM Nathan Gray <kolib...@graystudios.org> wrote: > 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 >