mirror of https://github.com/AxioDL/amuse.git
MIDI API refactor
This commit is contained in:
parent
2a5823d6de
commit
64ed5e2ea5
|
@ -174,6 +174,7 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
int m_sfxId = -1;
|
int m_sfxId = -1;
|
||||||
std::shared_ptr<amuse::Voice> m_vox;
|
std::shared_ptr<amuse::Voice> m_vox;
|
||||||
size_t m_lastVoxCount = 0;
|
size_t m_lastVoxCount = 0;
|
||||||
|
int8_t m_lastChanProg = -1;
|
||||||
|
|
||||||
/* Control state */
|
/* Control state */
|
||||||
float m_volume = 0.5f;
|
float m_volume = 0.5f;
|
||||||
|
@ -297,14 +298,22 @@ struct AppCallback : boo::IApplicationCallback
|
||||||
m_engine->pumpEngine();
|
m_engine->pumpEngine();
|
||||||
|
|
||||||
size_t voxCount;
|
size_t voxCount;
|
||||||
|
int8_t progId;
|
||||||
if (m_seq)
|
if (m_seq)
|
||||||
|
{
|
||||||
voxCount = m_seq->getVoiceCount();
|
voxCount = m_seq->getVoiceCount();
|
||||||
|
progId = m_seq->getChanProgram(m_chanId);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
voxCount = 0;
|
voxCount = 0;
|
||||||
|
progId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_lastVoxCount != voxCount)
|
if (m_lastVoxCount != voxCount || m_lastChanProg != progId)
|
||||||
{
|
{
|
||||||
m_lastVoxCount = voxCount;
|
m_lastVoxCount = voxCount;
|
||||||
|
m_lastChanProg = progId;
|
||||||
UpdateSongDisplay();
|
UpdateSongDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
#include "IBackendVoice.hpp"
|
#include "IBackendVoice.hpp"
|
||||||
#include "IBackendSubmix.hpp"
|
#include "IBackendSubmix.hpp"
|
||||||
#include "IBackendVoiceAllocator.hpp"
|
#include "IBackendVoiceAllocator.hpp"
|
||||||
|
#include <mutex>
|
||||||
|
#include <list>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
@ -66,15 +69,21 @@ public:
|
||||||
/** Backend MIDI event reader for controlling sequencer with external hardware / software */
|
/** Backend MIDI event reader for controlling sequencer with external hardware / software */
|
||||||
class BooBackendMIDIReader : public IMIDIReader, public boo::IMIDIReader
|
class BooBackendMIDIReader : public IMIDIReader, public boo::IMIDIReader
|
||||||
{
|
{
|
||||||
|
friend class BooBackendVoiceAllocator;
|
||||||
Engine& m_engine;
|
Engine& m_engine;
|
||||||
std::unique_ptr<boo::IMIDIIn> m_midiIn;
|
std::unique_ptr<boo::IMIDIIn> m_midiIn;
|
||||||
boo::MIDIDecoder m_decoder;
|
boo::MIDIDecoder m_decoder;
|
||||||
|
|
||||||
|
std::list<std::pair<std::chrono::steady_clock::time_point, std::vector<uint8_t>>> m_queue;
|
||||||
|
std::mutex m_midiMutex;
|
||||||
|
void _MIDIReceive(std::vector<uint8_t>&& bytes);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BooBackendMIDIReader(Engine& engine, std::unique_ptr<boo::IMIDIIn>&& in)
|
~BooBackendMIDIReader();
|
||||||
: m_engine(engine), m_midiIn(std::move(in)), m_decoder(*m_midiIn, *this) {}
|
BooBackendMIDIReader(Engine& engine, const char* name);
|
||||||
|
|
||||||
std::string description();
|
std::string description();
|
||||||
void pumpReader();
|
void pumpReader(double dt);
|
||||||
|
|
||||||
void noteOff(uint8_t chan, uint8_t key, uint8_t velocity);
|
void noteOff(uint8_t chan, uint8_t key, uint8_t velocity);
|
||||||
void noteOn(uint8_t chan, uint8_t key, uint8_t velocity);
|
void noteOn(uint8_t chan, uint8_t key, uint8_t velocity);
|
||||||
|
@ -107,6 +116,7 @@ public:
|
||||||
/** Backend voice allocator implementation for boo mixer */
|
/** Backend voice allocator implementation for boo mixer */
|
||||||
class BooBackendVoiceAllocator : public IBackendVoiceAllocator
|
class BooBackendVoiceAllocator : public IBackendVoiceAllocator
|
||||||
{
|
{
|
||||||
|
friend class BooBackendMIDIReader;
|
||||||
boo::IAudioVoiceEngine& m_booEngine;
|
boo::IAudioVoiceEngine& m_booEngine;
|
||||||
public:
|
public:
|
||||||
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
|
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Engine
|
||||||
friend class Voice;
|
friend class Voice;
|
||||||
friend class Emitter;
|
friend class Emitter;
|
||||||
friend class Sequencer;
|
friend class Sequencer;
|
||||||
friend class Sequencer::ChannelState;
|
friend struct Sequencer::ChannelState;
|
||||||
|
|
||||||
IBackendVoiceAllocator& m_backend;
|
IBackendVoiceAllocator& m_backend;
|
||||||
std::unique_ptr<IMIDIReader> m_midiReader;
|
std::unique_ptr<IMIDIReader> m_midiReader;
|
||||||
|
|
|
@ -29,7 +29,7 @@ class IMIDIReader
|
||||||
public:
|
public:
|
||||||
virtual ~IMIDIReader()=default;
|
virtual ~IMIDIReader()=default;
|
||||||
virtual std::string description()=0;
|
virtual std::string description()=0;
|
||||||
virtual void pumpReader()=0;
|
virtual void pumpReader(double dt)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Client-implemented voice allocator */
|
/** Client-implemented voice allocator */
|
||||||
|
|
|
@ -107,9 +107,55 @@ std::string BooBackendMIDIReader::description()
|
||||||
return m_midiIn->description();
|
return m_midiIn->description();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::pumpReader()
|
BooBackendMIDIReader::~BooBackendMIDIReader() {}
|
||||||
|
|
||||||
|
BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name)
|
||||||
|
: m_engine(engine), m_decoder(*this)
|
||||||
{
|
{
|
||||||
while (m_decoder.receiveBytes()) {}
|
BooBackendVoiceAllocator& voxAlloc = static_cast<BooBackendVoiceAllocator&>(engine.getBackend());
|
||||||
|
if (!name)
|
||||||
|
m_midiIn = voxAlloc.m_booEngine.newVirtualMIDIIn(std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
||||||
|
std::placeholders::_1));
|
||||||
|
else
|
||||||
|
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(name,
|
||||||
|
std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(m_midiMutex);
|
||||||
|
m_queue.emplace_back(std::chrono::steady_clock::now(), std::move(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BooBackendMIDIReader::pumpReader(double dt)
|
||||||
|
{
|
||||||
|
dt += 0.001; /* Add 1ms to ensure consumer keeps up with producer */
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lk(m_midiMutex);
|
||||||
|
if (m_queue.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Determine range of buffer updates within this period */
|
||||||
|
auto periodEnd = m_queue.cbegin();
|
||||||
|
std::chrono::steady_clock::time_point startPt = m_queue.front().first;
|
||||||
|
for (; periodEnd != m_queue.cend() ; ++periodEnd)
|
||||||
|
{
|
||||||
|
double delta = std::chrono::duration_cast<std::chrono::microseconds>
|
||||||
|
(periodEnd->first - startPt).count() / 1000000.0;
|
||||||
|
if (delta > dt)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_queue.cbegin() == periodEnd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Dispatch buffers */
|
||||||
|
for (auto it = m_queue.begin() ; it != periodEnd ;)
|
||||||
|
{
|
||||||
|
m_decoder.receiveBytes(it->second.cbegin(), it->second.cend());
|
||||||
|
it = m_queue.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendMIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
void BooBackendMIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
|
@ -241,16 +287,10 @@ std::vector<std::pair<std::string, std::string>> BooBackendVoiceAllocator::enume
|
||||||
|
|
||||||
std::unique_ptr<IMIDIReader> BooBackendVoiceAllocator::allocateMIDIReader(Engine& engine, const char* name)
|
std::unique_ptr<IMIDIReader> BooBackendVoiceAllocator::allocateMIDIReader(Engine& engine, const char* name)
|
||||||
{
|
{
|
||||||
std::unique_ptr<boo::IMIDIIn> inPort;
|
std::unique_ptr<IMIDIReader> ret = std::make_unique<BooBackendMIDIReader>(engine, name);
|
||||||
if (!name)
|
if (!static_cast<BooBackendMIDIReader&>(*ret).m_midiIn)
|
||||||
inPort = m_booEngine.newVirtualMIDIIn();
|
|
||||||
else
|
|
||||||
inPort = m_booEngine.newRealMIDIIn(name);
|
|
||||||
|
|
||||||
if (!inPort)
|
|
||||||
return {};
|
return {};
|
||||||
|
return ret;
|
||||||
return std::make_unique<BooBackendMIDIReader>(engine, std::move(inPort));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoiceAllocator::register5MsCallback(std::function<void(double)>&& callback)
|
void BooBackendVoiceAllocator::register5MsCallback(std::function<void(double)>&& callback)
|
||||||
|
|
|
@ -158,7 +158,7 @@ void Engine::_bringOutYourDead()
|
||||||
void Engine::_5MsCallback(double dt)
|
void Engine::_5MsCallback(double dt)
|
||||||
{
|
{
|
||||||
if (m_midiReader)
|
if (m_midiReader)
|
||||||
m_midiReader->pumpReader();
|
m_midiReader->pumpReader(dt);
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
||||||
seq->advance(dt);
|
seq->advance(dt);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue