Browse Source

Use ticks in midi-sequencer (48 ticks per beat)

tags/1.9.6
falkTX 10 years ago
parent
commit
843fd5914d
3 changed files with 129 additions and 82 deletions
  1. +10
    -4
      source/native-plugins/midi-base.hpp
  2. +2
    -2
      source/native-plugins/midi-file.cpp
  3. +117
    -76
      source/native-plugins/midi-sequencer.cpp

+ 10
- 4
source/native-plugins/midi-base.hpp View File

@@ -52,7 +52,7 @@ class AbstractMidiPlayer
{
public:
virtual ~AbstractMidiPlayer() {}
virtual void writeMidiEvent(const uint8_t port, const uint64_t timePosFrame, const RawMidiEvent* const event) = 0;
virtual void writeMidiEvent(const uint8_t port, const long double timePosFrame, const RawMidiEvent* const event) = 0;
};

// -----------------------------------------------------------------------
@@ -230,12 +230,18 @@ public:
// -------------------------------------------------------------------
// play on time

void play(uint64_t timePosFrame, const uint32_t frames)
void play(const uint64_t timePosFrame, const uint32_t frames)
{
play(static_cast<long double>(timePosFrame), static_cast<double>(frames));
}

void play(long double timePosFrame, const double frames)
{
if (! fMutex.tryLock())
return;

timePosFrame += fStartTime;
if (fStartTime != 0)
timePosFrame += static_cast<long double>(fStartTime);

for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
{
@@ -247,7 +253,7 @@ public:
if (timePosFrame + frames <= rawMidiEvent->time)
continue;

kPlayer->writeMidiEvent(fMidiPort, timePosFrame, rawMidiEvent);
kPlayer->writeMidiEvent(fMidiPort, static_cast<long double>(rawMidiEvent->time)-timePosFrame, rawMidiEvent);
}

fMutex.unlock();


+ 2
- 2
source/native-plugins/midi-file.cpp View File

@@ -99,12 +99,12 @@ protected:
// -------------------------------------------------------------------
// AbstractMidiPlayer calls

void writeMidiEvent(const uint8_t port, const uint64_t timePosFrame, const RawMidiEvent* const event) override
void writeMidiEvent(const uint8_t port, const long double timePosFrame, const RawMidiEvent* const event) override
{
NativeMidiEvent midiEvent;

midiEvent.port = port;
midiEvent.time = uint32_t(event->time-timePosFrame);
midiEvent.time = uint32_t(timePosFrame);
midiEvent.size = event->size;
midiEvent.data[0] = event->data[0];
midiEvent.data[1] = event->data[1];


+ 117
- 76
source/native-plugins/midi-sequencer.cpp View File

@@ -26,106 +26,137 @@ class MidiSequencerPlugin : public NativePluginAndUiClass,
public AbstractMidiPlayer
{
public:
enum Parameters {
kParameterCount = 0
};

MidiSequencerPlugin(const NativeHostDescriptor* const host)
: NativePluginAndUiClass(host, CARLA_OS_SEP_STR "midiseq-ui"),
fWantInEvents(false),
fWasPlayingBefore(false),
fTicksPerFrame(0.0),
fInEvents(),
fMidiOut(this),
fTimeInfo(),
leakDetector_MidiSequencerPlugin()
{
// TEST SONG (unsorted to test RtList API)
// TEST SONG

uint32_t m = 44;
// assuming 4x4
const uint32_t onebeat = 48; // 1 beat = 48 ticks
//const uint32_t onebar = onebeat*4; // 1 bar = 4 beats

fMidiOut.addControl(0*m, 0, 7, 99);
fMidiOut.addControl(0*m, 0, 10, 63);
fMidiOut.addProgram(0*m, 0, 0, 0);
// 0 On ch=1 n=64 v=90
// 325 Off ch=1 n=64 v=90
// 384 On ch=1 n=62 v=90
// 709 Off ch=1 n=62 v=90
// 768 On ch=1 n=60 v=90
//1093 Off ch=1 n=60 v=90
uint32_t curTick = 0;

// 6912 On ch=1 n=60 v=90
// 7237 Off ch=1 n=60 v=90
// 7296 On ch=1 n=62 v=90
// 7621 Off ch=1 n=62 v=90
// 7680 On ch=1 n=64 v=90
// 8005 Off ch=1 n=64 v=90
fMidiOut.addNote(6912*m, 0, 60, 90, 325*m);
fMidiOut.addNote(7680*m, 0, 64, 90, 325*m);
fMidiOut.addNote(7296*m, 0, 62, 90, 325*m);
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 60, 90, onebeat-1);
curTick += onebeat;

// 1152 On ch=1 n=62 v=90
// 1152 On ch=1 n=62 v=90
// 1477 Off ch=1 n=62 v=90
// 1536 On ch=1 n=64 v=90
// 1536 On ch=1 n=64 v=90
// 1861 Off ch=1 n=64 v=90
// 1920 On ch=1 n=64 v=90
// 1920 On ch=1 n=64 v=90
// 2245 Off ch=1 n=64 v=90
fMidiOut.addNote(1152*m, 0, 62, 90, 325*m);
fMidiOut.addNote(1920*m, 0, 64, 90, 325*m);
fMidiOut.addNote(1536*m, 0, 64, 90, 325*m);
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;

// 2304 On ch=1 n=64 v=90
// 2955 Off ch=1 n=64 v=90

// 3840 On ch=1 n=62 v=90
// 3072 On ch=1 n=62 v=90
// 3397 Off ch=1 n=62 v=90
// 3456 On ch=1 n=62 v=90
// 3781 Off ch=1 n=62 v=90
fMidiOut.addNote(curTick, 0, 64, 90, onebeat*2-1);
curTick += onebeat*2;
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;

// 3840 On ch=1 n=62 v=90
// 4491 Off ch=1 n=62 v=90
// 4608 On ch=1 n=64 v=90
// 4608 On ch=1 n=64 v=90
// 4933 Off ch=1 n=64 v=90
// 4992 On ch=1 n=67 v=90
// 4992 On ch=1 n=67 v=90
// 5317 Off ch=1 n=67 v=90
fMidiOut.addNote(3840*m, 0, 62, 90, 650*m);
fMidiOut.addNote(4992*m, 0, 67, 90, 325*m);
fMidiOut.addNote(4608*m, 0, 64, 90, 325*m);

// 0 On ch=1 n=64 v=90
// 325 Off ch=1 n=64 v=90
// 384 On ch=1 n=62 v=90
// 709 Off ch=1 n=62 v=90
// 768 On ch=1 n=60 v=90
//1093 Off ch=1 n=60 v=90
fMidiOut.addNote( 0*m, 0, 64, 90, 325*m);
fMidiOut.addNote(768*m, 0, 60, 90, 325*m);
fMidiOut.addNote(384*m, 0, 62, 90, 325*m);

// 10752 On ch=1 n=60 v=90
// 12056 Off ch=1 n=60 v=90
fMidiOut.addNote(10752*m, 0, 60, 90, 650*m);

// 5376 On ch=1 n=67 v=90
fMidiOut.addNote(curTick, 0, 62, 90, onebeat*2-1);
curTick += onebeat*2;
fMidiOut.addNote(curTick, 0, 67, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;

// 5376 On ch=1 n=67 v=90
// 6027 Off ch=1 n=67 v=90
// 6144 On ch=1 n=64 v=90
// 6144 On ch=1 n=64 v=90
// 6469 Off ch=1 n=64 v=90
// 6528 On ch=1 n=62 v=90
// 6528 On ch=1 n=62 v=90
// 6853 Off ch=1 n=62 v=90
fMidiOut.addNote(5376*m, 0, 67, 90, 650*m);
fMidiOut.addNote(6144*m, 0, 64, 90, 325*m);
fMidiOut.addNote(6528*m, 0, 62, 90, 325*m);

// 8064 On ch=1 n=64 v=90
fMidiOut.addNote(curTick, 0, 67, 90, onebeat*2-1);
curTick += onebeat*2;
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;

// 6912 On ch=1 n=60 v=90
// 7237 Off ch=1 n=60 v=90
// 7296 On ch=1 n=62 v=90
// 7621 Off ch=1 n=62 v=90
// 7680 On ch=1 n=64 v=90
// 8005 Off ch=1 n=64 v=90
fMidiOut.addNote(curTick, 0, 60, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;

// 8064 On ch=1 n=64 v=90
// 8389 Off ch=1 n=64 v=90
// 8448 On ch=1 n=64 v=90
// 8448 On ch=1 n=64 v=90
// 9099 Off ch=1 n=64 v=90
// 9216 On ch=1 n=62 v=90
// 9216 On ch=1 n=62 v=90
// 9541 Off ch=1 n=62 v=90
fMidiOut.addNote(8064*m, 0, 64, 90, 325*m);
fMidiOut.addNote(8448*m, 0, 64, 90, 650*m);
fMidiOut.addNote(9216*m, 0, 62, 90, 325*m);

// 9600 On ch=1 n=62 v=90
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 64, 90, onebeat*2-1);
curTick += onebeat*2;
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;

// 9600 On ch=1 n=62 v=90
// 9925 Off ch=1 n=62 v=90
// 9984 On ch=1 n=64 v=90
// 9984 On ch=1 n=64 v=90
// 10309 Off ch=1 n=64 v=90
// 10368 On ch=1 n=62 v=90
// 10368 On ch=1 n=62 v=90
// 10693 Off ch=1 n=62 v=90
fMidiOut.addNote(9600*m, 0, 62, 90, 325*m);
fMidiOut.addNote(9984*m, 0, 64, 90, 325*m);
fMidiOut.addNote(10368*m, 0, 62, 90, 325*m);

// 2304 On ch=1 n=64 v=90
// 2955 Off ch=1 n=64 v=90
// 3072 On ch=1 n=62 v=90
// 3397 Off ch=1 n=62 v=90
// 3456 On ch=1 n=62 v=90
// 3781 Off ch=1 n=62 v=90
fMidiOut.addNote(2304*m, 0, 64, 90, 650*m);
fMidiOut.addNote(3072*m, 0, 62, 90, 325*m);
fMidiOut.addNote(3456*m, 0, 62, 90, 325*m);
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 64, 90, onebeat-1);
curTick += onebeat;
fMidiOut.addNote(curTick, 0, 62, 90, onebeat-1);
curTick += onebeat;

// 10752 On ch=1 n=60 v=90
// 12056 Off ch=1 n=60 v=90
fMidiOut.addNote(curTick, 0, 60, 90, onebeat*2-1);
curTick += onebeat*2;

carla_zeroStruct(fTimeInfo);
}
@@ -165,8 +196,13 @@ protected:

if (fTimeInfo.playing)
{
// TODO: convert frames to ticks, using 48 ticks per beat
fMidiOut.play(fTimeInfo.frame, frames);
if (! fTimeInfo.bbt.valid)
fTimeInfo.bbt.beatsPerMinute = 120.0;

fTicksPerFrame = 48.0 / (60.0 / fTimeInfo.bbt.beatsPerMinute * getSampleRate());

fMidiOut.play(fTicksPerFrame*static_cast<long double>(fTimeInfo.frame),
fTicksPerFrame*static_cast<double>(frames));
}
else if (fWasPlayingBefore)
{
@@ -263,18 +299,21 @@ protected:
// -------------------------------------------------------------------
// AbstractMidiPlayer calls

void writeMidiEvent(const uint8_t port, const uint64_t timePosFrame, const RawMidiEvent* const event) override
void writeMidiEvent(const uint8_t port, const long double timePosFrame, const RawMidiEvent* const event) override
{
NativeMidiEvent midiEvent;

midiEvent.port = port;
midiEvent.time = uint32_t(event->time-timePosFrame);
midiEvent.time = uint32_t(timePosFrame/fTicksPerFrame);
midiEvent.data[0] = event->data[0];
midiEvent.data[1] = event->data[1];
midiEvent.data[2] = event->data[2];
midiEvent.data[3] = event->data[3];
midiEvent.size = event->size;

carla_stdout("Playing at %i :: %03X:%03i:%03i",
midiEvent.time, midiEvent.data[0], midiEvent.data[1], midiEvent.data[2]);

NativePluginAndUiClass::writeMidiEvent(&midiEvent);
}

@@ -343,6 +382,8 @@ private:
bool fWantInEvents;
bool fWasPlayingBefore;

double fTicksPerFrame;

struct InRtEvents {
CarlaMutex mutex;
RtLinkedList<RawMidiEvent>::Pool dataPool;
@@ -438,7 +479,7 @@ static const NativePluginDescriptor midisequencerDesc = {
/* audioOuts */ 0,
/* midiIns */ 1,
/* midiOuts */ 1,
/* paramIns */ 0,
/* paramIns */ MidiSequencerPlugin::kParameterCount,
/* paramOuts */ 0,
/* name */ "MIDI Sequencer",
/* label */ "midisequencer",


Loading…
Cancel
Save