MIDI: Overhaul player completely, now Audio Unit support works properly, and the Sound Canvas VA hack is no longer needed. Now System Exclusive messages may be filtered for all plugins.

CQTexperiment
Christopher Snowhill 2021-11-02 19:52:12 -07:00
parent 8b2e4524b2
commit bce21b44d4
16 changed files with 592 additions and 428 deletions

View File

@ -33,8 +33,6 @@
83B06722180D70FE008E3612 /* MIDIDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83B06721180D70FE008E3612 /* MIDIDecoder.mm */; };
83C35702180EDB74007E9DF0 /* MIDIContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83C35700180EDB74007E9DF0 /* MIDIContainer.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 */; };
/* End PBXBuildFile section */
@ -140,10 +138,6 @@
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>"; };
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>"; };
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>"; };
@ -270,10 +264,6 @@
83A09F5D1CFA83F2001E7D2D /* fmopl3lib */,
834BE9191DE407CB00A07DCD /* resampler.c */,
834BE91A1DE407CB00A07DCD /* resampler.h */,
83DFEA031CBC87BB00BCC565 /* SCCore.cpp */,
83DFEA041CBC87BB00BCC565 /* SCCore.h */,
83DFEA051CBC87BB00BCC565 /* SCPlayer.cpp */,
83DFEA061CBC87BB00BCC565 /* SCPlayer.h */,
83686AAD1C5C6A2700671C7A /* AUPlayerView.h */,
83686AAB1C5C69D400671C7A /* AUPlayerView.mm */,
83E973451C4378880007F413 /* AUPlayer.mm */,
@ -403,10 +393,8 @@
files = (
83E973471C4378880007F413 /* AUPlayer.mm in Sources */,
83686AAC1C5C69D400671C7A /* AUPlayerView.mm in Sources */,
83DFEA071CBC87BB00BCC565 /* SCCore.cpp in Sources */,
83A09F621CFA83F2001E7D2D /* i_oplmusic.cpp in Sources */,
83B06709180D64DA008E3612 /* MIDIPlayer.cpp in Sources */,
83DFEA081CBC87BB00BCC565 /* SCPlayer.cpp in Sources */,
83A09F631CFA83F2001E7D2D /* opl3midi.cpp in Sources */,
83B06722180D70FE008E3612 /* MIDIDecoder.mm in Sources */,
83A09F6F1CFA8D6B001E7D2D /* MSPlayer.cpp in Sources */,

View File

@ -31,12 +31,17 @@ public:
void setComponent(OSType uSubType, OSType uManufacturer);
protected:
virtual unsigned int send_event_needs_time();
virtual void send_event(uint32_t b);
virtual void send_sysex(const uint8_t * data, size_t size, size_t port);
virtual void render(float * out, unsigned long count);
virtual void shutdown();
virtual bool startup();
virtual void send_event_time(uint32_t b, unsigned int time);
virtual void send_sysex_time(const uint8_t * data, size_t size, size_t port, unsigned int time);
private:
void loadSoundFont(const char * name);

View File

@ -12,6 +12,8 @@
#define _countof(arr) (sizeof(arr) / sizeof((arr)[0]))
#define BLOCK_SIZE (512)
AUPlayer::AUPlayer() : MIDIPlayer()
{
samplerUnit[0] = NULL;
@ -38,40 +40,53 @@ AUPlayer::~AUPlayer()
}
void AUPlayer::send_event(uint32_t b)
{
send_event_time(b, 0);
}
void AUPlayer::send_sysex(const uint8_t * data, size_t size, size_t port)
{
send_sysex_time(data, size, port, 0);
}
void AUPlayer::send_event_time(uint32_t b, unsigned int time)
{
#ifdef AUPLAYERVIEW
int _port = -1;
#endif
if (!(b & 0x80000000))
{
unsigned char event[ 3 ];
event[ 0 ] = (unsigned char)b;
event[ 1 ] = (unsigned char)( b >> 8 );
event[ 2 ] = (unsigned char)( b >> 16 );
unsigned port = (b >> 24) & 0x7F;
if ( port > 2 ) port = 2;
unsigned char event[ 3 ];
event[ 0 ] = (unsigned char)b;
event[ 1 ] = (unsigned char)( b >> 8 );
event[ 2 ] = (unsigned char)( b >> 16 );
unsigned port = (b >> 24) & 0x7F;
if ( port > 2 ) port = 2;
#ifdef AUPLAYERVIEW
_port = (int)port;
_port = (int)port;
#endif
MusicDeviceMIDIEvent(samplerUnit[port], event[0], event[1], event[2], 0);
MusicDeviceMIDIEvent(samplerUnit[port], event[0], event[1], event[2], time);
#ifdef AUPLAYERVIEW
if (_port >= 0 && !samplerUIinitialized[_port])
{
samplerUIinitialized[_port] = true;
dispatch_async(dispatch_get_main_queue(), ^{
samplerUI[_port] = new AUPluginUI(samplerUnit[_port]);
});
}
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;
#ifdef AUPLAYERVIEW
_port = (int)port;
#endif
MusicDeviceSysEx(samplerUnit[port], data, (UInt32) size);
if ( port == 0 )
{
MusicDeviceSysEx(samplerUnit[1], data, (UInt32) size);
MusicDeviceSysEx(samplerUnit[2], data, (UInt32) size);
}
}
}
void AUPlayer::send_sysex_time(const uint8_t * data, size_t size, size_t port, unsigned int time)
{
if ( port > 2 ) port = 0;
#ifdef AUPLAYERVIEW
_port = (int)port;
#endif
MusicDeviceSysEx(samplerUnit[port], data, (UInt32) size);
if ( port == 0 )
{
MusicDeviceSysEx(samplerUnit[1], data, (UInt32) size);
MusicDeviceSysEx(samplerUnit[2], data, (UInt32) size);
}
#ifdef AUPLAYERVIEW
if (_port >= 0 && !samplerUIinitialized[_port])
{
@ -89,7 +104,7 @@ void AUPlayer::render(float * out, unsigned long count)
memset(out, 0, count * sizeof(float) * 2);
while (count)
{
UInt32 numberFrames = count > 512 ? 512 : (UInt32) count;
UInt32 numberFrames = count > BLOCK_SIZE ? BLOCK_SIZE : (UInt32) count;
for (unsigned long i = 0; i < 3; ++i)
{
@ -99,7 +114,7 @@ void AUPlayer::render(float * out, unsigned long count)
{
bufferList->mBuffers[j].mNumberChannels = 1;
bufferList->mBuffers[j].mDataByteSize = (UInt32) (numberFrames * sizeof(float));
bufferList->mBuffers[j].mData = audioBuffer + j * 512;
bufferList->mBuffers[j].mData = audioBuffer + j * BLOCK_SIZE;
memset(bufferList->mBuffers[j].mData, 0, numberFrames * sizeof(float));
}
@ -175,6 +190,7 @@ void AUPlayer::shutdown()
free(bufferList);
bufferList = NULL;
}
initialized = false;
}
void AUPlayer::enumComponents(callback cbEnum)
@ -291,7 +307,7 @@ bool AUPlayer::startup()
kAudioUnitScope_Output, 0, &stream, sizeof (stream));
}
value = 512;
value = BLOCK_SIZE;
AudioUnitSetProperty (samplerUnit[i], kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global, 0, &value, size);
@ -348,7 +364,7 @@ bool AUPlayer::startup()
if (!bufferList)
return false;
audioBuffer = (float *) malloc(1024 * sizeof(float));
audioBuffer = (float *) malloc(BLOCK_SIZE * 2 * sizeof(float));
if (!audioBuffer)
return false;
@ -357,6 +373,10 @@ bool AUPlayer::startup()
memset(&mTimeStamp, 0, sizeof(mTimeStamp));
mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
initialized = true;
setFilterMode(mode);
return true;
}
@ -377,3 +397,8 @@ void AUPlayer::loadSoundFont(const char *name)
CFRelease(url);
}
}
unsigned int AUPlayer::send_event_needs_time()
{
return BLOCK_SIZE;
}

