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: public:
virtual ~AbstractMidiPlayer() {} 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 // 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()) if (! fMutex.tryLock())
return; return;


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


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


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


fMutex.unlock(); fMutex.unlock();


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

@@ -99,12 +99,12 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// AbstractMidiPlayer calls // 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; NativeMidiEvent midiEvent;


midiEvent.port = port; midiEvent.port = port;
midiEvent.time = uint32_t(event->time-timePosFrame);
midiEvent.time = uint32_t(timePosFrame);
midiEvent.size = event->size; midiEvent.size = event->size;
midiEvent.data[0] = event->data[0]; midiEvent.data[0] = event->data[0];
midiEvent.data[1] = event->data[1]; 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 AbstractMidiPlayer
{ {
public: public:
enum Parameters {
kParameterCount = 0
};

MidiSequencerPlugin(const NativeHostDescriptor* const host) MidiSequencerPlugin(const NativeHostDescriptor* const host)
: NativePluginAndUiClass(host, CARLA_OS_SEP_STR "midiseq-ui"), : NativePluginAndUiClass(host, CARLA_OS_SEP_STR "midiseq-ui"),
fWantInEvents(false), fWantInEvents(false),
fWasPlayingBefore(false), fWasPlayingBefore(false),
fTicksPerFrame(0.0),
fInEvents(), fInEvents(),
fMidiOut(this), fMidiOut(this),
fTimeInfo(), fTimeInfo(),
leakDetector_MidiSequencerPlugin() 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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); carla_zeroStruct(fTimeInfo);
} }
@@ -165,8 +196,13 @@ protected:


if (fTimeInfo.playing) 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) else if (fWasPlayingBefore)
{ {
@@ -263,18 +299,21 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// AbstractMidiPlayer calls // 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; NativeMidiEvent midiEvent;


midiEvent.port = port; midiEvent.port = port;
midiEvent.time = uint32_t(event->time-timePosFrame);
midiEvent.time = uint32_t(timePosFrame/fTicksPerFrame);
midiEvent.data[0] = event->data[0]; midiEvent.data[0] = event->data[0];
midiEvent.data[1] = event->data[1]; midiEvent.data[1] = event->data[1];
midiEvent.data[2] = event->data[2]; midiEvent.data[2] = event->data[2];
midiEvent.data[3] = event->data[3]; midiEvent.data[3] = event->data[3];
midiEvent.size = event->size; 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); NativePluginAndUiClass::writeMidiEvent(&midiEvent);
} }


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


double fTicksPerFrame;

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


Loading…
Cancel
Save