|
- /*
- * Carla Native Plugins
- * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or any later version.
- *
- * This program is distributed in the hope that it 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.
- *
- * For a full copy of the GNU General Public License see the doc/GPL.txt file.
- */
-
- #ifndef MIDI_BASE_HPP_INCLUDED
- #define MIDI_BASE_HPP_INCLUDED
-
- #include "CarlaMIDI.h"
- #include "CarlaMutex.hpp"
- #include "LinkedList.hpp"
-
- #include "CarlaMathUtils.hpp"
-
- #define MAX_EVENT_DATA_SIZE 4
- #define MIN_PREALLOCATED_EVENT_COUNT 100
- #define MAX_PREALLOCATED_EVENT_COUNT 1000
-
- struct RawMidiEvent {
- uint64_t time;
- uint8_t size;
- uint8_t data[MAX_EVENT_DATA_SIZE];
-
- RawMidiEvent()
- : time(0),
- size(0)
- {
- carla_fill<uint8_t>(data, 0, MAX_EVENT_DATA_SIZE);
- }
- };
-
- class AbstractMidiPlayer
- {
- public:
- virtual ~AbstractMidiPlayer() {}
- virtual void writeMidiEvent(const uint64_t timePosFrame, const RawMidiEvent* const event) = 0;
- };
-
- class MidiPattern
- {
- public:
- MidiPattern(AbstractMidiPlayer* const player)
- : kPlayer(player),
- fMutex(),
- fData(),
- leakDetector_MidiPattern()
- //fStartTime(0),
- //fDuration(0)
- {
- CARLA_ASSERT(kPlayer != nullptr);
- }
-
- ~MidiPattern()
- {
- fData.clear();
- }
-
- void addControl(const uint64_t time, const uint8_t channel, const uint8_t control, const uint8_t value)
- {
- RawMidiEvent* ctrlEvent(new RawMidiEvent());
- ctrlEvent->time = time;
- ctrlEvent->size = 3;
- ctrlEvent->data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F));
- ctrlEvent->data[1] = control;
- ctrlEvent->data[2] = value;
-
- append(ctrlEvent);
- }
-
- void addChannelPressure(const uint64_t time, const uint8_t channel, const uint8_t pressure)
- {
- RawMidiEvent* pressureEvent(new RawMidiEvent());
- pressureEvent->time = time;
- pressureEvent->size = 2;
- pressureEvent->data[0] = uint8_t(MIDI_STATUS_CHANNEL_PRESSURE | (channel & 0x0F));
- pressureEvent->data[1] = pressure;
-
- append(pressureEvent);
- }
-
- void addNote(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity, const uint32_t duration)
- {
- addNoteOn(time, channel, pitch, velocity);
- addNoteOff(time+duration, channel, pitch, velocity);
- }
-
- void addNoteOn(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity)
- {
- RawMidiEvent* noteOnEvent(new RawMidiEvent());
- noteOnEvent->time = time;
- noteOnEvent->size = 3;
- noteOnEvent->data[0] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & 0x0F));
- noteOnEvent->data[1] = pitch;
- noteOnEvent->data[2] = velocity;
-
- append(noteOnEvent);
- }
-
- void addNoteOff(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity = 0)
- {
- RawMidiEvent* noteOffEvent(new RawMidiEvent());
- noteOffEvent->time = time;
- noteOffEvent->size = 3;
- noteOffEvent->data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & 0x0F));
- noteOffEvent->data[1] = pitch;
- noteOffEvent->data[2] = velocity;
-
- append(noteOffEvent);
- }
-
- void addNoteAftertouch(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t pressure)
- {
- RawMidiEvent* noteAfterEvent(new RawMidiEvent());
- noteAfterEvent->time = time;
- noteAfterEvent->size = 3;
- noteAfterEvent->data[0] = uint8_t(MIDI_STATUS_POLYPHONIC_AFTERTOUCH | (channel & 0x0F));
- noteAfterEvent->data[1] = pitch;
- noteAfterEvent->data[2] = pressure;
-
- append(noteAfterEvent);
- }
-
- void addProgram(const uint64_t time, const uint8_t channel, const uint8_t bank, const uint8_t program)
- {
- RawMidiEvent* bankEvent(new RawMidiEvent());
- bankEvent->time = time;
- bankEvent->size = 3;
- bankEvent->data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F));
- bankEvent->data[1] = MIDI_CONTROL_BANK_SELECT;
- bankEvent->data[2] = bank;
-
- RawMidiEvent* programEvent(new RawMidiEvent());
- programEvent->time = time;
- programEvent->size = 2;
- programEvent->data[0] = uint8_t(MIDI_STATUS_PROGRAM_CHANGE | (channel & 0x0F));
- programEvent->data[1] = program;
-
- append(bankEvent);
- append(programEvent);
- }
-
- void addPitchbend(const uint64_t time, const uint8_t channel, const uint8_t lsb, const uint8_t msb)
- {
- RawMidiEvent* pressureEvent(new RawMidiEvent());
- pressureEvent->time = time;
- pressureEvent->size = 3;
- pressureEvent->data[0] = uint8_t(MIDI_STATUS_PITCH_WHEEL_CONTROL | (channel & 0x0F));
- pressureEvent->data[1] = lsb;
- pressureEvent->data[2] = msb;
-
- append(pressureEvent);
- }
-
- void addRaw(const uint64_t time, const uint8_t* data, const uint8_t size)
- {
- RawMidiEvent* rawEvent(new RawMidiEvent());
- rawEvent->time = time;
- rawEvent->size = size;
-
- carla_copy<uint8_t>(rawEvent->data, data, size);
-
- append(rawEvent);
- }
-
- void play(uint64_t timePosFrame, uint32_t frames)
- {
- if (! fMutex.tryLock())
- return;
-
- for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
- {
- const RawMidiEvent* const rawMidiEvent(it.getValue());
-
- if (timePosFrame > rawMidiEvent->time)
- continue;
- if (timePosFrame + frames <= rawMidiEvent->time)
- continue;
-
- kPlayer->writeMidiEvent(timePosFrame, rawMidiEvent);
- }
-
- fMutex.unlock();
- }
-
- void clear()
- {
- const CarlaMutexLocker sl(fMutex);
- fData.clear();
- }
-
- private:
- AbstractMidiPlayer* const kPlayer;
-
- //uint32_t fStartTime; // unused
- //uint32_t fDuration; // unused
-
- CarlaMutex fMutex;
- LinkedList<const RawMidiEvent*> fData;
-
- void append(const RawMidiEvent* const event)
- {
- if (fData.isEmpty())
- {
- const CarlaMutexLocker sl(fMutex);
- fData.append(event);
- return;
- }
-
- for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
- {
- const RawMidiEvent* const oldEvent(it.getValue());
-
- if (event->time >= oldEvent->time)
- continue;
-
- const CarlaMutexLocker sl(fMutex);
- fData.insertAt(event, it);
- return;
- }
-
- const CarlaMutexLocker sl(fMutex);
- fData.append(event);
- }
-
- CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiPattern)
- };
-
- #endif // MIDI_BASE_HPP_INCLUDED
|