View File

@ -10,7 +10,6 @@
#import "AUPlayer.h"
#import "SFPlayer.h"
#import "SCPlayer.h"
#import "MSPlayer.h"
#import "Logging.h"
@ -155,6 +154,26 @@ static OSType getOSType(const char * in_)
DLog(@"Track num: %i", track_num);
MIDIPlayer::filter_mode mode = MIDIPlayer::filter_sc55;
NSString * flavor = [[NSUserDefaults standardUserDefaults] stringForKey:@"midi.flavor"];
if ([flavor isEqualToString:@"default"])
mode = MIDIPlayer::filter_default;
else if ([flavor isEqualToString:@"gm"])
mode = MIDIPlayer::filter_gm;
else if ([flavor isEqualToString:@"gm2"])
mode = MIDIPlayer::filter_gm2;
else if ([flavor isEqualToString:@"sc55"])
mode = MIDIPlayer::filter_sc55;
else if ([flavor isEqualToString:@"sc88"])
mode = MIDIPlayer::filter_sc88;
else if ([flavor isEqualToString:@"sc88pro"])
mode = MIDIPlayer::filter_sc88pro;
else if ([flavor isEqualToString:@"sc8850"])
mode = MIDIPlayer::filter_sc8850;
else if ([flavor isEqualToString:@"xg"])
mode = MIDIPlayer::filter_xg;
NSString * plugin = [[NSUserDefaults standardUserDefaults] stringForKey:@"midi.plugin"];
if (!plugin || [plugin isEqualToString:@"FluidSynth"])
{
@ -212,41 +231,6 @@ static OSType getOSType(const char * in_)
componentSubType = getOSType(cplugin);
componentManufacturer = getOSType(cplugin + 4);
if ((componentManufacturer == 'rolD' || componentManufacturer == 'RoCl') && componentSubType == 'Sc55')
{
const char * plugin_path = "/Library/Audio/Plug-Ins/Components/SOUND Canvas VA.component/Contents/Resources/SCCore00.dylib";
if (!dlopen_preflight(plugin_path))
return NO;
SCPlayer * scplayer = new SCPlayer;
SCPlayer::sc_mode mode = SCPlayer::sc_sc55;
NSString * flavor = [[NSUserDefaults standardUserDefaults] stringForKey:@"midi.flavor"];
if ([flavor isEqualToString:@"default"])
mode = SCPlayer::sc_default;
else 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(plugin_path);
scplayer->set_mode( mode );
scplayer->setSampleRate( 44100 );
player = scplayer;
}
else
{
auplayer = new AUPlayer;
@ -263,6 +247,8 @@ static OSType getOSType(const char * in_)
}
}
player->setFilterMode( mode );
unsigned int loop_mode = framesFade ? MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force : 0;
unsigned int clean_flags = midi_container::clean_flag_emidi;
@ -284,7 +270,7 @@ static OSType getOSType(const char * in_)
return -1;
}
player->SetLoopMode((repeatone || isLooped) ? (MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force) : 0);
player->setLoopMode((repeatone || isLooped) ? (MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force) : 0);
if ( !repeatone && framesRead >= localTotalFrames )
return 0;
@ -302,8 +288,12 @@ static OSType getOSType(const char * in_)
soundFontsAssigned = YES;
}
if ( player->Play( (float *) buf, frames ) < frames )
return -1;
UInt32 frames_done = player->Play( (float *) buf, frames );
if ( !frames_done )
return 0;
frames = frames_done;
if ( !repeatone && framesRead + frames > localFramesLength ) {
if ( framesFade ) {

View File

@ -9,6 +9,7 @@ MIDIPlayer::MIDIPlayer()
uTimeCurrent = 0;
uTimeEnd = 0;
uTimeLoopStart = 0;
initialized = false;
}
void MIDIPlayer::setSampleRate(unsigned long rate)
@ -130,15 +131,28 @@ unsigned long MIDIPlayer::Play(float * out, unsigned long count)
if ( !startup() ) return 0;
unsigned long done = 0;
unsigned int needs_block_size = send_event_needs_time();
unsigned int into_block = 0;
// This should be a multiple of block size, and have leftover
if ( uSamplesRemaining )
while ( uSamplesRemaining )
{
unsigned long todo = uSamplesRemaining;
if (todo > count) todo = count;
if (needs_block_size && todo > needs_block_size)
todo = needs_block_size;
if (todo < needs_block_size)
{
uSamplesRemaining = 0;
into_block = todo;
break;
}
render( out, todo );
uSamplesRemaining -= todo;
done += todo;
uTimeCurrent += todo;
uTimeCurrent += todo;
}
while (done < count)
@ -165,42 +179,71 @@ unsigned long MIDIPlayer::Play(float * out, unsigned long count)
uSamplesRemaining = samples_todo - ( count - done );
samples_todo = count - done;
}
render( out + done * 2, samples_todo );
done += samples_todo;
if (!needs_block_size && samples_todo)
{
render( out + done * 2, samples_todo );
done += samples_todo;
uTimeCurrent += samples_todo;
}
if ( uSamplesRemaining )
{
uTimeCurrent = me->m_timestamp;
uSamplesRemaining += into_block;
return done;
}
}
send_event( me->m_event );
if (needs_block_size)
{
into_block += samples_todo;
while (into_block >= needs_block_size)
{
render( out + done * 2, needs_block_size );
done += needs_block_size;
into_block -= needs_block_size;
uTimeCurrent += needs_block_size;
}
send_event_time_filtered( me->m_event, into_block );
}
else
send_event_filtered( me->m_event );
uTimeCurrent = me->m_timestamp;
}
}
if ( done < count )
{
unsigned long samples_todo;
if ( uStreamPosition < mStream.size() ) samples_todo = mStream[uStreamPosition].m_timestamp;
else samples_todo = uTimeEnd;
samples_todo -= uTimeCurrent;
if ( samples_todo > count - done ) samples_todo = count - done;
render( out + done * 2, samples_todo );
done += samples_todo;
}
if ( done < count )
{
unsigned long samples_todo;
if ( uStreamPosition < mStream.size() ) samples_todo =
mStream[uStreamPosition].m_timestamp;
else samples_todo = uTimeEnd;
samples_todo -= uTimeCurrent;
if ( samples_todo > count - done ) samples_todo = count
- done;
if ( needs_block_size && samples_todo > needs_block_size )
samples_todo = needs_block_size;
if ( samples_todo >= needs_block_size )
{
render( out + done * 2, samples_todo );
done += samples_todo;
uTimeCurrent += samples_todo;
}
}
if (!needs_block_size)
uTimeCurrent = time_target;
uTimeCurrent = time_target;
if (uTimeCurrent >= uTimeEnd)
if (time_target >= uTimeEnd)
{
if ( uStreamPosition < mStream.size() )
{
for (; uStreamPosition < mStream.size(); uStreamPosition++)
{
send_event( mStream[ uStreamPosition ].m_event );
if ( needs_block_size )
send_event_time_filtered( mStream[ uStreamPosition ].m_event, into_block );
else
send_event_filtered( mStream[ uStreamPosition ].m_event );
}
}
@ -219,7 +262,9 @@ unsigned long MIDIPlayer::Play(float * out, unsigned long count)
}
else break;
}
}
}
uSamplesRemaining = into_block;
return done;
}
@ -292,22 +337,51 @@ void MIDIPlayer::Seek(unsigned long sample)
}
}
float temp[32];
bool needs_time = send_event_needs_time();
float * temp;
unsigned int needs_time = send_event_needs_time();
for (i = 0; i < stream_start; i++)
{
if (me[i].m_event)
if (needs_time)
{
temp = (float *) malloc(needs_time * 2 * sizeof(float));
if (temp)
{
send_event(me[i].m_event);
if (needs_time)
render(temp, 16);
unsigned int render_junk = 0;
for (i = 0; i < stream_start; i++)
{
if (me[i].m_event)
{
send_event_time_filtered(me[i].m_event, render_junk);
render_junk += 16;
if (render_junk >= needs_time)
{
render(temp, needs_time);
render_junk -= needs_time;
}
}
}
uSamplesRemaining = render_junk;
free(temp);
}
}
}
else
{
temp = (float *) malloc(16 * 2 * sizeof(float));
if (temp)
{
for (i = 0; i < stream_start; i++)
{
if (me[i].m_event)
{
send_event_filtered(me[i].m_event);
}
}
free(temp);
}
}
}
}
void MIDIPlayer::SetLoopMode(unsigned int mode)
void MIDIPlayer::setLoopMode(unsigned int mode)
{
if (uLoopMode != mode)
{
@ -318,3 +392,247 @@ void MIDIPlayer::SetLoopMode(unsigned int mode)
}
uLoopMode = mode;
}
void MIDIPlayer::send_event_filtered(uint32_t b)
{
if (!(b & 0x80000000u))
{
send_event(b);
}
else
{
unsigned int p_index = b & 0xffffff;
const uint8_t * p_data;
size_t p_size, p_port;
mSysexMap.get_entry(p_index, p_data, p_size, p_port);
send_sysex_filtered(p_data, p_size, p_port);
}
}
void MIDIPlayer::send_event_time_filtered(uint32_t b, unsigned int time)
{
if (!(b & 0x80000000u))
{
send_event_time(b, time);
}
else
{
unsigned int p_index = b & 0xffffff;
const uint8_t * p_data;
size_t p_size, p_port;
mSysexMap.get_entry(p_index, p_data, p_size, p_port);
send_sysex_time_filtered(p_data, p_size, p_port, time);
}
}
void MIDIPlayer::setFilterMode(filter_mode m)
{
mode = m;
if (initialized)
{
sysex_reset(0, 0);
sysex_reset(1, 0);
sysex_reset(2, 0);
}
}
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 MIDIPlayer::sysex_send_gs(size_t port, uint8_t * data, size_t size, unsigned int time)
{
unsigned long i;
unsigned char checksum = 0;
for (i = 5; i + 1 < size && data[i+1] != 0xF7; ++i)
checksum += data[i];
checksum = (128 - checksum) & 127;
data[i] = checksum;
if (time)
send_sysex_time(data, size, port, time);
else
send_sysex(data, size, port);
}
void MIDIPlayer::sysex_reset_sc(uint32_t port, unsigned int time)
{
unsigned int i;
uint8_t message[11];
memcpy(message, syx_gs_limit_bank_lsb, 11);
message[7] = 1;
switch (mode)
{
default: break;
case filter_sc55:
message[8] = 1;
break;
case filter_sc88:
message[8] = 2;
break;
case filter_sc88pro:
message[8] = 3;
break;
case filter_sc8850:
case filter_default:
message[8] = 4;
break;
}
for (i = 0x41; i <= 0x49; ++i)
{
message[6] = i;
sysex_send_gs(port, message, sizeof(message), time);
}
message[6] = 0x40;
sysex_send_gs(port, message, sizeof(message), time);
for (i = 0x4A; i <= 0x4F; ++i)
{
message[6] = i;
sysex_send_gs(port, message, sizeof(message), time);
}
}
void MIDIPlayer::sysex_reset(size_t port, unsigned int time)
{
if (initialized)
{
if (time)
{
send_sysex_time(syx_reset_xg, sizeof(syx_reset_xg), port, time);
send_sysex_time(syx_reset_gm2, sizeof(syx_reset_gm2), port, time);
send_sysex_time(syx_reset_gm, sizeof(syx_reset_gm), port, time);
}
else
{
send_sysex(syx_reset_xg, sizeof(syx_reset_xg), port);
send_sysex(syx_reset_gm2, sizeof(syx_reset_gm2), port);
send_sysex(syx_reset_gm, sizeof(syx_reset_gm), port);
}
switch (mode)
{
case filter_gm:
/*
if (time)
send_sysex_time(syx_reset_gm, sizeof(syx_reset_gm), port, time);
else
send_sysex(syx_reset_gm, sizeof(syx_reset_gm), port);
*/
break;
case filter_gm2:
if (time)
send_sysex_time(syx_reset_gm2, sizeof(syx_reset_gm2), port, time);
else
send_sysex(syx_reset_gm2, sizeof(syx_reset_gm2), port);
break;
case filter_sc55:
case filter_sc88:
case filter_sc88pro:
case filter_sc8850:
case filter_default:
if (time)
send_sysex_time(syx_reset_gs, sizeof(syx_reset_gs), port, time);
else
send_sysex(syx_reset_gs, sizeof(syx_reset_gs), port);
sysex_reset_sc(port, time);
break;
case filter_xg:
if (time)
send_sysex_time(syx_reset_xg, sizeof(syx_reset_xg), port, time);
else
send_sysex(syx_reset_xg, sizeof(syx_reset_xg), port);
break;
}
{
unsigned int i;
for (i = 0; i < 16; ++i)
{
if (time)
{
send_event_time(0x78B0 + i + (port << 24), time);
send_event_time(0x79B0 + i + (port << 24), time);
if (mode != filter_xg || i != 9)
{
send_event_time(0x20B0 + i + (port << 24), time);
send_event_time(0x00B0 + i + (port << 24), time);
send_event_time(0xC0 + i + (port << 24), time);
}
}
else
{
send_event(0x78B0 + i + (port << 24));
send_event(0x79B0 + i + (port << 24));
if (mode != filter_xg || i != 9)
{
send_event(0x20B0 + i + (port << 24));
send_event(0x00B0 + i + (port << 24));
send_event(0xC0 + i + (port << 24));
}
}
}
}
if (mode == filter_xg)
{
if (time)
{
send_event_time(0x20B9 + (port << 24), time);
send_event_time(0x7F00B9 + (port << 24), time);
send_event_time(0xC9 + (port << 24), time);
}
else
{
send_event(0x20B9 + (port << 24));
send_event(0x7F00B9 + (port << 24));
send_event(0xC9 + (port << 24));
}
}
}
}
void MIDIPlayer::send_sysex_filtered(const uint8_t *data, size_t size, size_t port)
{
send_sysex(data, size, port);
if (syx_is_reset(data) && mode != filter_default)
{
sysex_reset(port, 0);
}
}
void MIDIPlayer::send_sysex_time_filtered(const uint8_t *data, size_t size, size_t port, unsigned int time)
{
send_sysex_time(data, size, port, time);
if (syx_is_reset(data) && mode != filter_default)
{
sysex_reset(port, time);
}
}

