void DrumMachine::getNextAudioBlock(const AudioSourceChannelInfo& bufferToFill) { // std::cout << "drum machine!!" << std::endl; auto& transport = audioEngine.getTransport(); if (transport.isPlaying()) { int frameStartSamples = transport.getFrameStartSamples(); float frameStartTicks = transport.getFrameStartTicks(); float frameEndTicks = transport.getFrameEndTicks(); if ((int) frameStartTicks < (int) frameEndTicks) { int tick = (int) frameEndTicks; if (patternLength != 0) { int ntick = tick % patternLength; for (int voice = 0; voice < NUM_DRUM_VOICES; voice++) { if (mute[voice]) continue; if (pattern[voice][ntick] > 0) { // we need to queue the appropriate note in the drum machine's synth. int offset = transport.ticksToSamples(tick) - frameStartSamples; if (offset > 0) { MidiMessage msg = MidiMessage::noteOn(1, voice, (float) 1.0); msg.setTimeStamp(offset); midiCollector.addMessageToQueue(msg); } } } } } } // the synth always adds its output to the audio buffer, so we have to clear it // first.. bufferToFill.clearActiveBufferRegion(); // fill a midi buffer with incoming messages from the midi input. MidiBuffer incomingMidi; midiCollector.removeNextBlockOfMessages(incomingMidi, bufferToFill.numSamples); // pass these messages to the keyboard state so that it can update the component // to show on-screen which keys are being pressed on the physical midi keyboard. // This call will also add midi messages to the buffer which were generated by // the mouse-clicking on the on-screen keyboard. keyboardState.processNextMidiBuffer(incomingMidi, 0, bufferToFill.numSamples, true); // and now get the synth to process the midi events and generate its output. synth.renderNextBlock(*bufferToFill.buffer, incomingMidi, 0, bufferToFill.numSamples); bufferToFill.buffer->applyGain(0, 0, bufferToFill.numSamples, 0.2); bufferToFill.buffer->applyGain(1, 0, bufferToFill.numSamples, 0.2); }
//============================================================================== bool MidiSequencePlugin::eventAdded (const int controller, const double automationValue, const float beatNumber) { MidiMessage msgOn = MidiMessage::controllerEvent (NOTE_CHANNEL, controller, automationValue * 127); msgOn.setTimeStamp (beatNumber); DBG ("Adding:" +String (automationValue) + " " + String (beatNumber)); { const ScopedLock sl (parentHost->getCallbackLock ()); midiSequence->addEvent (msgOn); } DBG ("Added:" + String (automationValue) + " " + String (beatNumber)); return true; }
//============================================================================== bool MidiSequencePlugin::eventMoved ( const int controllerNum, const double oldValue, const float oldBeat, const double automationValue, const float beatNumber) { DBG ("Moving:" + String (oldValue) + " " + String (oldBeat)); double noteOnBeats = oldBeat - NOTE_PREFRAMES; int eventIndex = midiSequence->getNextIndexAtTime (noteOnBeats); while (eventIndex < midiSequence->getNumEvents ()) { MidiMessage* eventOn = &midiSequence->getEventPointer (eventIndex)->message; if (eventOn->isController() && eventOn->getControllerNumber() == controllerNum && eventOn->getControllerValue() == floor(oldValue * 127)) // should make this a "matches controller" method { MidiMessage msgOn = MidiMessage::controllerEvent (NOTE_CHANNEL, controllerNum, automationValue * 127); msgOn.setTimeStamp (beatNumber); { const ScopedLock sl (parentHost->getCallbackLock()); // remove old events midiSequence->deleteEvent (eventIndex, true); midiSequence->addEvent (msgOn); } return true; } eventIndex++; } DBG (">>> Move failed:" + String (oldValue) + " @ " + String (oldBeat)); return false; }
//============================================================================== void MainContentComponent::handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) { MidiMessage m (MidiMessage::noteOff (midiChannel, midiNoteNumber, velocity)); m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001); sendToOutputs (m); }
MidiMessageSequence* MidiStochaster::createMelody(int minOctaveOffset, int maxOctaveOffset, double speedFactor) { int currentOctaveOffset; if (minOctaveOffset <= 0) { currentOctaveOffset = 0; } else { currentOctaveOffset = minOctaveOffset; } int randInt1 = randomInt(100, 200); double stopProbability = (double) randInt1 / (randInt1 + 1); int randInt2 = randomInt(4, 10); double octaveSwitchProbability = (double) randInt2 / (randInt2 + 1); double currentTime = 0.0; MidiMessageSequence* melody = new MidiMessageSequence(starter); if (!goodSource) { return melody; } while (randomDouble(0,1) < stopProbability) { int notePitch = pitches->at(randomInt(0, pitches->size() - 1)) + 12 * currentOctaveOffset; while (notePitch < 0) { notePitch+=12; currentOctaveOffset++; minOctaveOffset++; } while (notePitch > 127) { notePitch-=12; currentOctaveOffset--; maxOctaveOffset--; } int noteVelocity = randomInt(lowVelocity, highVelocity); int noteLength = randomDouble(lowNoteLength, highNoteLength) * (1.0 / speedFactor); int nextRestLength; if (randomDouble(0,1) < negRestProbability) { nextRestLength = randomDouble(lowNegRestLength, highNegRestLength) * 1.0 / speedFactor; } else { nextRestLength = randomDouble(lowRestLength, highRestLength) * 1.0 / speedFactor; } MidiMessage noteDown = MidiMessage::noteOn(1, notePitch, (uint8_t) noteVelocity); noteDown.setTimeStamp(currentTime); MidiMessage noteUp = MidiMessage::noteOff(1, notePitch); noteUp.setTimeStamp(currentTime + noteLength); melody->addEvent(noteDown); melody->addEvent(noteUp); melody->updateMatchedPairs(); currentTime += noteLength + nextRestLength; if (randomDouble(0,1) > octaveSwitchProbability) { currentOctaveOffset = randomInt(minOctaveOffset, maxOctaveOffset); } } return melody; }