Hi there. I’m very new to JUCE (and still getting used to C++), so any advice would be greatly appreciated. I would like to build a JUCE audio plug-in that generates MIDI data to be read by a DAW (like Logic or Ableton). I want my DAW to pick up the MIDI just like it would from a USB MIDI keyboard, except the data is generated by my tool.
To start with something simple, I have tried the following so far:
created a new audio plugin in the projucer
In PluginProcessor.cpp, in the Processblock, added auto message = MidiMessage::noteOn (1, 5, (uint8) 100); MidiBuffer midiBuffer; midiBuffer.addEvent(message, 0);
As an alternative, I also tried MidiMessage message = MidiMessage::noteOn (1, 5, (uint8) 100); midiMessages.addEvent (message, 0);
I tried compiling each version, then opened Logic and put the plug-in onto an audio track. I then opened a MIDI instrument track, hoping that it might pick up the MIDI. It doesn’t. What am I doing wrong here?
Did you insert your plug-in as a midi effect before your synth or after as an audio effect? I just tested both VST3 in Reaper and AU in Logic, and it works like a charm. In Logic I had to hit play for the plug-in to produce MIDI
Thank you both for your help, appreciate your time. @danielrudrich I tried both those things, I compiled my plugin both as a MIDI effect and normal plugin and neither seems to work… Would it perhaps be possible for me to send you some of my work to see if it differs from yours, or for you to send me yours? I even tried to hit record to see if it would pick something up in a MIDI recording.
Thanks, I started again from scratch but still no luck. This is very strange. My audio output works and I am receiving MIDI from all channels as expected. Normal keyboard MIDI input works, too. BTW when you say end of process block, do you mean inside of or after the bit saying
for (int channel = 0; channel < totalNumInputChannels; ++channel){…}
Ohh, it works for the Logic Retro Synth!! I have been trying the Vintage Electric Piano, which for some reason doesn’t like it. Do you have an idea why this could be? I thought all software instruments would pick up MIDI in the same way. Is it a channel thing? Though can’t be since I ticked “all”…
Some more intel: no matter how I set my synth amp ADSR, the note has an endless sustain. I know there is no note off but unless I have a sustain, it should still end I thought. Lots of riddles here!
Just playing with it some more. It appears to keep re-triggering the sound in regular intervals. Got some accidental dubstep from another synth
I agree, though it sounds to me as though the note keeps getting triggered, that’s why I get a wobble. It’s not a long sustain; and it also happens on short, percussive synth presets. Will look at it some more tomorrow. Thanks for all your help so far!
Hi again. So as suspected, the MIDI off message does not work as expected.
Currently, it says the following at the end of my process block:
midiMessages.addEvent(MidiMessage(MidiMessage::noteOn(1,(int)(60),(uint8) 100)),0);
midiMessages.addEvent(MidiMessage(MidiMessage::noteOff(1,(int)(60),(uint8) 100)),100);
When testing this Logic, the note seems to get started over and over again and never ends. Does anyone know why this might be?
Since processBlock is repeatedly called while the audio is running, if you don’t have any condition to limit the notes from being added, they just keep on being added. And because the processing blocks may be quite short, you may get some weird effects from synths following your MIDI generator plugin because they are quickly hammered with incoming MIDI notes.
The note-offs not working may be related to that, synths might not expect to get a note-off during the same processing block for the same note. You somehow have to keep track of when the note ons and note offs should happen and then accordingly add the messages to the MIDI buffer.
Thanks again for everybody’s help so far. I’m stuck on the next step now.
I am struggling to work out how the process block works in regards to musical timing. I read many forum entries and the documentation but I’m still struggling and feel that I need to ask some dumb questions for now.
Say I wanted to use a toggle button to control an endless sequence of MIDI notes (of random pitches but equal durations) being turned on and off. When I turn the button on, the sequence starts; and when I turn the button off, the sequence stops. I’m using the following code at the moment. IsOn is a boole that’s initiated as false above the process block and IsPlaying is my button toggle info.
I understand that the process block is continuously being recalled, but I don’t understand why the next note plays before the previous note has stopped, since I’m only setting IsPlaying back to false afterwards.
Presumably I am using this completely wrong. Can somebody help suggest the tools I need to make the timing work? Thanks!
You are still not counting the elapsed times for the notes in any way. The time stamp given to addEvent should be a time stamp within the current processing buffer. If you put something like 80000 there for the note off message, the event is likely just ignored by Juce or the host. And it doesn’t mean the next processBlock call is going to happen after 80000 samples. The processBlock calls happen at some relatively short time period, typically something like 64 to 1024 samples. That is completely independent of what you put into the MIDI messages.
You will need to figure out which MIDI messages and when to put into the current MIDI buffer : put a note on message into the messages at the first processBlock call, then you don’t maybe add any messages during lots of the processBlock calls, and finally when the note should end, you add the note off event and possibly a new note on event for the next note and so on. The logic needed to implement that is tricky because you need to keep track of what notes are currently playing and so on. You can look at the ArpeggiatorPluginDemo.h in the Juce examples to get some ideas how to implement it.