View File

@ -12,6 +12,19 @@ public:
loop_mode_force = 1 << 1
};
typedef enum
{
filter_default = 0,
filter_gm,
filter_gm2,
filter_sc55,
filter_sc88,
filter_sc88pro,
filter_sc8850,
filter_xg
}
filter_mode;
// zero variables
MIDIPlayer();
@ -20,28 +33,46 @@ public:
// setup
void setSampleRate(unsigned long rate);
void SetLoopMode(unsigned int mode);
void setLoopMode(unsigned int mode);
void setFilterMode(filter_mode m);
bool Load(const midi_container & midi_file, unsigned subsong, unsigned loop_mode, unsigned clean_flags);
unsigned long Play(float * out, unsigned long count);
void Seek(unsigned long sample);
protected:
virtual bool send_event_needs_time() { return false; }
// this should return the block size that the renderer expects, otherwise 0
virtual unsigned int send_event_needs_time() { return 0; }
virtual void send_event(uint32_t b) {}
virtual void send_sysex(const uint8_t * event, size_t size, size_t port) {};
virtual void render(float * out, unsigned long count) {}
virtual void shutdown() {};
virtual bool startup() {return false;}
// time should only be block level offset
virtual void send_event_time(uint32_t b, unsigned int time) {};
virtual void send_sysex_time(const uint8_t * event, size_t size, size_t port, unsigned int time) {};
unsigned long uSampleRate;
system_exclusive_table mSysexMap;
bool initialized;
filter_mode mode;
private:
void send_event_filtered(uint32_t b);
void send_sysex_filtered(const uint8_t * event, size_t size, size_t port);
void send_event_time_filtered(uint32_t b, unsigned int time);
void send_sysex_time_filtered(const uint8_t * event, size_t size, size_t port, unsigned int time);
void sysex_reset(size_t port, unsigned int time);
void sysex_send_gs(size_t port, uint8_t * data, size_t size, unsigned int time);
void sysex_reset_sc(uint32_t port, unsigned int time);
unsigned long uSamplesRemaining;
unsigned uLoopMode;
std::vector<midi_stream_event> mStream;
unsigned long uStreamPosition;

