|
- /*
- ==============================================================================
-
- This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi.
-
- JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2008 by Julian Storer.
-
- ------------------------------------------------------------------------------
-
- JUCE and JUCETICE can be redistributed and/or modified under the terms of
- the GNU Lesser General Public License, as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- JUCE and JUCETICE are distributed in the hope that they will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ==============================================================================
-
- @author rockhardbuns
- @tweaker Lucio Asnaghi
- @tweaker falkTX
-
- ==============================================================================
- */
-
- #ifndef DISTRHO_VEX_ARP_HEADER_INCLUDED
- #define DISTRHO_VEX_ARP_HEADER_INCLUDED
-
- #include "VexArpSettings.h"
-
- #ifndef CARLA_EXPORT
- #define CARLA_EXPORT
- #endif
-
- #ifdef CARLA_EXPORT
- #include "juce_audio_basics.h"
- #else
- #include "../StandardHeader.h"
- #endif
-
- class VexArp
- {
- public:
- static const int kMaxNotes = 10;
-
- VexArp(const VexArpSettings* p)
- : arpSet(p),
- dead(true),
- notesPlaying(false),
- doSync(true),
- nextStep(0),
- sampleCount(0),
- sampleRate(44100)
- {
- meter[0] = 4;
- meter[1] = 8;
- meter[2] = 16;
- meter[3] = 32;
-
- for (int i = 0; i < kMaxNotes; ++i)
- {
- cKeysDown[i] = 0;
- cNotesToKill[i] = 0;
- cKeysVelocity[i] = 0;
- }
-
- outMidiBuffer.ensureSize(kMaxNotes+128);
- }
-
- void addNote(const char note, const char vel)
- {
- char tmp, tmpNote = note, tmpVel = vel;
-
- for (int i = 0; i < kMaxNotes; ++i)
- {
- if (note < cKeysDown[i] || cKeysDown[i] == 0)
- {
- tmp = cKeysDown[i]; cKeysDown[i] = tmpNote; tmpNote = tmp;
- tmp = cKeysVelocity[i]; cKeysVelocity[i] = tmpVel; tmpVel = tmp;
- }
- }
-
- doSync = true;
- }
-
- void dropNote(const char note)
- {
- int i = 0;
-
- for (; i < kMaxNotes; ++i)
- {
- if (cKeysDown[i] == note)
- break;
- }
-
- if (i == kMaxNotes)
- return;
-
- for (; i < kMaxNotes-1; ++i)
- {
- cKeysDown[i] = cKeysDown[i+1];
- cKeysVelocity[i] = cKeysVelocity[i+1];
- }
-
- cKeysDown[kMaxNotes-1] = 0;
- cKeysVelocity[kMaxNotes-1] = 0;
- }
-
- void killThisNoteLater(const char note)
- {
- for (int i = 0; i < kMaxNotes; ++i)
- {
- if (cNotesToKill[i] == note)
- break;
-
- if (cNotesToKill[i] == 0)
- {
- cNotesToKill[i] = note;
- break;
- }
- }
- }
-
- void setSampleRate(const int srate)
- {
- sampleRate = srate;
- }
-
- const MidiBuffer& processMidi(MidiBuffer& inMidiBuffer, const bool isPlaying,
- const double ppqPosition,
- const double ppqPositionOfLastBarStart,
- const double bpm,
- const int numSamples)
- {
- const int timeSig = meter[arpSet->timeMode];
-
- // Loop though the midibuffer, take away note on/off, let the rest pass
- {
- outMidiBuffer.clear();
-
- MidiBuffer::Iterator inBufferIterator(inMidiBuffer);
- MidiMessage midiMessage(0xf4);
- int samplePosition;
-
- while (inBufferIterator.getNextEvent(midiMessage, samplePosition))
- {
- if (midiMessage.isNoteOn())
- addNote(midiMessage.getNoteNumber(), midiMessage.getVelocity());
- else if (midiMessage.isNoteOff())
- dropNote(midiMessage.getNoteNumber());
- else
- outMidiBuffer.addEvent(midiMessage, samplePosition);
- }
- }
-
- const double beatsPerSec = (60.0 * double(sampleRate)) / bpm;
-
- // BarSync
- const unsigned int samplesPerStep = int(beatsPerSec * 4.0) / timeSig;
-
- if (isPlaying && arpSet->syncMode == 2) // bar sync
- {
- if (doSync)
- {
- //offset sample count
- sampleCount = int((ppqPosition - ppqPositionOfLastBarStart) * beatsPerSec);
-
- //offset step count
- nextStep = sampleCount / samplesPerStep;
-
- //Cycle the counts
- sampleCount = (sampleCount % samplesPerStep) + samplesPerStep - 10;
- nextStep = nextStep % arpSet->length;
-
- doSync = false;
- }
- }
- else
- {
- doSync = true;
- }
-
- //***************************
- if (cKeysDown[0])
- { // Keys are down
- dead = false;
- sampleCount += numSamples;
- bool repeat = false;
-
- do
- {
- repeat = false;
-
- //***
- if (sampleCount >= samplesPerStep)
- { //Play step
- int offset = numSamples - (sampleCount - samplesPerStep);
- bool doFail = true;
-
- for (int i = 0; i < 5; ++i)
- {
- if((cKeysDown[i]!= 0) && (arpSet->grid[nextStep*5 + i]))
- { // we have a note to play
- int vel;
-
- switch (arpSet->velMode)
- {
- case 1:
- vel = roundFloatToInt (arpSet->velocities[nextStep] * 127.0f);
- break;
- case 2:
- vel = (int) cKeysVelocity[i];
- break;
- case 3:
- vel = (int) cKeysVelocity[i] + roundFloatToInt (arpSet->velocities[nextStep] * 127.0f);
- break;
- default:
- vel = 127;
- break;
- }
-
- doFail = false;
- notesPlaying = true;
- killThisNoteLater(cKeysDown[i]);
- outMidiBuffer.addEvent(MidiMessage::noteOn(1, cKeysDown[i], uint8(vel)), offset);
- }
- }
-
- if (doFail)
- {
- switch (arpSet->failMode)
- {
- case 1: //normal
- sampleCount -= samplesPerStep;
- nextStep++;
- nextStep = nextStep % arpSet->length;
- break;
- case 2: //skip one
- //SampleCount -= SamplesPerStep;
- nextStep++;
- nextStep = nextStep % arpSet->length;
- repeat = true;
- break;
- case 3: //skip two
- //SampleCount -= SamplesPerStep;
- nextStep += 2;
- nextStep = nextStep % arpSet->length;
- repeat = true;
- break;
- }
- }
- else
- {
- sampleCount -= samplesPerStep;
- nextStep++;
- nextStep = nextStep % arpSet->length; //Cycle the steps over pattern length
- }
- }
- } while (repeat);
-
- //***
- unsigned int NoteLength = (samplesPerStep / 4) * 3;
- if ((sampleCount >= NoteLength) && notesPlaying)
- { //Mute step
- int offset = numSamples - (sampleCount - NoteLength);
- //***
- for(int i = 0; i < kMaxNotes; ++i)
- {
- if (cNotesToKill[i] != 0)
- { //do we have a note to kill?
- outMidiBuffer.addEvent(MidiMessage::noteOff(1, cNotesToKill[i]), offset);
- cNotesToKill[i] = 0;
- }
- }
- notesPlaying = false;
- }
- //***
- }
- else if (! dead)
- { //No keys pressed - kill 'em all
- for (int i = 0; i < kMaxNotes; ++i)
- {
- if (cNotesToKill[i] != 0)
- { //do we have a note to kill?
- outMidiBuffer.addEvent(MidiMessage::noteOff(1, cNotesToKill[i]), 0);
- cNotesToKill[i] = 0;
- }
- }
-
- nextStep = 0;
- sampleCount = samplesPerStep;
- dead = true;
- }
-
- return outMidiBuffer;
- }
-
- private:
- const VexArpSettings* arpSet;
- MidiBuffer outMidiBuffer;
- bool dead, notesPlaying, doSync; // doSync used only in bar-sync
- unsigned int nextStep;
- unsigned int sampleCount, sampleRate;
- int meter[4];
- char cKeysDown[kMaxNotes];
- char cKeysVelocity[kMaxNotes];
- char cNotesToKill[kMaxNotes];
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexArp)
- };
-
- #endif // DISTRHO_VEX_ARP_HEADER_INCLUDED
|