Implemented MIDI flavor override control for Sound Canvas VA Audio Unit
parent
f10fa14668
commit
6c8a08fff1
|
@ -501,6 +501,8 @@ increase/decrease as long as the user holds the left/right, plus/minus button */
|
||||||
|
|
||||||
[userDefaultsValuesDict setObject:@"dls appl" forKey:@"midi.plugin"];
|
[userDefaultsValuesDict setObject:@"dls appl" forKey:@"midi.plugin"];
|
||||||
|
|
||||||
|
[userDefaultsValuesDict setObject:@"sc55" forKey:@"midi.flavor"];
|
||||||
|
|
||||||
//Register and sync defaults
|
//Register and sync defaults
|
||||||
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
|
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
83B06722180D70FE008E3612 /* MIDIDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83B06721180D70FE008E3612 /* MIDIDecoder.mm */; };
|
83B06722180D70FE008E3612 /* MIDIDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83B06721180D70FE008E3612 /* MIDIDecoder.mm */; };
|
||||||
83C35702180EDB74007E9DF0 /* MIDIContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83C35700180EDB74007E9DF0 /* MIDIContainer.mm */; };
|
83C35702180EDB74007E9DF0 /* MIDIContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83C35700180EDB74007E9DF0 /* MIDIContainer.mm */; };
|
||||||
83C35705180EDD1C007E9DF0 /* MIDIMetadataReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83C35703180EDD1C007E9DF0 /* MIDIMetadataReader.mm */; };
|
83C35705180EDD1C007E9DF0 /* MIDIMetadataReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83C35703180EDD1C007E9DF0 /* MIDIMetadataReader.mm */; };
|
||||||
|
83DFEA071CBC87BB00BCC565 /* SCCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83DFEA031CBC87BB00BCC565 /* SCCore.cpp */; };
|
||||||
|
83DFEA081CBC87BB00BCC565 /* SCPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83DFEA051CBC87BB00BCC565 /* SCPlayer.cpp */; };
|
||||||
83E973471C4378880007F413 /* AUPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83E973451C4378880007F413 /* AUPlayer.mm */; };
|
83E973471C4378880007F413 /* AUPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83E973451C4378880007F413 /* AUPlayer.mm */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
@ -108,6 +110,10 @@
|
||||||
83C35701180EDB74007E9DF0 /* MIDIContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIContainer.h; sourceTree = "<group>"; };
|
83C35701180EDB74007E9DF0 /* MIDIContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIContainer.h; sourceTree = "<group>"; };
|
||||||
83C35703180EDD1C007E9DF0 /* MIDIMetadataReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MIDIMetadataReader.mm; sourceTree = "<group>"; };
|
83C35703180EDD1C007E9DF0 /* MIDIMetadataReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MIDIMetadataReader.mm; sourceTree = "<group>"; };
|
||||||
83C35704180EDD1C007E9DF0 /* MIDIMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIMetadataReader.h; sourceTree = "<group>"; };
|
83C35704180EDD1C007E9DF0 /* MIDIMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIMetadataReader.h; sourceTree = "<group>"; };
|
||||||
|
83DFEA031CBC87BB00BCC565 /* SCCore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SCCore.cpp; sourceTree = "<group>"; };
|
||||||
|
83DFEA041CBC87BB00BCC565 /* SCCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCCore.h; sourceTree = "<group>"; };
|
||||||
|
83DFEA051CBC87BB00BCC565 /* SCPlayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SCPlayer.cpp; sourceTree = "<group>"; };
|
||||||
|
83DFEA061CBC87BB00BCC565 /* SCPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCPlayer.h; sourceTree = "<group>"; };
|
||||||
83E973451C4378880007F413 /* AUPlayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AUPlayer.mm; sourceTree = "<group>"; };
|
83E973451C4378880007F413 /* AUPlayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AUPlayer.mm; sourceTree = "<group>"; };
|
||||||
83E973461C4378880007F413 /* AUPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUPlayer.h; sourceTree = "<group>"; };
|
83E973461C4378880007F413 /* AUPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUPlayer.h; sourceTree = "<group>"; };
|
||||||
83FAF8A618ADD60100057CAF /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../../Playlist/PlaylistController.h; sourceTree = "<group>"; };
|
83FAF8A618ADD60100057CAF /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../../Playlist/PlaylistController.h; sourceTree = "<group>"; };
|
||||||
|
@ -179,6 +185,10 @@
|
||||||
83B06690180D5668008E3612 /* MIDI */ = {
|
83B06690180D5668008E3612 /* MIDI */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
83DFEA031CBC87BB00BCC565 /* SCCore.cpp */,
|
||||||
|
83DFEA041CBC87BB00BCC565 /* SCCore.h */,
|
||||||
|
83DFEA051CBC87BB00BCC565 /* SCPlayer.cpp */,
|
||||||
|
83DFEA061CBC87BB00BCC565 /* SCPlayer.h */,
|
||||||
83686AAD1C5C6A2700671C7A /* AUPlayerView.h */,
|
83686AAD1C5C6A2700671C7A /* AUPlayerView.h */,
|
||||||
83686AAB1C5C69D400671C7A /* AUPlayerView.mm */,
|
83686AAB1C5C69D400671C7A /* AUPlayerView.mm */,
|
||||||
83E973451C4378880007F413 /* AUPlayer.mm */,
|
83E973451C4378880007F413 /* AUPlayer.mm */,
|
||||||
|
@ -302,7 +312,9 @@
|
||||||
files = (
|
files = (
|
||||||
83E973471C4378880007F413 /* AUPlayer.mm in Sources */,
|
83E973471C4378880007F413 /* AUPlayer.mm in Sources */,
|
||||||
83686AAC1C5C69D400671C7A /* AUPlayerView.mm in Sources */,
|
83686AAC1C5C69D400671C7A /* AUPlayerView.mm in Sources */,
|
||||||
|
83DFEA071CBC87BB00BCC565 /* SCCore.cpp in Sources */,
|
||||||
83B06709180D64DA008E3612 /* MIDIPlayer.cpp in Sources */,
|
83B06709180D64DA008E3612 /* MIDIPlayer.cpp in Sources */,
|
||||||
|
83DFEA081CBC87BB00BCC565 /* SCPlayer.cpp in Sources */,
|
||||||
83B06722180D70FE008E3612 /* MIDIDecoder.mm in Sources */,
|
83B06722180D70FE008E3612 /* MIDIDecoder.mm in Sources */,
|
||||||
83C35702180EDB74007E9DF0 /* MIDIContainer.mm in Sources */,
|
83C35702180EDB74007E9DF0 /* MIDIContainer.mm in Sources */,
|
||||||
83B0670C180D6665008E3612 /* BMPlayer.cpp in Sources */,
|
83B0670C180D6665008E3612 /* BMPlayer.cpp in Sources */,
|
||||||
|
|
|
@ -31,8 +31,8 @@ public:
|
||||||
void setComponent(OSType uSubType, OSType uManufacturer);
|
void setComponent(OSType uSubType, OSType uManufacturer);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void send_event(uint32_t b, uint32_t sample_offset);
|
virtual void send_event(uint32_t b);
|
||||||
virtual void render_512(float * out);
|
virtual void render(float * out, unsigned long count);
|
||||||
|
|
||||||
virtual void shutdown();
|
virtual void shutdown();
|
||||||
virtual bool startup();
|
virtual bool startup();
|
||||||
|
|
|
@ -37,7 +37,7 @@ AUPlayer::~AUPlayer()
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AUPlayer::send_event(uint32_t b, uint32_t sample_offset)
|
void AUPlayer::send_event(uint32_t b)
|
||||||
{
|
{
|
||||||
#ifdef AUPLAYERVIEW
|
#ifdef AUPLAYERVIEW
|
||||||
int _port = -1;
|
int _port = -1;
|
||||||
|
@ -53,7 +53,7 @@ void AUPlayer::send_event(uint32_t b, uint32_t sample_offset)
|
||||||
#ifdef AUPLAYERVIEW
|
#ifdef AUPLAYERVIEW
|
||||||
_port = (int)port;
|
_port = (int)port;
|
||||||
#endif
|
#endif
|
||||||
MusicDeviceMIDIEvent(samplerUnit[port], event[0], event[1], event[2], sample_offset);
|
MusicDeviceMIDIEvent(samplerUnit[port], event[0], event[1], event[2], 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -83,35 +83,42 @@ void AUPlayer::send_event(uint32_t b, uint32_t sample_offset)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AUPlayer::render_512(float * out)
|
void AUPlayer::render(float * out, unsigned long count)
|
||||||
{
|
{
|
||||||
float *ptrL, *ptrR;
|
float *ptrL, *ptrR;
|
||||||
memset(out, 0, 512 * sizeof(float) * 2);
|
memset(out, 0, count * sizeof(float) * 2);
|
||||||
for (unsigned long i = 0; i < 3; ++i)
|
while (count)
|
||||||
{
|
{
|
||||||
AudioUnitRenderActionFlags ioActionFlags = 0;
|
UInt32 numberFrames = count > 512 ? 512 : count;
|
||||||
UInt32 numberFrames = 512;
|
|
||||||
|
for (unsigned long i = 0; i < 3; ++i)
|
||||||
for (unsigned long j = 0; j < 2; j++)
|
|
||||||
{
|
{
|
||||||
bufferList->mBuffers[j].mNumberChannels = 1;
|
AudioUnitRenderActionFlags ioActionFlags = 0;
|
||||||
bufferList->mBuffers[j].mDataByteSize = (UInt32) (512 * sizeof(float));
|
|
||||||
bufferList->mBuffers[j].mData = audioBuffer + j * 512;
|
|
||||||
memset(bufferList->mBuffers[j].mData, 0, 512 * sizeof(float));
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioUnitRender(samplerUnit[i], &ioActionFlags, &mTimeStamp, 0, numberFrames, bufferList);
|
for (unsigned long j = 0; j < 2; j++)
|
||||||
|
{
|
||||||
|
bufferList->mBuffers[j].mNumberChannels = 1;
|
||||||
|
bufferList->mBuffers[j].mDataByteSize = (UInt32) (numberFrames * sizeof(float));
|
||||||
|
bufferList->mBuffers[j].mData = audioBuffer + j * 512;
|
||||||
|
memset(bufferList->mBuffers[j].mData, 0, numberFrames * sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
ptrL = (float *) bufferList->mBuffers[0].mData;
|
AudioUnitRender(samplerUnit[i], &ioActionFlags, &mTimeStamp, 0, numberFrames, bufferList);
|
||||||
ptrR = (float *) bufferList->mBuffers[1].mData;
|
|
||||||
for (unsigned long j = 0; j < 512; ++j)
|
ptrL = (float *) bufferList->mBuffers[0].mData;
|
||||||
{
|
ptrR = (float *) bufferList->mBuffers[1].mData;
|
||||||
out[j * 2 + 0] += ptrL[j];
|
for (unsigned long j = 0; j < numberFrames; ++j)
|
||||||
out[j * 2 + 1] += ptrR[j];
|
{
|
||||||
|
out[j * 2 + 0] += ptrL[j];
|
||||||
|
out[j * 2 + 1] += ptrR[j];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out += numberFrames * 2;
|
||||||
|
count -= numberFrames;
|
||||||
|
|
||||||
|
mTimeStamp.mSampleTime += (double)numberFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTimeStamp.mSampleTime += 512.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AUPlayer::shutdown()
|
void AUPlayer::shutdown()
|
||||||
|
|
|
@ -248,11 +248,6 @@ void BMPlayer::send_event(uint32_t b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BMPlayer::send_event(uint32_t b, uint32_t sample_offset)
|
|
||||||
{
|
|
||||||
_eventQueue.push_back(BASS_event(b, sample_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BMPlayer::render(float * out, unsigned long count)
|
void BMPlayer::render(float * out, unsigned long count)
|
||||||
{
|
{
|
||||||
float buffer[1024];
|
float buffer[1024];
|
||||||
|
@ -275,44 +270,6 @@ void BMPlayer::render(float * out, unsigned long count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BMPlayer::render_512(float *out)
|
|
||||||
{
|
|
||||||
unsigned long queue_index = 0;
|
|
||||||
unsigned long queue_count = _eventQueue.size();
|
|
||||||
uint32_t current = 0;
|
|
||||||
uint32_t next = 512;
|
|
||||||
if (queue_count)
|
|
||||||
next = _eventQueue[0].sample_offset;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (next > 512)
|
|
||||||
next = 512;
|
|
||||||
|
|
||||||
if (next > current)
|
|
||||||
render(out + current * 2, next - current);
|
|
||||||
|
|
||||||
current = next;
|
|
||||||
|
|
||||||
while (queue_index < queue_count && _eventQueue[queue_index].sample_offset <= next)
|
|
||||||
{
|
|
||||||
send_event(_eventQueue[queue_index].b);
|
|
||||||
queue_index++;
|
|
||||||
}
|
|
||||||
if (queue_index < queue_count)
|
|
||||||
next = _eventQueue[queue_index].sample_offset;
|
|
||||||
else
|
|
||||||
next = 512;
|
|
||||||
} while (current < 512);
|
|
||||||
|
|
||||||
if (queue_index < queue_count)
|
|
||||||
{
|
|
||||||
memmove(&_eventQueue[0], &_eventQueue[queue_index], sizeof(BASS_event) * (queue_count - queue_index));
|
|
||||||
_eventQueue.resize(queue_count - queue_index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_eventQueue.resize(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BMPlayer::setSoundFont( const char * in )
|
void BMPlayer::setSoundFont( const char * in )
|
||||||
{
|
{
|
||||||
sSoundFontName = in;
|
sSoundFontName = in;
|
||||||
|
|
|
@ -20,11 +20,8 @@ public:
|
||||||
void setSincInterpolation(bool enable = true);
|
void setSincInterpolation(bool enable = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void send_event(uint32_t b);
|
virtual void send_event(uint32_t b);
|
||||||
void render(float * out, unsigned long count);
|
virtual void render(float * out, unsigned long count);
|
||||||
|
|
||||||
virtual void send_event(uint32_t b, uint32_t sample_offset);
|
|
||||||
virtual void render_512(float * out);
|
|
||||||
|
|
||||||
virtual void shutdown();
|
virtual void shutdown();
|
||||||
virtual bool startup();
|
virtual bool startup();
|
||||||
|
@ -37,15 +34,6 @@ private:
|
||||||
std::string sSoundFontName;
|
std::string sSoundFontName;
|
||||||
std::string sFileSoundFontName;
|
std::string sFileSoundFontName;
|
||||||
|
|
||||||
typedef struct BASS_event
|
|
||||||
{
|
|
||||||
uint32_t b;
|
|
||||||
uint32_t sample_offset;
|
|
||||||
BASS_event() : b(0), sample_offset(0) { }
|
|
||||||
BASS_event(uint32_t _b, uint32_t _sample_offset) : b(_b), sample_offset(_sample_offset) { }
|
|
||||||
} BASS_event;
|
|
||||||
std::vector<BASS_event> _eventQueue;
|
|
||||||
|
|
||||||
HSTREAM _stream[3];
|
HSTREAM _stream[3];
|
||||||
|
|
||||||
bool bSincInterpolation;
|
bool bSincInterpolation;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#import "AUPlayer.h"
|
#import "AUPlayer.h"
|
||||||
#import "BMPlayer.h"
|
#import "BMPlayer.h"
|
||||||
|
#import "SCPlayer.h"
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
|
@ -147,19 +148,49 @@ static OSType getOSType(const char * in_)
|
||||||
|
|
||||||
componentSubType = getOSType(cplugin);
|
componentSubType = getOSType(cplugin);
|
||||||
componentManufacturer = getOSType(cplugin + 4);
|
componentManufacturer = getOSType(cplugin + 4);
|
||||||
|
|
||||||
auplayer = new AUPlayer;
|
|
||||||
|
|
||||||
auplayer->setComponent(componentSubType, componentManufacturer);
|
if (componentManufacturer == 'rolD' && componentSubType == 'Sc55')
|
||||||
auplayer->setSampleRate( 44100 );
|
|
||||||
|
|
||||||
if ( [soundFontPath length] )
|
|
||||||
{
|
{
|
||||||
auplayer->setSoundFont( [soundFontPath UTF8String] );
|
SCPlayer * scplayer = new SCPlayer;
|
||||||
soundFontsAssigned = YES;
|
|
||||||
|
SCPlayer::sc_mode mode = SCPlayer::sc_sc55;
|
||||||
|
NSString * flavor = [[NSUserDefaults standardUserDefaults] stringForKey:@"midi.flavor"];
|
||||||
|
if ([flavor isEqualToString:@"gm"])
|
||||||
|
mode = SCPlayer::sc_gm;
|
||||||
|
else if ([flavor isEqualToString:@"gm2"])
|
||||||
|
mode = SCPlayer::sc_gm2;
|
||||||
|
else if ([flavor isEqualToString:@"sc55"])
|
||||||
|
mode = SCPlayer::sc_sc55;
|
||||||
|
else if ([flavor isEqualToString:@"sc88"])
|
||||||
|
mode = SCPlayer::sc_sc88;
|
||||||
|
else if ([flavor isEqualToString:@"sc88pro"])
|
||||||
|
mode = SCPlayer::sc_sc88pro;
|
||||||
|
else if ([flavor isEqualToString:@"sc8850"])
|
||||||
|
mode = SCPlayer::sc_sc8850;
|
||||||
|
else if ([flavor isEqualToString:@"xg"])
|
||||||
|
mode = SCPlayer::sc_xg;
|
||||||
|
|
||||||
|
scplayer->set_sccore_path("/Library/Audio/Plug-Ins/Components/SOUND Canvas VA.component/Contents/Resources/SCCore00.dylib");
|
||||||
|
scplayer->set_mode( mode );
|
||||||
|
scplayer->setSampleRate( 44100 );
|
||||||
|
|
||||||
|
player = scplayer;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auplayer = new AUPlayer;
|
||||||
|
|
||||||
player = auplayer;
|
auplayer->setComponent(componentSubType, componentManufacturer);
|
||||||
|
auplayer->setSampleRate( 44100 );
|
||||||
|
|
||||||
|
if ( [soundFontPath length] )
|
||||||
|
{
|
||||||
|
auplayer->setSoundFont( [soundFontPath UTF8String] );
|
||||||
|
soundFontsAssigned = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
player = auplayer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int loop_mode = framesFade ? MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force : 0;
|
unsigned int loop_mode = framesFade ? MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force : 0;
|
||||||
|
|
|
@ -9,7 +9,6 @@ MIDIPlayer::MIDIPlayer()
|
||||||
uTimeCurrent = 0;
|
uTimeCurrent = 0;
|
||||||
uTimeEnd = 0;
|
uTimeEnd = 0;
|
||||||
uTimeLoopStart = 0;
|
uTimeLoopStart = 0;
|
||||||
uSamplesInBuffer = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MIDIPlayer::setSampleRate(unsigned long rate)
|
void MIDIPlayer::setSampleRate(unsigned long rate)
|
||||||
|
@ -159,52 +158,26 @@ unsigned long MIDIPlayer::Play(float * out, unsigned long count)
|
||||||
midi_stream_event * me = &mStream[uStreamPosition];
|
midi_stream_event * me = &mStream[uStreamPosition];
|
||||||
|
|
||||||
unsigned long samples_todo = me->m_timestamp - uTimeCurrent;
|
unsigned long samples_todo = me->m_timestamp - uTimeCurrent;
|
||||||
while ( samples_todo >= 512 )
|
if ( samples_todo )
|
||||||
{
|
{
|
||||||
if ( samples_todo > count - done )
|
if ( samples_todo > count - done )
|
||||||
{
|
{
|
||||||
uSamplesRemaining = samples_todo - ( count - done );
|
uSamplesRemaining = samples_todo - ( count - done );
|
||||||
samples_todo = count - done;
|
samples_todo = count - done;
|
||||||
}
|
}
|
||||||
if ( uSamplesInBuffer )
|
render( out + done * 2, samples_todo );
|
||||||
{
|
done += samples_todo;
|
||||||
if ( samples_todo >= uSamplesInBuffer )
|
|
||||||
{
|
|
||||||
unsigned int localSamplesInBuffer = uSamplesInBuffer;
|
|
||||||
render( out + done * 2, localSamplesInBuffer );
|
|
||||||
done += localSamplesInBuffer;
|
|
||||||
uTimeCurrent += localSamplesInBuffer;
|
|
||||||
samples_todo -= localSamplesInBuffer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
render( out + done * 2, (uint32_t) samples_todo );
|
|
||||||
done += samples_todo;
|
|
||||||
uTimeCurrent += samples_todo;
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( samples_todo >= 512 )
|
|
||||||
{
|
|
||||||
render_512( out + done * 2 );
|
|
||||||
done += 512;
|
|
||||||
uTimeCurrent += 512;
|
|
||||||
samples_todo -= 512;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
render( out + done * 2, (uint32_t) samples_todo );
|
|
||||||
done += samples_todo;
|
|
||||||
uTimeCurrent += samples_todo;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( uSamplesRemaining )
|
if ( uSamplesRemaining )
|
||||||
{
|
{
|
||||||
|
uTimeCurrent = me->m_timestamp;
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
send_event( me->m_event, (uint32_t) samples_todo );
|
send_event( me->m_event );
|
||||||
|
|
||||||
|
uTimeCurrent = me->m_timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +188,7 @@ unsigned long MIDIPlayer::Play(float * out, unsigned long count)
|
||||||
else samples_todo = uTimeEnd;
|
else samples_todo = uTimeEnd;
|
||||||
samples_todo -= uTimeCurrent;
|
samples_todo -= uTimeCurrent;
|
||||||
if ( samples_todo > count - done ) samples_todo = count - done;
|
if ( samples_todo > count - done ) samples_todo = count - done;
|
||||||
render( out + done * 2, (uint32_t) samples_todo );
|
render( out + done * 2, samples_todo );
|
||||||
done += samples_todo;
|
done += samples_todo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +200,7 @@ unsigned long MIDIPlayer::Play(float * out, unsigned long count)
|
||||||
{
|
{
|
||||||
for (; uStreamPosition < mStream.size(); uStreamPosition++)
|
for (; uStreamPosition < mStream.size(); uStreamPosition++)
|
||||||
{
|
{
|
||||||
send_event( mStream[ uStreamPosition ].m_event, 0 );
|
send_event( mStream[ uStreamPosition ].m_event );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,8 +247,6 @@ void MIDIPlayer::Seek(unsigned long sample)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!startup()) return;
|
if (!startup()) return;
|
||||||
|
|
||||||
uSamplesInBuffer = 0;
|
|
||||||
|
|
||||||
uTimeCurrent = sample;
|
uTimeCurrent = sample;
|
||||||
|
|
||||||
|
@ -324,45 +295,7 @@ void MIDIPlayer::Seek(unsigned long sample)
|
||||||
for (i = 0; i < stream_start; i++)
|
for (i = 0; i < stream_start; i++)
|
||||||
{
|
{
|
||||||
if (me[i].m_event)
|
if (me[i].m_event)
|
||||||
send_event(me[i].m_event, 0);
|
send_event(me[i].m_event);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MIDIPlayer::render(float * out, uint32_t count)
|
|
||||||
{
|
|
||||||
if (uSamplesInBuffer)
|
|
||||||
{
|
|
||||||
if (uSamplesInBuffer >= count)
|
|
||||||
{
|
|
||||||
memcpy(out, fSampleBuffer, sizeof(float) * 2 * count);
|
|
||||||
uSamplesInBuffer -= count;
|
|
||||||
memmove(fSampleBuffer, fSampleBuffer + count * 2, sizeof(float) * 2 * uSamplesInBuffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(out, fSampleBuffer, sizeof(float) * 2 * uSamplesInBuffer);
|
|
||||||
out += uSamplesInBuffer * 2;
|
|
||||||
count -= uSamplesInBuffer;
|
|
||||||
uSamplesInBuffer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (count > 0)
|
|
||||||
{
|
|
||||||
if (count >= 512)
|
|
||||||
{
|
|
||||||
render_512(out);
|
|
||||||
out += 512 * 2;
|
|
||||||
count -= 512;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
render_512(fSampleBuffer);
|
|
||||||
memcpy(out, fSampleBuffer, sizeof(float) * 2 * count);
|
|
||||||
uSamplesInBuffer = 512 - count;
|
|
||||||
memmove(fSampleBuffer, fSampleBuffer + count * 2, sizeof(float) * 2 * uSamplesInBuffer);
|
|
||||||
count = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,16 +20,15 @@ public:
|
||||||
|
|
||||||
// setup
|
// setup
|
||||||
void setSampleRate(unsigned long rate);
|
void setSampleRate(unsigned long rate);
|
||||||
|
void SetLoopMode(unsigned int mode);
|
||||||
|
|
||||||
bool Load(const midi_container & midi_file, unsigned subsong, unsigned loop_mode, unsigned clean_flags);
|
bool Load(const midi_container & midi_file, unsigned subsong, unsigned loop_mode, unsigned clean_flags);
|
||||||
unsigned long Play(float * out, unsigned long count);
|
unsigned long Play(float * out, unsigned long count);
|
||||||
void Seek(unsigned long sample);
|
void Seek(unsigned long sample);
|
||||||
|
|
||||||
void SetLoopMode(unsigned mode);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void send_event(uint32_t b, uint32_t sample_offset) {}
|
virtual void send_event(uint32_t b) {}
|
||||||
virtual void render_512(float * out) {}
|
virtual void render(float * out, unsigned long count) {}
|
||||||
|
|
||||||
virtual void shutdown() {};
|
virtual void shutdown() {};
|
||||||
virtual bool startup() {return false;}
|
virtual bool startup() {return false;}
|
||||||
|
@ -38,8 +37,6 @@ protected:
|
||||||
system_exclusive_table mSysexMap;
|
system_exclusive_table mSysexMap;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void render(float * out, uint32_t count);
|
|
||||||
|
|
||||||
unsigned long uSamplesRemaining;
|
unsigned long uSamplesRemaining;
|
||||||
|
|
||||||
unsigned uLoopMode;
|
unsigned uLoopMode;
|
||||||
|
@ -53,9 +50,6 @@ private:
|
||||||
unsigned long uStreamLoopStart;
|
unsigned long uStreamLoopStart;
|
||||||
unsigned long uTimeLoopStart;
|
unsigned long uTimeLoopStart;
|
||||||
unsigned long uStreamEnd;
|
unsigned long uStreamEnd;
|
||||||
|
|
||||||
unsigned int uSamplesInBuffer;
|
|
||||||
float fSampleBuffer[512 * 2];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include "SCCore.h"
|
||||||
|
|
||||||
|
SCCore::SCCore()
|
||||||
|
{
|
||||||
|
duped = false;
|
||||||
|
path = 0;
|
||||||
|
|
||||||
|
handle = 0;
|
||||||
|
|
||||||
|
TG_initialize = 0;
|
||||||
|
//TG_terminate = 0;
|
||||||
|
TG_activate = 0;
|
||||||
|
TG_deactivate = 0;
|
||||||
|
TG_setSampleRate = 0;
|
||||||
|
TG_setMaxBlockSize = 0;
|
||||||
|
TG_flushMidi = 0;
|
||||||
|
TG_setInterruptThreadIdAtThisTime = 0;
|
||||||
|
// TG_PMidiIn = 0;
|
||||||
|
TG_ShortMidiIn = 0;
|
||||||
|
TG_LongMidiIn = 0;
|
||||||
|
// TG_isFatalError = 0;
|
||||||
|
// TG_getErrorStrings = 0;
|
||||||
|
TG_XPgetCurTotalRunningVoices = 0;
|
||||||
|
// TG_XPsetSystemConfig = 0;
|
||||||
|
// TG_XPgetCurSystemConfig = 0;
|
||||||
|
TG_Process = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCCore::~SCCore()
|
||||||
|
{
|
||||||
|
Unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCCore::Unload()
|
||||||
|
{
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
dlclose(handle);
|
||||||
|
handle = 0;
|
||||||
|
}
|
||||||
|
if (duped && path)
|
||||||
|
{
|
||||||
|
unlink(path);
|
||||||
|
duped = false;
|
||||||
|
}
|
||||||
|
if (path)
|
||||||
|
{
|
||||||
|
free(path);
|
||||||
|
path = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char name_template[] = "/tmp/SCCore.dylib.XXXXXXXX";
|
||||||
|
|
||||||
|
bool SCCore::Load(const char * _path, bool dupe)
|
||||||
|
{
|
||||||
|
uintptr_t size = 0;
|
||||||
|
|
||||||
|
if (dupe)
|
||||||
|
{
|
||||||
|
path = (char *) malloc(strlen(name_template) + 1);
|
||||||
|
strcpy(path, name_template);
|
||||||
|
mktemp(path);
|
||||||
|
|
||||||
|
const char * uniq = path + strlen(path) - 8;
|
||||||
|
|
||||||
|
FILE * f = fopen(_path, "rb");
|
||||||
|
if (!f) return false;
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
size_t fs = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
size = fs;
|
||||||
|
|
||||||
|
unsigned char * buffer = (unsigned char *) malloc(fs);
|
||||||
|
if (!fs)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(buffer, 1, fs, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fs - 14; ++i)
|
||||||
|
{
|
||||||
|
if (memcmp(buffer + i, "SCCore00.dylib", 14) == 0)
|
||||||
|
{
|
||||||
|
memcpy(buffer + i, uniq, 8);
|
||||||
|
i += 13;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
duped = true;
|
||||||
|
|
||||||
|
f = fopen(path, "wb");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
free(buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(buffer, 1, fs, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path = (char *) malloc(strlen(_path) + 1);
|
||||||
|
strcpy(path, _path);
|
||||||
|
|
||||||
|
FILE * f = fopen(path, "rb");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
size = ftell(f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
*(void**)&TG_initialize = dlsym(handle, "TG_initialize");
|
||||||
|
//*(void**)&TG_terminate = dlsym(handle, "TG_terminate");
|
||||||
|
*(void**)&TG_activate = dlsym(handle, "TG_activate");
|
||||||
|
*(void**)&TG_deactivate = dlsym(handle, "TG_deactivate");
|
||||||
|
*(void**)&TG_setSampleRate = dlsym(handle, "TG_setSampleRate");
|
||||||
|
*(void**)&TG_setMaxBlockSize = dlsym(handle, "TG_setMaxBlockSize");
|
||||||
|
*(void**)&TG_flushMidi = dlsym(handle, "TG_flushMidi");
|
||||||
|
*(void**)&TG_setInterruptThreadIdAtThisTime = dlsym(handle, "TG_setInterruptThreadIdAtThisTime");
|
||||||
|
//*(void**)&TG_PMidiIn = dlsym(handle, "TG_PMidiIn");
|
||||||
|
*(void**)&TG_ShortMidiIn = dlsym(handle, "TG_ShortMidiIn");
|
||||||
|
*(void**)&TG_LongMidiIn = dlsym(handle, "TG_LongMidiIn");
|
||||||
|
//*(void**)&TG_isFatalError = dlsym(handle, "TG_isFatalError");
|
||||||
|
//*(void**)&TG_getErrorStrings = dlsym(handle, "TG_getErrorStrings");
|
||||||
|
*(void**)&TG_XPgetCurTotalRunningVoices = dlsym(handle, "TG_XPgetCurTotalRunningVoices");
|
||||||
|
//*(void**)&TG_XPsetSystemConfig = dlsym(handle, "TG_XPsetSystemConfig");
|
||||||
|
//*(void**)&TG_XPgetCurSystemConfig = dlsym(handle, "TG_XPgetCurSystemConfig");
|
||||||
|
*(void**)&TG_Process = dlsym(handle, "TG_Process");
|
||||||
|
|
||||||
|
if (TG_initialize && /*TG_terminate &&*/ TG_activate && TG_deactivate &&
|
||||||
|
TG_setSampleRate && TG_setMaxBlockSize && TG_flushMidi &&
|
||||||
|
TG_setInterruptThreadIdAtThisTime && /*TG_PMidiIn &&*/
|
||||||
|
TG_ShortMidiIn && TG_LongMidiIn && /*TG_isFatalError &&
|
||||||
|
TG_getErrorStrings &&*/ TG_XPgetCurTotalRunningVoices &&
|
||||||
|
/*TG_XPsetSystemConfig && TG_XPgetCurSystemConfig &&*/
|
||||||
|
TG_Process)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TG_initialize = 0;
|
||||||
|
//TG_terminate = 0;
|
||||||
|
TG_activate = 0;
|
||||||
|
TG_deactivate = 0;
|
||||||
|
TG_setSampleRate = 0;
|
||||||
|
TG_setMaxBlockSize = 0;
|
||||||
|
TG_flushMidi = 0;
|
||||||
|
TG_setInterruptThreadIdAtThisTime = 0;
|
||||||
|
// TG_PMidiIn = 0;
|
||||||
|
TG_ShortMidiIn = 0;
|
||||||
|
TG_LongMidiIn = 0;
|
||||||
|
// TG_isFatalError = 0;
|
||||||
|
// TG_getErrorStrings = 0;
|
||||||
|
TG_XPgetCurTotalRunningVoices = 0;
|
||||||
|
// TG_XPsetSystemConfig = 0;
|
||||||
|
// TG_XPgetCurSystemConfig = 0;
|
||||||
|
TG_Process = 0;
|
||||||
|
|
||||||
|
dlclose(handle);
|
||||||
|
handle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef _SCCore_h_
|
||||||
|
#define _SCCore_h_
|
||||||
|
|
||||||
|
// Static single instance - duplicate library to temp path for unique instance
|
||||||
|
|
||||||
|
class SCCore
|
||||||
|
{
|
||||||
|
bool duped;
|
||||||
|
char * path;
|
||||||
|
void * handle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int (* TG_initialize)(int i); // i = 0, returns negative on failure
|
||||||
|
|
||||||
|
//void (* TG_terminate)(); // Unused
|
||||||
|
|
||||||
|
void (* TG_activate)(float sampleRate, int blockSize);
|
||||||
|
|
||||||
|
void (* TG_deactivate)(); // Unused - hopefully cleans up
|
||||||
|
|
||||||
|
void (*TG_setSampleRate)(float sampleRate);
|
||||||
|
|
||||||
|
void (*TG_setMaxBlockSize)(unsigned int blockSize);
|
||||||
|
|
||||||
|
void (*TG_flushMidi)(); // Called after applying presets
|
||||||
|
|
||||||
|
void (*TG_setInterruptThreadIdAtThisTime)();
|
||||||
|
|
||||||
|
//void (*TG_PMidiIn)(MpPacket *, int count); // Unknown
|
||||||
|
|
||||||
|
void (*TG_ShortMidiIn)(unsigned int eventCode, unsigned int deltaFrames);
|
||||||
|
|
||||||
|
void (*TG_LongMidiIn)(const unsigned char * sysEx, unsigned int deltaFrames);
|
||||||
|
|
||||||
|
//void (*TG_isFatalError)(int errCode); // Unused
|
||||||
|
|
||||||
|
//void (*TG_getErrorStrings)(int errCode); // Unused
|
||||||
|
|
||||||
|
unsigned int (*TG_XPgetCurTotalRunningVoices)(); // Unused
|
||||||
|
|
||||||
|
//void (*TG_XPsetSystemConfig)();
|
||||||
|
|
||||||
|
//void (*TG_XPgetCurSystemConfig)();
|
||||||
|
|
||||||
|
void (*TG_Process)(float * left, float * right, unsigned int count);
|
||||||
|
|
||||||
|
SCCore();
|
||||||
|
~SCCore();
|
||||||
|
|
||||||
|
bool Load(const char * path, bool dupe);
|
||||||
|
void Unload();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,297 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "SCPlayer.h"
|
||||||
|
|
||||||
|
// YAY! OS X doesn't unload dylibs on dlclose, so we cache up to two sets of instances here
|
||||||
|
|
||||||
|
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static const unsigned int g_max_instances = 2;
|
||||||
|
static std::vector<unsigned int> g_instances_open;
|
||||||
|
static SCCore g_sampler[3 * g_max_instances];
|
||||||
|
|
||||||
|
SCPlayer::SCPlayer() : MIDIPlayer(), initialized(false), mode(sc_default), sccore_path(0)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&g_lock);
|
||||||
|
while (g_instances_open.size() >= g_max_instances)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&g_lock);
|
||||||
|
usleep(10000);
|
||||||
|
pthread_mutex_lock(&g_lock);
|
||||||
|
}
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < g_max_instances; ++i)
|
||||||
|
{
|
||||||
|
if (std::find(g_instances_open.begin(), g_instances_open.end(), i) == g_instances_open.end())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_instances_open.push_back(i);
|
||||||
|
instance_id = i;
|
||||||
|
sampler = &g_sampler[i * 3];
|
||||||
|
pthread_mutex_unlock(&g_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCPlayer::~SCPlayer()
|
||||||
|
{
|
||||||
|
shutdown();
|
||||||
|
if (sccore_path)
|
||||||
|
free(sccore_path);
|
||||||
|
if (sampler)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&g_lock);
|
||||||
|
auto it = std::find(g_instances_open.begin(), g_instances_open.end(), instance_id);
|
||||||
|
it = g_instances_open.erase(it);
|
||||||
|
pthread_mutex_unlock(&g_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t syx_reset_gm[] = { 0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7 };
|
||||||
|
static const uint8_t syx_reset_gm2[] = { 0xF0, 0x7E, 0x7F, 0x09, 0x03, 0xF7 };
|
||||||
|
static const uint8_t syx_reset_gs[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7 };
|
||||||
|
static const uint8_t syx_reset_xg[] = { 0xF0, 0x43, 0x10, 0x4C, 0x00, 0x00, 0x7E, 0x00, 0xF7 };
|
||||||
|
|
||||||
|
static const uint8_t syx_gs_limit_bank_lsb[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x41, 0x00, 0x03, 0x00, 0xF7 };
|
||||||
|
|
||||||
|
static bool syx_equal(const uint8_t * a, const uint8_t * b)
|
||||||
|
{
|
||||||
|
while (*a != 0xF7 && *b != 0xF7 && *a == *b)
|
||||||
|
{
|
||||||
|
a++; b++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *a == *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool syx_is_reset(const uint8_t * data)
|
||||||
|
{
|
||||||
|
return syx_equal(data, syx_reset_gm) || syx_equal(data, syx_reset_gm2) || syx_equal(data, syx_reset_gs) || syx_equal(data, syx_reset_xg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::send_sysex(uint32_t port, const uint8_t * data)
|
||||||
|
{
|
||||||
|
sampler[port].TG_LongMidiIn( data, 0 );
|
||||||
|
if (syx_is_reset(data))
|
||||||
|
{
|
||||||
|
reset(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::send_gs(uint32_t port, uint8_t * data)
|
||||||
|
{
|
||||||
|
unsigned long i;
|
||||||
|
unsigned char checksum = 0;
|
||||||
|
for (i = 5; data[i+1] != 0xF7; ++i)
|
||||||
|
checksum += data[i];
|
||||||
|
checksum = (128 - checksum) & 127;
|
||||||
|
data[i] = checksum;
|
||||||
|
sampler[port].TG_LongMidiIn( data, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::reset_sc(uint32_t port)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
uint8_t message[11];
|
||||||
|
|
||||||
|
memcpy(message, syx_gs_limit_bank_lsb, 11);
|
||||||
|
|
||||||
|
message[7] = 1;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
case sc_sc55:
|
||||||
|
message[8] = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_sc88:
|
||||||
|
message[8] = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_sc88pro:
|
||||||
|
message[8] = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_sc8850:
|
||||||
|
message[8] = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0x41; i <= 0x49; ++i)
|
||||||
|
{
|
||||||
|
message[6] = i;
|
||||||
|
send_gs(port, message);
|
||||||
|
}
|
||||||
|
message[6] = 0x40;
|
||||||
|
send_gs(port, message);
|
||||||
|
for (i = 0x4A; i <= 0x4F; ++i)
|
||||||
|
{
|
||||||
|
message[6] = i;
|
||||||
|
send_gs(port, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::reset(uint32_t port)
|
||||||
|
{
|
||||||
|
if (initialized)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case sc_gm:
|
||||||
|
sampler[port].TG_LongMidiIn( syx_reset_gm, 0 );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_gm2:
|
||||||
|
sampler[port].TG_LongMidiIn( syx_reset_gm2, 0 );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_sc55:
|
||||||
|
case sc_sc88:
|
||||||
|
case sc_sc88pro:
|
||||||
|
case sc_sc8850:
|
||||||
|
reset_sc(port);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sc_xg:
|
||||||
|
sampler[port].TG_LongMidiIn( syx_reset_xg, 0 );
|
||||||
|
sampler[port].TG_ShortMidiIn( 0x7F00B9, 0 ); // fix drum channel
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::set_mode(sc_mode m)
|
||||||
|
{
|
||||||
|
mode = m;
|
||||||
|
reset(0);
|
||||||
|
reset(1);
|
||||||
|
reset(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::set_sccore_path(const char *path)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
if (sccore_path) free(sccore_path);
|
||||||
|
len = strlen(path);
|
||||||
|
sccore_path = (char *) malloc(len + 1);
|
||||||
|
if (sccore_path)
|
||||||
|
memcpy(sccore_path, path, len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::send_event(uint32_t b)
|
||||||
|
{
|
||||||
|
if (!(b & 0x80000000))
|
||||||
|
{
|
||||||
|
unsigned port = (b >> 24) & 0x7F;
|
||||||
|
if ( port > 2 ) port = 2;
|
||||||
|
sampler[port].TG_ShortMidiIn(b, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t n = b & 0xffffff;
|
||||||
|
const uint8_t * data;
|
||||||
|
std::size_t size, port;
|
||||||
|
mSysexMap.get_entry( n, data, size, port );
|
||||||
|
if ( port > 2 ) port = 2;
|
||||||
|
send_sysex( (uint32_t) port, data );
|
||||||
|
if ( port == 0 )
|
||||||
|
{
|
||||||
|
send_sysex( 1, data );
|
||||||
|
send_sysex( 2, data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::render(float * out, unsigned long count)
|
||||||
|
{
|
||||||
|
memset(out, 0, count * sizeof(float) * 2);
|
||||||
|
while (count)
|
||||||
|
{
|
||||||
|
float buffer[2][4096];
|
||||||
|
unsigned long todo = count > 4096 ? 4096 : count;
|
||||||
|
for (unsigned long i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
memset(buffer[0], 0, todo * sizeof(float));
|
||||||
|
memset(buffer[1], 0, todo * sizeof(float));
|
||||||
|
|
||||||
|
sampler[i].TG_setInterruptThreadIdAtThisTime();
|
||||||
|
sampler[i].TG_Process(buffer[0], buffer[1], (unsigned int) todo);
|
||||||
|
|
||||||
|
for (unsigned long j = 0; j < todo; ++j)
|
||||||
|
{
|
||||||
|
out[j * 2 + 0] += buffer[0][j];
|
||||||
|
out[j * 2 + 1] += buffer[1][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out += todo * 2;
|
||||||
|
count -= todo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCPlayer::shutdown()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (sampler[i].TG_deactivate)
|
||||||
|
{
|
||||||
|
sampler[i].TG_flushMidi();
|
||||||
|
sampler[i].TG_deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SCPlayer::startup()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (initialized) return true;
|
||||||
|
|
||||||
|
if (!sccore_path) return false;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (!sampler[i].TG_initialize)
|
||||||
|
{
|
||||||
|
if (!sampler[i].Load(sccore_path, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (sampler[i].TG_initialize(0) < 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sampler[i].TG_activate(44100.0, 1024);
|
||||||
|
sampler[i].TG_setMaxBlockSize(256);
|
||||||
|
sampler[i].TG_setSampleRate((float)uSampleRate);
|
||||||
|
sampler[i].TG_setSampleRate((float)uSampleRate);
|
||||||
|
sampler[i].TG_setMaxBlockSize(4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
reset(i);
|
||||||
|
sampler[i].TG_flushMidi();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int SCPlayer::get_playing_note_count()
|
||||||
|
{
|
||||||
|
unsigned int total = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!initialized)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
total += sampler[i].TG_XPgetCurTotalRunningVoices();
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef __SCPlayer_h__
|
||||||
|
#define __SCPlayer_h__
|
||||||
|
|
||||||
|
#include "MIDIPlayer.h"
|
||||||
|
|
||||||
|
#include "SCCore.h"
|
||||||
|
|
||||||
|
class SCPlayer : public MIDIPlayer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// zero variables
|
||||||
|
SCPlayer();
|
||||||
|
|
||||||
|
// close, unload
|
||||||
|
virtual ~SCPlayer();
|
||||||
|
|
||||||
|
unsigned int get_playing_note_count();
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
sc_gm = 0,
|
||||||
|
sc_gm2,
|
||||||
|
sc_sc55,
|
||||||
|
sc_sc88,
|
||||||
|
sc_sc88pro,
|
||||||
|
sc_sc8850,
|
||||||
|
sc_xg,
|
||||||
|
sc_default = sc_sc55
|
||||||
|
}
|
||||||
|
sc_mode;
|
||||||
|
|
||||||
|
void set_mode(sc_mode m);
|
||||||
|
|
||||||
|
void set_sccore_path(const char * path);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void send_event(uint32_t b);
|
||||||
|
virtual void render(float * out, unsigned long count);
|
||||||
|
|
||||||
|
virtual void shutdown();
|
||||||
|
virtual bool startup();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void send_sysex(uint32_t port, const uint8_t * data);
|
||||||
|
void send_gs(uint32_t port, uint8_t * data);
|
||||||
|
void reset_sc(uint32_t port);
|
||||||
|
|
||||||
|
void reset(uint32_t port);
|
||||||
|
|
||||||
|
unsigned int instance_id;
|
||||||
|
bool initialized;
|
||||||
|
SCCore * sampler;
|
||||||
|
|
||||||
|
sc_mode mode;
|
||||||
|
|
||||||
|
char * sccore_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment version="1050" identifier="macosx"/>
|
<deployment version="1050" identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10116"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="GeneralPreferencesPlugin">
|
<customObject id="-2" userLabel="File's Owner" customClass="GeneralPreferencesPlugin">
|
||||||
|
@ -270,7 +270,8 @@
|
||||||
</customView>
|
</customView>
|
||||||
<customObject id="i5B-ga-Atm" userLabel="MIDIPane" customClass="MIDIPane">
|
<customObject id="i5B-ga-Atm" userLabel="MIDIPane" customClass="MIDIPane">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="view" destination="JXu-ar-J3Y" id="Jal-Yh-Yg3"/>
|
<outlet property="midiFlavorControl" destination="1Yw-25-Gbs" id="6In-S0-YE2"/>
|
||||||
|
<outlet property="view" destination="JXu-ar-J3Y" id="uI3-0O-h4x"/>
|
||||||
</connections>
|
</connections>
|
||||||
</customObject>
|
</customObject>
|
||||||
<arrayController id="59" userLabel="OutputDevices" customClass="OutputsArrayController">
|
<arrayController id="59" userLabel="OutputDevices" customClass="OutputsArrayController">
|
||||||
|
@ -483,11 +484,11 @@
|
||||||
</subviews>
|
</subviews>
|
||||||
</customView>
|
</customView>
|
||||||
<customView id="JXu-ar-J3Y" userLabel="MIDIView">
|
<customView id="JXu-ar-J3Y" userLabel="MIDIView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="500" height="111"/>
|
<rect key="frame" x="0.0" y="0.0" width="500" height="137"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button verticalHuggingPriority="750" id="SBO-WF-DVS" userLabel="Push Button - Select a SoundFont">
|
<button verticalHuggingPriority="750" id="SBO-WF-DVS" userLabel="Push Button - Select a SoundFont">
|
||||||
<rect key="frame" x="14" y="67" width="160" height="32"/>
|
<rect key="frame" x="14" y="93" width="160" height="32"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Select a SoundFont" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="yeL-9c-lFq" userLabel="Button Cell - Select a SoundFont">
|
<buttonCell key="cell" type="push" title="Select a SoundFont" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="yeL-9c-lFq" userLabel="Button Cell - Select a SoundFont">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
@ -498,7 +499,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="FRC-Dh-BS2" userLabel="Text Field - Selected:">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="FRC-Dh-BS2" userLabel="Text Field - Selected:">
|
||||||
<rect key="frame" x="173" y="76" width="61" height="17"/>
|
<rect key="frame" x="173" y="102" width="61" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Selected:" id="KJz-qS-IcO" userLabel="Text Field Cell - Selected">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Selected:" id="KJz-qS-IcO" userLabel="Text Field Cell - Selected">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
|
@ -507,7 +508,7 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="cZr-2d-6cv">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="cZr-2d-6cv">
|
||||||
<rect key="frame" x="236" y="76" width="220" height="17"/>
|
<rect key="frame" x="236" y="102" width="220" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Label" id="ECB-P0-pve">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Label" id="ECB-P0-pve">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
|
@ -524,16 +525,16 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="G86-18-hiK">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="G86-18-hiK">
|
||||||
<rect key="frame" x="32" y="22" width="138" height="17"/>
|
<rect key="frame" x="32" y="48" width="138" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Resampling quality:" id="eX0-PC-iVo">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Resampling Quality:" id="eX0-PC-iVo">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="4uG-vW-B64">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="4uG-vW-B64">
|
||||||
<rect key="frame" x="79" y="49" width="91" height="17"/>
|
<rect key="frame" x="79" y="75" width="91" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="MIDI Plugin:" id="n5F-dq-NZh">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="MIDI Plugin:" id="n5F-dq-NZh">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
|
@ -542,7 +543,7 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<popUpButton verticalHuggingPriority="750" id="8Nj-G4-5ag">
|
<popUpButton verticalHuggingPriority="750" id="8Nj-G4-5ag">
|
||||||
<rect key="frame" x="173" y="44" width="164" height="26"/>
|
<rect key="frame" x="173" y="70" width="164" height="26"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="vaQ-pZ-jXy" id="xcv-1b-kTI">
|
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="vaQ-pZ-jXy" id="xcv-1b-kTI">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
@ -556,15 +557,46 @@
|
||||||
</menu>
|
</menu>
|
||||||
</popUpButtonCell>
|
</popUpButtonCell>
|
||||||
<connections>
|
<connections>
|
||||||
|
<action selector="setMidiPlugin:" target="i5B-ga-Atm" id="8Nt-Z0-LvI"/>
|
||||||
<binding destination="czk-eG-6QG" name="content" keyPath="arrangedObjects" id="Mzg-yr-6mv"/>
|
<binding destination="czk-eG-6QG" name="content" keyPath="arrangedObjects" id="Mzg-yr-6mv"/>
|
||||||
<binding destination="czk-eG-6QG" name="contentObjects" keyPath="arrangedObjects.preference" previousBinding="Mzg-yr-6mv" id="NFp-di-hMf"/>
|
|
||||||
<binding destination="czk-eG-6QG" name="contentValues" keyPath="arrangedObjects.name" previousBinding="NFp-di-hMf" id="6JE-ba-47Z"/>
|
<binding destination="czk-eG-6QG" name="contentValues" keyPath="arrangedObjects.name" previousBinding="NFp-di-hMf" id="6JE-ba-47Z"/>
|
||||||
|
<binding destination="czk-eG-6QG" name="contentObjects" keyPath="arrangedObjects.preference" previousBinding="Mzg-yr-6mv" id="NFp-di-hMf"/>
|
||||||
<binding destination="52" name="selectedObject" keyPath="values.midi.plugin" previousBinding="6JE-ba-47Z" id="n1u-ie-870"/>
|
<binding destination="52" name="selectedObject" keyPath="values.midi.plugin" previousBinding="6JE-ba-47Z" id="n1u-ie-870"/>
|
||||||
</connections>
|
</connections>
|
||||||
</popUpButton>
|
</popUpButton>
|
||||||
<popUpButton verticalHuggingPriority="750" id="E1D-Bo-ZVf">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="K5c-km-7Qa">
|
||||||
|
<rect key="frame" x="50" y="23" width="120" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="MIDI Flavor:" id="FQF-vJ-hBx">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<popUpButton verticalHuggingPriority="750" id="1Yw-25-Gbs">
|
||||||
<rect key="frame" x="173" y="17" width="164" height="26"/>
|
<rect key="frame" x="173" y="17" width="164" height="26"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" enabled="NO" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="XzK-h2-vIT" id="qzt-Ox-taI">
|
||||||
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="menu"/>
|
||||||
|
<menu key="menu" id="q1g-E5-NwQ">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Item 1" state="on" id="XzK-h2-vIT"/>
|
||||||
|
<menuItem title="Item 2" id="nzS-3F-jPX"/>
|
||||||
|
<menuItem title="Item 3" id="jLL-zc-kYf"/>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</popUpButtonCell>
|
||||||
|
<connections>
|
||||||
|
<binding destination="KAn-H1-QH6" name="content" keyPath="arrangedObjects" id="Zvj-Wf-Bum"/>
|
||||||
|
<binding destination="KAn-H1-QH6" name="contentObjects" keyPath="arrangedObjects.preference" previousBinding="Zvj-Wf-Bum" id="WGj-w1-erz"/>
|
||||||
|
<binding destination="KAn-H1-QH6" name="contentValues" keyPath="arrangedObjects.name" previousBinding="WGj-w1-erz" id="Rvq-46-YeR"/>
|
||||||
|
<binding destination="52" name="selectedObject" keyPath="values.midi.flavor" previousBinding="Rvq-46-YeR" id="zC1-3J-frL"/>
|
||||||
|
</connections>
|
||||||
|
</popUpButton>
|
||||||
|
<popUpButton verticalHuggingPriority="750" id="E1D-Bo-ZVf">
|
||||||
|
<rect key="frame" x="173" y="43" width="164" height="26"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="3Gx-cs-3B0" id="5q7-83-7V6">
|
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="3Gx-cs-3B0" id="5q7-83-7V6">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="menu"/>
|
<font key="font" metaFont="menu"/>
|
||||||
|
@ -584,7 +616,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</popUpButton>
|
</popUpButton>
|
||||||
</subviews>
|
</subviews>
|
||||||
<point key="canvasLocation" x="340" y="554.5"/>
|
<point key="canvasLocation" x="340" y="567.5"/>
|
||||||
</customView>
|
</customView>
|
||||||
<arrayController objectClassName="NSDictionary" editable="NO" id="JB6-r9-XpG" userLabel="ResamplerBehavior" customClass="ResamplerBehaviorArrayController">
|
<arrayController objectClassName="NSDictionary" editable="NO" id="JB6-r9-XpG" userLabel="ResamplerBehavior" customClass="ResamplerBehaviorArrayController">
|
||||||
<declaredKeys>
|
<declaredKeys>
|
||||||
|
@ -600,5 +632,12 @@
|
||||||
<string>preference</string>
|
<string>preference</string>
|
||||||
</declaredKeys>
|
</declaredKeys>
|
||||||
</arrayController>
|
</arrayController>
|
||||||
|
<arrayController objectClassName="NSDictionary" editable="NO" id="KAn-H1-QH6" userLabel="MIDIFlavorBehavior" customClass="MIDIFlavorBehaviorArrayController">
|
||||||
|
<declaredKeys>
|
||||||
|
<string>name</string>
|
||||||
|
<string>slug</string>
|
||||||
|
<string>preference</string>
|
||||||
|
</declaredKeys>
|
||||||
|
</arrayController>
|
||||||
</objects>
|
</objects>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
8384918C1808596A00E7332D /* NDHotKey.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 838491841808588D00E7332D /* NDHotKey.framework */; };
|
8384918C1808596A00E7332D /* NDHotKey.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 838491841808588D00E7332D /* NDHotKey.framework */; };
|
||||||
83B06729180D85B8008E3612 /* MIDIPane.m in Sources */ = {isa = PBXBuildFile; fileRef = 83B06728180D85B8008E3612 /* MIDIPane.m */; };
|
83B06729180D85B8008E3612 /* MIDIPane.m in Sources */ = {isa = PBXBuildFile; fileRef = 83B06728180D85B8008E3612 /* MIDIPane.m */; };
|
||||||
83B0672B180D8B39008E3612 /* midi.png in Resources */ = {isa = PBXBuildFile; fileRef = 83B0672A180D8B39008E3612 /* midi.png */; };
|
83B0672B180D8B39008E3612 /* midi.png in Resources */ = {isa = PBXBuildFile; fileRef = 83B0672A180D8B39008E3612 /* midi.png */; };
|
||||||
|
83DFEA0B1CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83DFEA0A1CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.m */; };
|
||||||
83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83EF495E17FBC96A00642E3C /* VolumeBehaviorArrayController.m */; };
|
83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83EF495E17FBC96A00642E3C /* VolumeBehaviorArrayController.m */; };
|
||||||
83F27E6B1810DD3A00CEF538 /* appearance@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 83F27E651810DD3A00CEF538 /* appearance@2x.png */; };
|
83F27E6B1810DD3A00CEF538 /* appearance@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 83F27E651810DD3A00CEF538 /* appearance@2x.png */; };
|
||||||
83F27E6C1810DD3A00CEF538 /* growl@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 83F27E661810DD3A00CEF538 /* growl@2x.png */; };
|
83F27E6C1810DD3A00CEF538 /* growl@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 83F27E661810DD3A00CEF538 /* growl@2x.png */; };
|
||||||
|
@ -107,6 +108,8 @@
|
||||||
83B06727180D85B8008E3612 /* MIDIPane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIPane.h; sourceTree = "<group>"; };
|
83B06727180D85B8008E3612 /* MIDIPane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIPane.h; sourceTree = "<group>"; };
|
||||||
83B06728180D85B8008E3612 /* MIDIPane.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIPane.m; sourceTree = "<group>"; };
|
83B06728180D85B8008E3612 /* MIDIPane.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIPane.m; sourceTree = "<group>"; };
|
||||||
83B0672A180D8B39008E3612 /* midi.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = midi.png; path = Icons/midi.png; sourceTree = "<group>"; };
|
83B0672A180D8B39008E3612 /* midi.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = midi.png; path = Icons/midi.png; sourceTree = "<group>"; };
|
||||||
|
83DFEA091CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIFlavorBehaviorArrayController.h; sourceTree = "<group>"; };
|
||||||
|
83DFEA0A1CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIFlavorBehaviorArrayController.m; sourceTree = "<group>"; };
|
||||||
83EF495D17FBC96A00642E3C /* VolumeBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VolumeBehaviorArrayController.h; sourceTree = "<group>"; };
|
83EF495D17FBC96A00642E3C /* VolumeBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VolumeBehaviorArrayController.h; sourceTree = "<group>"; };
|
||||||
83EF495E17FBC96A00642E3C /* VolumeBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VolumeBehaviorArrayController.m; sourceTree = "<group>"; };
|
83EF495E17FBC96A00642E3C /* VolumeBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VolumeBehaviorArrayController.m; sourceTree = "<group>"; };
|
||||||
83F27E651810DD3A00CEF538 /* appearance@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "appearance@2x.png"; path = "Icons/appearance@2x.png"; sourceTree = "<group>"; };
|
83F27E651810DD3A00CEF538 /* appearance@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "appearance@2x.png"; path = "Icons/appearance@2x.png"; sourceTree = "<group>"; };
|
||||||
|
@ -233,6 +236,8 @@
|
||||||
17D503410ABDB1660022D1E8 /* Custom */ = {
|
17D503410ABDB1660022D1E8 /* Custom */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
83DFEA091CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.h */,
|
||||||
|
83DFEA0A1CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.m */,
|
||||||
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */,
|
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */,
|
||||||
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */,
|
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */,
|
||||||
8372053518E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.h */,
|
8372053518E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.h */,
|
||||||
|
@ -417,6 +422,7 @@
|
||||||
8E07AA890AAC8EA200A4B32F /* GeneralPreferencePane.m in Sources */,
|
8E07AA890AAC8EA200A4B32F /* GeneralPreferencePane.m in Sources */,
|
||||||
8E07AA8A0AAC8EA200A4B32F /* GeneralPreferencesPlugin.m in Sources */,
|
8E07AA8A0AAC8EA200A4B32F /* GeneralPreferencesPlugin.m in Sources */,
|
||||||
8E6C13A00AACBAB500819171 /* HotKeyControl.m in Sources */,
|
8E6C13A00AACBAB500819171 /* HotKeyControl.m in Sources */,
|
||||||
|
83DFEA0B1CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.m in Sources */,
|
||||||
83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */,
|
83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */,
|
||||||
17C643380B8A77CC00C53518 /* OutputsArrayController.m in Sources */,
|
17C643380B8A77CC00C53518 /* OutputsArrayController.m in Sources */,
|
||||||
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */,
|
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// MIDIFlavorBehaviorArrayController.h
|
||||||
|
// General
|
||||||
|
//
|
||||||
|
// Created by Christopher Snowhill on 04/12/16.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface MIDIFlavorBehaviorArrayController : NSArrayController
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// MIDIFlavorBehaviorArrayController.m
|
||||||
|
// General
|
||||||
|
//
|
||||||
|
// Created by Christopher Snowhill on 04/12/16.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MIDIFlavorBehaviorArrayController.h"
|
||||||
|
|
||||||
|
@implementation MIDIFlavorBehaviorArrayController
|
||||||
|
- (void)awakeFromNib
|
||||||
|
{
|
||||||
|
[self removeObjects:[self arrangedObjects]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"General MIDI", @"name", @"gm", @"preference", nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"General MIDI 2", @"name", @"gm2", @"preference", nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"Roland SC-55", @"name", @"sc55", @"preference", nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"Roland SC-88", @"name", @"sc88", @"preference", nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"Roland SC-88 Pro", @"name", @"sc88pro", @"preference", nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"Roland SC-8850", @"name", @"sc8850", @"preference", nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
@"Yamaha XG", @"name", @"xg", @"preference", nil]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -10,8 +10,10 @@
|
||||||
#import "GeneralPreferencePane.h"
|
#import "GeneralPreferencePane.h"
|
||||||
|
|
||||||
@interface MIDIPane : GeneralPreferencePane {
|
@interface MIDIPane : GeneralPreferencePane {
|
||||||
|
IBOutlet NSPopUpButton *midiFlavorControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)setSoundFont:(id)sender;
|
- (IBAction)setSoundFont:(id)sender;
|
||||||
|
- (IBAction)setMidiPlugin:(id)sender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
|
|
||||||
@implementation MIDIPane
|
@implementation MIDIPane
|
||||||
|
|
||||||
|
- (void)awakeFromNib
|
||||||
|
{
|
||||||
|
if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"midi.plugin"] isEqualToString:@"Sc55rolD"])
|
||||||
|
[midiFlavorControl setEnabled:YES];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)title
|
- (NSString *)title
|
||||||
{
|
{
|
||||||
return NSLocalizedStringFromTableInBundle(@"Synthesis", nil, [NSBundle bundleForClass:[self class]], @"");
|
return NSLocalizedStringFromTableInBundle(@"Synthesis", nil, [NSBundle bundleForClass:[self class]], @"");
|
||||||
|
@ -39,4 +45,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)setMidiPlugin:(id)sender
|
||||||
|
{
|
||||||
|
if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"midi.plugin"] isEqualToString:@"Sc55rolD"])
|
||||||
|
[midiFlavorControl setEnabled:YES];
|
||||||
|
else
|
||||||
|
[midiFlavorControl setEnabled:NO];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// ResamplerBehaviorArrayController.h
|
// MIDIPluginBehaviorArrayController.h
|
||||||
// General
|
// General
|
||||||
//
|
//
|
||||||
// Created by Christopher Snowhill on 03/26/14.
|
// Created by Christopher Snowhill on 03/26/14.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// ResamplerBehaviorArrayController.m
|
// MIDIPluginBehaviorArrayController.m
|
||||||
// General
|
// General
|
||||||
//
|
//
|
||||||
// Created by Christopher Snowhill on 03/26/14.
|
// Created by Christopher Snowhill on 03/26/14.
|
||||||
|
|
Loading…
Reference in New Issue