View File

@ -33,10 +33,11 @@ void MSPlayer::set_extp(unsigned int extp)
void MSPlayer::send_event(uint32_t b)
{
if (!(b & 0x80000000))
{
synth->midi_write(b);
}
synth->midi_write(b);
}
void MSPlayer::send_sysex(const uint8_t * data, size_t size, size_t port)
{
}
void MSPlayer::render(float * out, unsigned long count)
@ -60,6 +61,7 @@ void MSPlayer::shutdown()
{
delete synth;
synth = 0;
initialized = false;
}
bool MSPlayer::startup()
@ -83,6 +85,10 @@ bool MSPlayer::startup()
if (!synth->midi_init((unsigned int)uSampleRate, bank_id, extp))
return false;
initialized = true;
setFilterMode(mode);
return true;
}

View File

@ -26,6 +26,7 @@ public:
protected:
virtual void send_event(uint32_t b);
virtual void send_sysex(const uint8_t * data, size_t size, size_t port);
virtual void render(float * out, unsigned long count);
virtual void shutdown();

View File

@ -7,6 +7,8 @@
#include "SCPlayer.h"
#define BLOCK_SIZE (512)
// 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;
@ -14,7 +16,7 @@ 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)
SCPlayer::SCPlayer() : MIDIPlayer(), initialized(false), sccore_path(0)
{
pthread_mutex_lock(&g_lock);
while (g_instances_open.size() >= g_max_instances)
@ -49,180 +51,6 @@ SCPlayer::~SCPlayer()
}
}
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) && mode != sc_default)
{
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:
case sc_default:
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)
{
sampler[port].TG_LongMidiIn(syx_reset_xg, 0); junk(port, 1024);
sampler[port].TG_LongMidiIn(syx_reset_gm2, 0); junk(port, 1024);
sampler[port].TG_LongMidiIn(syx_reset_gm, 0); junk(port, 1024);
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:
case sc_default:
sampler[port].TG_LongMidiIn( syx_reset_gs, 0 ); junk(port, 1024);
reset_sc(port);
break;
case sc_xg:
sampler[port].TG_LongMidiIn( syx_reset_xg, 0 );
break;
}
junk(port, 1024);
{
unsigned int i;
for (i = 0; i < 16; ++i)
{
sampler[port].TG_ShortMidiIn(0x78B0 + i, 0);
sampler[port].TG_ShortMidiIn(0x79B0 + i, 0);
if (mode != sc_xg || i != 9)
{
sampler[port].TG_ShortMidiIn(0x20B0 + i, 0);
sampler[port].TG_ShortMidiIn(0x00B0 + i, 0);
sampler[port].TG_ShortMidiIn(0xC0 + i, 0);
}
}
}
if (mode == sc_xg)
{
sampler[port].TG_ShortMidiIn(0x20B9, 0);
sampler[port].TG_ShortMidiIn(0x7F00B9, 0);
sampler[port].TG_ShortMidiIn(0xC9, 0);
}
junk(port, uSampleRate * 2 / 3);
}
}
void SCPlayer::junk(uint32_t port, unsigned long count)
{
float temp[2][1024];
unsigned long i, j;
for (i = 0, j = count / 1024; i < j; ++i)
{
memset(temp, 0, sizeof(temp));
sampler[port].TG_setInterruptThreadIdAtThisTime();
sampler[port].TG_Process(temp[0], temp[1], 1024);
}
count %= 1024;
if (count)
{
memset(temp, 0, sizeof(temp));
sampler[port].TG_setInterruptThreadIdAtThisTime();
sampler[port].TG_Process(temp[0], temp[1], (unsigned int) count);
}
}
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;
@ -235,26 +63,30 @@ void SCPlayer::set_sccore_path(const char *path)
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 );
}
}
send_event_time(b, 0);
}
void SCPlayer::send_sysex(const uint8_t * data, size_t size, size_t port)
{
send_sysex_time(data, size, port, 0);
}
void SCPlayer::send_event_time(uint32_t b, unsigned int time)
{
unsigned port = (b >> 24) & 0x7F;
if ( port > 2 ) port = 0;
sampler[port].TG_ShortMidiIn(b, time);
}
void SCPlayer::send_sysex_time(const uint8_t * data, size_t size, size_t port, unsigned int time)
{
if ( port > 2 ) port = 0;
sampler[port].TG_LongMidiIn(data, time);
if (port == 0)
{
sampler[1].TG_LongMidiIn(data, time);
sampler[2].TG_LongMidiIn(data, time);
}
}
void SCPlayer::render(float * out, unsigned long count)
@ -262,8 +94,8 @@ 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;
float buffer[2][BLOCK_SIZE];
unsigned long todo = count > BLOCK_SIZE ? BLOCK_SIZE : count;
for (unsigned long i = 0; i < 3; ++i)
{
memset(buffer[0], 0, todo * sizeof(float));
@ -319,14 +151,14 @@ bool SCPlayer::startup()
sampler[i].TG_setMaxBlockSize(256);
sampler[i].TG_setSampleRate((float)uSampleRate);
sampler[i].TG_setSampleRate((float)uSampleRate);
sampler[i].TG_setMaxBlockSize(4096);
sampler[i].TG_setMaxBlockSize(BLOCK_SIZE);
}
initialized = true;
for (int i = 0; i < 3; i++)
{
reset(i);
reset(i, 0);
}
return true;
@ -346,7 +178,7 @@ unsigned int SCPlayer::get_playing_note_count()
return total;
}
bool SCPlayer::send_event_needs_time()
unsigned int SCPlayer::send_event_needs_time()
{
return true;
return BLOCK_SIZE;
}

