Use MIDI Sequences

This commit is contained in:
Matthias Neeracher 2006-10-16 09:00:02 +00:00
parent fe55af3f7c
commit a80c82cb18

View File

@ -15,76 +15,38 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
const int kMidiChannelInUse = 0;
enum {
kMidiMessage_ControlChange = 0xB,
kMidiMessage_ProgramChange = 0xC,
kMidiMessage_BankMSBControl = 0,
kMidiMessage_BankLSBControl = 32,
kMidiMessage_NoteOn = 0x9,
kMidiMessage_NoteOff = 0x8
};
class VLAUSoundOut : public VLSoundOut { class VLAUSoundOut : public VLSoundOut {
public: public:
VLAUSoundOut(); VLAUSoundOut();
virtual void PlayNote(const VLNote & note); virtual void PlayNote(const VLNote & note);
virtual void PlayChord(const VLChord & chord); virtual void PlayChord(const VLChord & chord);
virtual ~VLAUSoundOut(); virtual ~VLAUSoundOut();
private:
AUGraph fGraph;
AudioUnit fSynth;
bool fRunning;
void Run();
void Stop(); void Stop();
void Play(const int8_t * note, size_t numNotes = 1); private:
protected: AUGraph fGraph;
friend class VLAUSoundEvent; MusicPlayer fPlayer;
MusicSequence fMusic;
bool fRunning;
void Play(const int8_t * note, size_t numNotes, void PlaySequence(MusicSequence music);
UInt32 msg, UInt32 velocity); void Play(const int8_t * note, size_t numNotes = 1);
}; };
VLSoundEvent::~VLSoundEvent() VLSoundEvent::~VLSoundEvent()
{ {
} }
class VLAUSoundEvent : public VLSoundEvent {
public:
VLAUSoundEvent(VLAUSoundOut * soundOut,
const int8_t * note, size_t numNotes,
UInt32 msg, UInt32 velocity)
: fSoundOut(soundOut), fNotes(note, note+numNotes),
fMsg(msg), fVelocity(velocity)
{}
virtual void Perform();
private:
VLAUSoundOut * fSoundOut;
std::vector<int8_t> fNotes;
UInt32 fMsg;
UInt32 fVelocity;
};
void VLAUSoundEvent::Perform()
{
fSoundOut->Play(&fNotes[0], fNotes.size(), fMsg, fVelocity);
delete this;
}
void VLSoundScheduler::Schedule(VLSoundEvent * what, float when) void VLSoundScheduler::Schedule(VLSoundEvent * what, float when)
{ {
usleep((int)(1000000.0f*when)); usleep((int)(1000000.0f*when));
what->Perform(); what->Perform();
} }
static std::auto_ptr<VLSoundOut> sSoundOut; static std::auto_ptr<VLSoundOut> sSoundOut;
static std::auto_ptr<VLSoundScheduler> sSoundScheduler; static std::auto_ptr<VLSoundScheduler> sSoundScheduler;
VLSoundOut * VLSoundOut::Instance() VLSoundOut * VLSoundOut::Instance()
{ {
@ -93,6 +55,12 @@ VLSoundOut * VLSoundOut::Instance()
if (!sSoundScheduler.get()) if (!sSoundScheduler.get())
sSoundScheduler.reset(new VLSoundScheduler); sSoundScheduler.reset(new VLSoundScheduler);
} }
}
VLSoundOut * VLSoundOut::Instance()
{
if (!sSoundOut.get())
sSoundOut.reset(new VLAUSoundOut);
return sSoundOut.get(); return sSoundOut.get();
} }
@ -107,7 +75,7 @@ VLSoundOut::~VLSoundOut()
} }
VLAUSoundOut::VLAUSoundOut() VLAUSoundOut::VLAUSoundOut()
: fRunning(false) : fRunning(false), fMusic(0)
{ {
AUNode synthNode, limiterNode, outNode; AUNode synthNode, limiterNode, outNode;
ComponentDescription cd; ComponentDescription cd;
@ -136,39 +104,42 @@ VLAUSoundOut::VLAUSoundOut()
AUGraphOpen(fGraph); AUGraphOpen(fGraph);
AUGraphConnectNodeInput(fGraph, synthNode, 0, limiterNode, 0); AUGraphConnectNodeInput(fGraph, synthNode, 0, limiterNode, 0);
AUGraphConnectNodeInput(fGraph, limiterNode, 0, outNode, 0); AUGraphConnectNodeInput(fGraph, limiterNode, 0, outNode, 0);
AUGraphGetNodeInfo(fGraph, synthNode, 0, 0, 0, &fSynth);
AUGraphInitialize(fGraph); AUGraphInitialize(fGraph);
MusicDeviceMIDIEvent(fSynth, NewMusicPlayer(&fPlayer);
kMidiMessage_ControlChange << 4 | kMidiChannelInUse,
kMidiMessage_BankMSBControl, 0,
0/*sample offset*/);
MusicDeviceMIDIEvent(fSynth,
kMidiMessage_ProgramChange << 4 | kMidiChannelInUse,
0/*prog change num*/, 0,
0/*sample offset*/);
} }
VLAUSoundOut::~VLAUSoundOut() VLAUSoundOut::~VLAUSoundOut()
{ {
DisposeMusicPlayer(fPlayer);
Stop(); Stop();
DisposeAUGraph(fGraph); DisposeAUGraph(fGraph);
} }
void VLAUSoundOut::Run() void VLAUSoundOut::PlaySequence(MusicSequence music)
{ {
if (!fRunning) { Stop();
AUGraphStart(fGraph);
fRunning = true; fMusic = music;
}
MusicSequenceSetAUGraph(fMusic, fGraph);
MusicPlayerSetSequence(fPlayer, fMusic);
MusicPlayerStart(fPlayer);
fRunning = true;
} }
void VLAUSoundOut::Stop() void VLAUSoundOut::Stop()
{ {
MusicPlayerStop(fPlayer);
if (fRunning) { if (fRunning) {
AUGraphStop(fGraph);
fRunning = false; fRunning = false;
if (fMusic) {
MusicPlayerSetSequence(fPlayer, NULL);
DisposeMusicSequence(fMusic);
fMusic = 0;
}
} }
} }
@ -191,20 +162,17 @@ void VLAUSoundOut::PlayChord(const VLChord & chord)
void VLAUSoundOut::Play(const int8_t * note, size_t numNotes) void VLAUSoundOut::Play(const int8_t * note, size_t numNotes)
{ {
Run(); MusicSequence music;
MusicTrack track;
const UInt32 kNoteOn = kMidiMessage_NoteOn << 4 | kMidiChannelInUse;
const UInt32 kNoteOff = kMidiMessage_NoteOff << 4 | kMidiChannelInUse; NewMusicSequence(&music);
const UInt32 kNoteVelocity= 127; MusicSequenceNewTrack(music, &track);
Play(note, numNotes, kNoteOn, kNoteVelocity); const int8_t kNoteVelocity = 127;
sSoundScheduler.get()->Schedule( for (int i=0; i<numNotes; ++i) {
new VLAUSoundEvent(this, note, numNotes, kNoteOff, kNoteVelocity), 0.5f); MIDINoteMessage n = {0, note[i], kNoteVelocity, 0, 1.0};
} MusicTrackNewMIDINoteEvent(track, 0.0, &n);
}
void VLAUSoundOut::Play(const int8_t * note, size_t numNotes,
UInt32 msg, UInt32 velocity) PlaySequence(music);
{
for (size_t i = 0; i<numNotes; ++i)
MusicDeviceMIDIEvent(fSynth, msg, note[i], velocity, 0);
} }