View File

@ -16,46 +16,25 @@ public:
unsigned int get_playing_note_count();
typedef enum
{
sc_default = 0,
sc_gm,
sc_gm2,
sc_sc55,
sc_sc88,
sc_sc88pro,
sc_sc8850,
sc_xg
}
sc_mode;
void set_mode(sc_mode m);
void set_sccore_path(const char * path);
protected:
virtual bool send_event_needs_time();
virtual unsigned int send_event_needs_time();
virtual void send_event(uint32_t b);
virtual void send_sysex(const uint8_t * data, size_t size, size_t port);
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);
void junk(uint32_t port, unsigned long count);
virtual void send_event_time(uint32_t b, unsigned int time);
virtual void send_sysex_time(const uint8_t * data, size_t size, size_t port, unsigned int time);
private:
unsigned int instance_id;
bool initialized;
SCCore * sampler;
sc_mode mode;
char * sccore_path;
};

View File

@ -56,58 +56,52 @@ void SFPlayer::setDynamicLoading(bool enabled)
void SFPlayer::send_event(uint32_t b)
{
if (!(b & 0x80000000))
int param2 = (b >> 16) & 0xFF;
int param1 = (b >> 8) & 0xFF;
int cmd = b & 0xF0;
int chan = b & 0x0F;
int port = (b >> 24) & 0x7F;
fluid_synth_t* _synth = this->_synth[0];
if ( port && port < 3 )
_synth = this->_synth[port];
switch (cmd)
{
int param2 = (b >> 16) & 0xFF;
int param1 = (b >> 8) & 0xFF;
int cmd = b & 0xF0;
int chan = b & 0x0F;
int port = (b >> 24) & 0x7F;
fluid_synth_t* _synth = this->_synth[0];
if ( port && port < 3 )
_synth = this->_synth[port];
switch (cmd)
{
case 0x80:
fluid_synth_noteoff(_synth, chan, param1);
break;
case 0x90:
fluid_synth_noteon(_synth, chan, param1, param2);
break;
case 0xA0:
break;
case 0xB0:
fluid_synth_cc(_synth, chan, param1, param2);
break;
case 0xC0:
fluid_synth_program_change(_synth, chan, param1);
break;
case 0xD0:
fluid_synth_channel_pressure(_synth, chan, param1);
break;
case 0xE0:
fluid_synth_pitch_bend(_synth, chan, (param2 << 7) | param1);
break;
}
case 0x80:
fluid_synth_noteoff(_synth, chan, param1);
break;
case 0x90:
fluid_synth_noteon(_synth, chan, param1, param2);
break;
case 0xA0:
break;
case 0xB0:
fluid_synth_cc(_synth, chan, param1, param2);
break;
case 0xC0:
fluid_synth_program_change(_synth, chan, param1);
break;
case 0xD0:
fluid_synth_channel_pressure(_synth, chan, param1);
break;
case 0xE0:
fluid_synth_pitch_bend(_synth, chan, (param2 << 7) | param1);
break;
}
else
}
void SFPlayer::send_sysex(const uint8_t *data, size_t size, size_t port)
{
if (port >= 3)
port = 0;
if (data && size > 2 && data[0] == 0xF0 && data[size-1] == 0xF7)
{
uint32_t n = b & 0xffffff;
const uint8_t * data;
size_t size, port;
mSysexMap.get_entry( n, data, size, port );
if (port >= 3)
port = 0;
if (data && size > 2 && data[0] == 0xF0 && data[size-1] == 0xF7)
{
++data;
size -= 2;
fluid_synth_sysex(_synth[0], (const char *)data, size, NULL, NULL, NULL, 0);
fluid_synth_sysex(_synth[1], (const char *)data, size, NULL, NULL, NULL, 0);
fluid_synth_sysex(_synth[2], (const char *)data, size, NULL, NULL, NULL, 0);
}
++data;
size -= 2;
fluid_synth_sysex(_synth[0], (const char *)data, size, NULL, NULL, NULL, 0);
fluid_synth_sysex(_synth[1], (const char *)data, size, NULL, NULL, NULL, 0);
fluid_synth_sysex(_synth[2], (const char *)data, size, NULL, NULL, NULL, 0);
}
}
@ -155,6 +149,7 @@ void SFPlayer::shutdown()
if (_synth[i]) delete_fluid_synth(_synth[i]);
_synth[i] = 0;
}
initialized = false;
}
bool SFPlayer::startup()
@ -257,6 +252,10 @@ bool SFPlayer::startup()
}
_last_error = "";
initialized = true;
setFilterMode(mode);
return true;
}

View File

@ -32,12 +32,13 @@ public:
private:
virtual void send_event(uint32_t b);
virtual void send_sysex(const uint8_t * data, size_t size, size_t port);
virtual void render(float * out, unsigned long count);
virtual void shutdown();
virtual bool startup();
std::string _last_error;
std::string _last_error;
fluid_settings_t * _settings[3];
fluid_synth_t * _synth[3];

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19455" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19455"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -326,6 +327,7 @@
<string>name</string>
<string>url</string>
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
<arrayController objectClassName="NSDictionary" editable="NO" selectsInsertedObjects="NO" id="246" userLabel="PlaylistBehavior" customClass="PlaylistBehaviorArrayController">
<declaredKeys>
@ -333,6 +335,7 @@
<string>slug</string>
<string>preference</string>
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
<arrayController objectClassName="NSDictionary" editable="NO" selectsInsertedObjects="NO" id="SuD-jI-ifw" userLabel="VolumeBehavior" customClass="VolumeBehaviorArrayController">
<declaredKeys>
@ -340,6 +343,7 @@
<string>slug</string>
<string>preference</string>
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
<customView id="0nK-XQ-5MY" userLabel="ScrobblerView">
<rect key="frame" x="0.0" y="0.0" width="530" height="94"/>
@ -531,7 +535,7 @@
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1Yw-25-Gbs">
<rect key="frame" x="173" y="17" 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" enabled="NO" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" altersStateOfSelectedItem="NO" selectedItem="XzK-h2-vIT" id="qzt-Ox-taI">
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" altersStateOfSelectedItem="NO" selectedItem="XzK-h2-vIT" id="qzt-Ox-taI">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" autoenablesItems="NO" id="q1g-E5-NwQ">
@ -547,11 +551,6 @@
<binding destination="KAn-H1-QH6" name="contentValues" keyPath="arrangedObjects.name" previousBinding="WGj-w1-erz" id="Rvq-46-YeR"/>
<binding destination="KAn-H1-QH6" name="contentObjects" keyPath="arrangedObjects.preference" previousBinding="Zvj-Wf-Bum" id="WGj-w1-erz"/>
<binding destination="52" name="selectedObject" keyPath="values.midi.flavor" previousBinding="Rvq-46-YeR" id="zC1-3J-frL"/>
<binding destination="52" name="enabled" keyPath="values.midi.plugin" id="GlZ-Ch-oua">
<dictionary key="options">
<string key="NSValueTransformerName">MIDIPluginFlavorTransformer</string>
</dictionary>
</binding>
</connections>
</popUpButton>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="E1D-Bo-ZVf">
@ -584,6 +583,7 @@
<string>slug</string>
<string>preference</string>
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
<arrayController objectClassName="NSDictionary" editable="NO" id="czk-eG-6QG" userLabel="MIDIPluginBehavior" customClass="MIDIPluginBehaviorArrayController">
<declaredKeys>
@ -591,6 +591,7 @@
<string>slug</string>
<string>preference</string>
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
<arrayController objectClassName="NSDictionary" editable="NO" id="KAn-H1-QH6" userLabel="MIDIFlavorBehavior" customClass="MIDIFlavorBehaviorArrayController">
<declaredKeys>
@ -598,6 +599,7 @@
<string>slug</string>
<string>preference</string>
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
</objects>
</document>

View File

@ -8,7 +8,6 @@
#import "GeneralPreferencesPlugin.h"
#import "PathToFileTransformer.h"
#import "MIDIPluginFlavorTransformer.h"
@implementation GeneralPreferencesPlugin
@ -17,9 +16,6 @@
NSValueTransformer *pathToFileTransformer = [[PathToFileTransformer alloc] init];
[NSValueTransformer setValueTransformer:pathToFileTransformer
forName:@"PathToFileTransformer"];
NSValueTransformer *midiPluginFlavorTransformer = [[MIDIPluginFlavorTransformer alloc] init];
[NSValueTransformer setValueTransformer:midiPluginFlavorTransformer
forName:@"MIDIPluginFlavorTransformer"];
}
+ (NSArray *)preferencePanes

View File

@ -43,9 +43,6 @@
- (IBAction)setMidiPlugin:(id)sender
{
NSString * plugin = [[NSUserDefaults standardUserDefaults] stringForKey:@"midi.plugin"];
BOOL enabled = [plugin isEqualToString:@"Sc55rolD"] || [plugin isEqualToString:@"Sc55RoCl"];
[midiFlavorControl setEnabled:enabled];
}
@end

View File

@ -18,6 +18,7 @@
17E41DB80C130AA500AC744D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 17E41DB70C130AA500AC744D /* Localizable.strings */; };
17E78A7E0D68BE3C005C5A59 /* file_tree.png in Resources */ = {isa = PBXBuildFile; fileRef = 17E78A7D0D68BE3C005C5A59 /* file_tree.png */; };
17E78B6A0D68C1E3005C5A59 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17E78B680D68C1E3005C5A59 /* Preferences.xib */; };
83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */; };
836C314125EC8A7000692622 /* MASShortcut.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = ED69CBAE25BE32500090B90D /* MASShortcut.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */; };
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */; };
@ -25,9 +26,7 @@
8384917818084D9F00E7332D /* growl.png in Resources */ = {isa = PBXBuildFile; fileRef = 8384917618084D9F00E7332D /* growl.png */; };
83B06729180D85B8008E3612 /* MIDIPane.m in Sources */ = {isa = PBXBuildFile; fileRef = 83B06728180D85B8008E3612 /* MIDIPane.m */; };
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 */; };
83F127AA1DEE47E90010CB8F /* MIDIPluginFlavorTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 83F127A81DEE47E90010CB8F /* MIDIPluginFlavorTransformer.m */; };
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 */; };
83F27E6D1810DD3A00CEF538 /* lastfm@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 83F27E671810DD3A00CEF538 /* lastfm@2x.png */; };
@ -114,6 +113,8 @@
8347435F20E6D5A000063D45 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Preferences.strings; sourceTree = "<group>"; };
835C888922CC1880001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
835C888A22CC1880001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIFlavorBehaviorArrayController.m; sourceTree = "<group>"; };
83651DA427322C8700A2C097 /* MIDIFlavorBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIFlavorBehaviorArrayController.h; sourceTree = "<group>"; };
8372053518E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResamplerBehaviorArrayController.h; sourceTree = "<group>"; };
8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ResamplerBehaviorArrayController.m; sourceTree = "<group>"; };
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIPluginBehaviorArrayController.h; sourceTree = "<group>"; };
@ -125,12 +126,8 @@
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>"; };
83BC5AB320E4C90F00631CD4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Preferences.xib; 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>"; };
83EF495E17FBC96A00642E3C /* VolumeBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VolumeBehaviorArrayController.m; sourceTree = "<group>"; };
83F127A81DEE47E90010CB8F /* MIDIPluginFlavorTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIPluginFlavorTransformer.m; sourceTree = "<group>"; };
83F127A91DEE47E90010CB8F /* MIDIPluginFlavorTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIPluginFlavorTransformer.h; sourceTree = "<group>"; };
83F27E651810DD3A00CEF538 /* appearance@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "appearance@2x.png"; path = "Icons/appearance@2x.png"; sourceTree = "<group>"; };
83F27E661810DD3A00CEF538 /* growl@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "growl@2x.png"; path = "Icons/growl@2x.png"; sourceTree = "<group>"; };
83F27E671810DD3A00CEF538 /* lastfm@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "lastfm@2x.png"; path = "Icons/lastfm@2x.png"; sourceTree = "<group>"; };
@ -256,18 +253,18 @@
17D503410ABDB1660022D1E8 /* Custom */ = {
isa = PBXGroup;
children = (
83DFEA091CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.h */,
83DFEA0A1CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.m */,
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */,
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */,
8372053518E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.h */,
8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */,
170744AB0BFF3938002475C9 /* AppcastArrayController.h */,
170744AC0BFF3938002475C9 /* AppcastArrayController.m */,
83651DA427322C8700A2C097 /* MIDIFlavorBehaviorArrayController.h */,
83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */,
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */,
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */,
17C643370B8A77CC00C53518 /* OutputsArrayController.h */,
17C643360B8A77CC00C53518 /* OutputsArrayController.m */,
99F1813D0DE01D7A00FD5FFB /* PlaylistBehaviorArrayController.h */,
99F1813E0DE01D7A00FD5FFB /* PlaylistBehaviorArrayController.m */,
8372053518E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.h */,
8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */,
83EF495D17FBC96A00642E3C /* VolumeBehaviorArrayController.h */,
83EF495E17FBC96A00642E3C /* VolumeBehaviorArrayController.m */,
);
@ -304,8 +301,6 @@
83F27E711810E41A00CEF538 /* Transformers */ = {
isa = PBXGroup;
children = (
83F127A81DEE47E90010CB8F /* MIDIPluginFlavorTransformer.m */,
83F127A91DEE47E90010CB8F /* MIDIPluginFlavorTransformer.h */,
83F27E721810E45D00CEF538 /* PathToFileTransformer.h */,
83F27E731810E45D00CEF538 /* PathToFileTransformer.m */,
);
@ -376,7 +371,7 @@
LastUpgradeCheck = 1230;
TargetAttributes = {
8D5B49AC048680CD000E48DA = {
DevelopmentTeam = "";
DevelopmentTeam = N6E749HJ2X;
ProvisioningStyle = Automatic;
};
};
@ -469,17 +464,16 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */,
83B06729180D85B8008E3612 /* MIDIPane.m in Sources */,
8E07AA880AAC8EA200A4B32F /* HotKeyPane.m in Sources */,
83F27E741810E45D00CEF538 /* PathToFileTransformer.m in Sources */,
8E07AA890AAC8EA200A4B32F /* GeneralPreferencePane.m in Sources */,
8E07AA8A0AAC8EA200A4B32F /* GeneralPreferencesPlugin.m in Sources */,
83DFEA0B1CBC94DE00BCC565 /* MIDIFlavorBehaviorArrayController.m in Sources */,
83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */,
17C643380B8A77CC00C53518 /* OutputsArrayController.m in Sources */,
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */,
17C6433F0B8A783F00C53518 /* OutputPane.m in Sources */,
83F127AA1DEE47E90010CB8F /* MIDIPluginFlavorTransformer.m in Sources */,
170744AD0BFF3938002475C9 /* AppcastArrayController.m in Sources */,
99F1813F0DE01D7A00FD5FFB /* PlaylistBehaviorArrayController.m in Sources */,
8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */,