diff --git a/Plugins/MIDI/MIDI/MIDIContainer.mm b/Plugins/MIDI/MIDI/MIDIContainer.mm index b182bba88..8302b0aca 100644 --- a/Plugins/MIDI/MIDI/MIDIContainer.mm +++ b/Plugins/MIDI/MIDI/MIDIContainer.mm @@ -11,6 +11,8 @@ #import +#import "Logging.h" + @implementation MIDIContainer + (NSArray *)fileTypes { @@ -45,14 +47,19 @@ long size = [source tell]; [source seek:0 whence:SEEK_SET]; - std::vector data; - data.resize(size); - [source read:&data[0] amount:size]; - size_t track_count = 0; - if(!midi_processor::process_track_count(data, [[url pathExtension] UTF8String], track_count)) + try { + std::vector data; + data.resize(size); + [source read:&data[0] amount:size]; + + if(!midi_processor::process_track_count(data, [[url pathExtension] UTF8String], track_count)) + return @[]; + } catch (std::exception &e) { + ALog(@"Exception caught processing MIDI track count: %s", e.what()); return @[]; + } NSMutableArray *tracks = [NSMutableArray array]; diff --git a/Plugins/MIDI/MIDI/MIDIDecoder.mm b/Plugins/MIDI/MIDI/MIDIDecoder.mm index b8483e15b..b6e24b435 100644 --- a/Plugins/MIDI/MIDI/MIDIDecoder.mm +++ b/Plugins/MIDI/MIDI/MIDIDecoder.mm @@ -55,28 +55,36 @@ static OSType getOSType(const char *in_) { source = s; - std::vector file_data; + unsigned long loopStart = ~0; + unsigned long loopEnd = ~0; - [s seek:0 whence:SEEK_END]; - size_t size = [s tell]; - [s seek:0 whence:SEEK_SET]; - file_data.resize(size); - [s read:&file_data[0] amount:size]; + try { + std::vector file_data; - if(!midi_processor::process_file(file_data, [[[s url] pathExtension] UTF8String], midi_file)) + [s seek:0 whence:SEEK_END]; + size_t size = [s tell]; + [s seek:0 whence:SEEK_SET]; + file_data.resize(size); + [s read:&file_data[0] amount:size]; + + if(!midi_processor::process_file(file_data, [[[s url] pathExtension] UTF8String], midi_file)) + return NO; + + if(!midi_file.get_timestamp_end(track_num)) + return NO; + + track_num = [[[s url] fragment] intValue]; // What if theres no fragment? Assuming we get 0. + + midi_file.scan_for_loops(true, true, true, true); + + framesLength = midi_file.get_timestamp_end(track_num, true); + + loopStart = midi_file.get_timestamp_loop_start(track_num, true); + loopEnd = midi_file.get_timestamp_loop_end(track_num, true); + } catch (std::exception &e) { + ALog(@"Exception caught while reading MIDI file: %s", e.what()); return NO; - - if(!midi_file.get_timestamp_end(track_num)) - return NO; - - track_num = [[[s url] fragment] intValue]; // What if theres no fragment? Assuming we get 0. - - midi_file.scan_for_loops(true, true, true, true); - - framesLength = midi_file.get_timestamp_end(track_num, true); - - unsigned long loopStart = midi_file.get_timestamp_loop_start(track_num, true); - unsigned long loopEnd = midi_file.get_timestamp_loop_end(track_num, true); + } if(loopStart == ~0UL) loopStart = 0; if(loopEnd == ~0UL) loopEnd = framesLength; @@ -206,73 +214,78 @@ static OSType getOSType(const char *in_) { } } - if(!plugin || [plugin isEqualToString:@"BASSMIDI"]) { - bmplayer = new BMPlayer; + try { + if(!plugin || [plugin isEqualToString:@"BASSMIDI"]) { + bmplayer = new BMPlayer; - bool resamplingSinc = false; - NSString *resampling = [[NSUserDefaults standardUserDefaults] stringForKey:@"resampling"]; - if([resampling isEqualToString:@"sinc"]) - resamplingSinc = true; + bool resamplingSinc = false; + NSString *resampling = [[NSUserDefaults standardUserDefaults] stringForKey:@"resampling"]; + if([resampling isEqualToString:@"sinc"]) + resamplingSinc = true; - bmplayer->setSincInterpolation(resamplingSinc); - bmplayer->setSampleRate(sampleRate); + bmplayer->setSincInterpolation(resamplingSinc); + bmplayer->setSampleRate(sampleRate); - if([soundFontPath length]) - bmplayer->setFileSoundFont([soundFontPath UTF8String]); + if([soundFontPath length]) + bmplayer->setFileSoundFont([soundFontPath UTF8String]); - player = bmplayer; - } else if([[plugin substringToIndex:4] isEqualToString:@"DOOM"]) { - MSPlayer *msplayer = new MSPlayer; - player = msplayer; + player = bmplayer; + } else if([[plugin substringToIndex:4] isEqualToString:@"DOOM"]) { + MSPlayer *msplayer = new MSPlayer; + player = msplayer; - msplayer->set_synth(0); + msplayer->set_synth(0); - msplayer->set_bank([[plugin substringFromIndex:4] intValue]); + msplayer->set_bank([[plugin substringFromIndex:4] intValue]); - msplayer->set_extp(1); + msplayer->set_extp(1); - msplayer->setSampleRate(sampleRate); - } else if([[plugin substringToIndex:5] isEqualToString:@"OPL3W"]) { - MSPlayer *msplayer = new MSPlayer; - player = msplayer; + msplayer->setSampleRate(sampleRate); + } else if([[plugin substringToIndex:5] isEqualToString:@"OPL3W"]) { + MSPlayer *msplayer = new MSPlayer; + player = msplayer; - msplayer->set_synth(1); + msplayer->set_synth(1); - msplayer->set_bank([[plugin substringFromIndex:5] intValue]); + msplayer->set_bank([[plugin substringFromIndex:5] intValue]); - msplayer->set_extp(1); + msplayer->set_extp(1); - msplayer->setSampleRate(sampleRate); - } else { - const char *cplugin = [plugin UTF8String]; - OSType componentSubType; - OSType componentManufacturer; + msplayer->setSampleRate(sampleRate); + } else { + const char *cplugin = [plugin UTF8String]; + OSType componentSubType; + OSType componentManufacturer; - componentSubType = getOSType(cplugin); - componentManufacturer = getOSType(cplugin + 4); + componentSubType = getOSType(cplugin); + componentManufacturer = getOSType(cplugin + 4); - { - auplayer = new AUPlayer; + { + auplayer = new AUPlayer; - auplayer->setComponent(componentSubType, componentManufacturer); - auplayer->setSampleRate(sampleRate); + auplayer->setComponent(componentSubType, componentManufacturer); + auplayer->setSampleRate(sampleRate); - if([soundFontPath length]) { - auplayer->setSoundFont([soundFontPath UTF8String]); - soundFontsAssigned = YES; + if([soundFontPath length]) { + auplayer->setSoundFont([soundFontPath UTF8String]); + soundFontsAssigned = YES; + } + + player = auplayer; } - - player = auplayer; } - } - player->setFilterMode(mode, false); + player->setFilterMode(mode, false); - unsigned int loop_mode = framesFade ? MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force : 0; - unsigned int clean_flags = midi_container::clean_flag_emidi; + unsigned int loop_mode = framesFade ? MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force : 0; + unsigned int clean_flags = midi_container::clean_flag_emidi; - if(!player->Load(midi_file, track_num, loop_mode, clean_flags)) + if(!player->Load(midi_file, track_num, loop_mode, clean_flags)) + return NO; + } catch (std::exception &e) { + ALog(@"Exception caught while loading MIDI file into player: %s", e.what()); return NO; + } return YES; } @@ -287,66 +300,71 @@ static OSType getOSType(const char *in_) { return nil; } - player->setLoopMode((repeatone || isLooped) ? (MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force) : 0); + try { + player->setLoopMode((repeatone || isLooped) ? (MIDIPlayer::loop_mode_enable | MIDIPlayer::loop_mode_force) : 0); - if(!repeatone && framesRead >= localTotalFrames) - return 0; + if(!repeatone && framesRead >= localTotalFrames) + return 0; - if((bmplayer || auplayer) && !soundFontsAssigned) { - if(globalSoundFontPath != nil) { - if(bmplayer) - bmplayer->setSoundFont([globalSoundFontPath UTF8String]); - else if(auplayer) - auplayer->setSoundFont([globalSoundFontPath UTF8String]); - } - - soundFontsAssigned = YES; - } - - int frames = 1024; - float buffer[frames * 2]; - - UInt32 frames_done = player->Play(buffer, frames); - - if(!frames_done) - return 0; - - frames = frames_done; - - if(!repeatone && framesRead + frames > localFramesLength) { - if(framesFade) { - long fadeStart = (localFramesLength > framesRead) ? localFramesLength : framesRead; - long fadeEnd = (framesRead + frames > localTotalFrames) ? localTotalFrames : (framesRead + frames); - long fadePos; - - float *buff = buffer; - - float fadeScale = (float)(framesFade - (fadeStart - localFramesLength)) / framesFade; - float fadeStep = 1.0 / (float)framesFade; - for(fadePos = fadeStart; fadePos < fadeEnd; ++fadePos) { - buff[0] *= fadeScale; - buff[1] *= fadeScale; - buff += 2; - fadeScale -= fadeStep; - if(fadeScale < 0) { - fadeScale = 0; - fadeStep = 0; - } + if((bmplayer || auplayer) && !soundFontsAssigned) { + if(globalSoundFontPath != nil) { + if(bmplayer) + bmplayer->setSoundFont([globalSoundFontPath UTF8String]); + else if(auplayer) + auplayer->setSoundFont([globalSoundFontPath UTF8String]); } - frames = (int)(fadeEnd - framesRead); - } else { - frames = (int)(localTotalFrames - framesRead); + soundFontsAssigned = YES; } + + int frames = 1024; + float buffer[frames * 2]; + + UInt32 frames_done = player->Play(buffer, frames); + + if(!frames_done) + return 0; + + frames = frames_done; + + if(!repeatone && framesRead + frames > localFramesLength) { + if(framesFade) { + long fadeStart = (localFramesLength > framesRead) ? localFramesLength : framesRead; + long fadeEnd = (framesRead + frames > localTotalFrames) ? localTotalFrames : (framesRead + frames); + long fadePos; + + float *buff = buffer; + + float fadeScale = (float)(framesFade - (fadeStart - localFramesLength)) / framesFade; + float fadeStep = 1.0 / (float)framesFade; + for(fadePos = fadeStart; fadePos < fadeEnd; ++fadePos) { + buff[0] *= fadeScale; + buff[1] *= fadeScale; + buff += 2; + fadeScale -= fadeStep; + if(fadeScale < 0) { + fadeScale = 0; + fadeStep = 0; + } + } + + frames = (int)(fadeEnd - framesRead); + } else { + frames = (int)(localTotalFrames - framesRead); + } + } + + framesRead += frames; + + id audioChunkClass = NSClassFromString(@"AudioChunk"); + AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; + [chunk assignSamples:buffer frameCount:frames]; + + return chunk; + } catch (std::exception &e) { + ALog(@"Exception caught while playing MIDI file: %s", e.what()); + return nil; } - - framesRead += frames; - - id audioChunkClass = NSClassFromString(@"AudioChunk"); - AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; - [chunk assignSamples:buffer frameCount:frames]; - - return chunk; } - (long)seek:(long)frame { @@ -355,7 +373,13 @@ static OSType getOSType(const char *in_) { return -1; } - player->Seek(frame); + try { + player->Seek(frame); + } catch (std::exception &e) { + ALog(@"Exception caught while seeking in MIDI file: %s", e.what()); + framesRead = 0; + return -1; + } framesRead = frame; diff --git a/Plugins/MIDI/MIDI/MIDIMetadataReader.mm b/Plugins/MIDI/MIDI/MIDIMetadataReader.mm index a4f29c79b..10e761b37 100644 --- a/Plugins/MIDI/MIDI/MIDIMetadataReader.mm +++ b/Plugins/MIDI/MIDI/MIDIMetadataReader.mm @@ -12,6 +12,8 @@ #import +#import "Logging.h" + @implementation MIDIMetadataReader + (NSArray *)fileTypes { @@ -49,51 +51,56 @@ static void setDictionary(NSMutableDictionary *dict, NSString *tag, NSString *va long size = [source tell]; [source seek:0 whence:SEEK_SET]; - std::vector data; - data.resize(size); - [source read:&data[0] amount:size]; + try { + std::vector data; + data.resize(size); + [source read:&data[0] amount:size]; - midi_container midi_file; + midi_container midi_file; - if(!midi_processor::process_file(data, [[url pathExtension] UTF8String], midi_file)) - return 0; + if(!midi_processor::process_file(data, [[url pathExtension] UTF8String], midi_file)) + return 0; - int track_num; - if([[url fragment] length] == 0) - track_num = 0; - else - track_num = [[url fragment] intValue]; + int track_num; + if([[url fragment] length] == 0) + track_num = 0; + else + track_num = [[url fragment] intValue]; - midi_meta_data metadata; + midi_meta_data metadata; - midi_file.get_meta_data(track_num, metadata); + midi_file.get_meta_data(track_num, metadata); - midi_meta_data_item item; - bool remap_display_name = !metadata.get_item("title", item); + midi_meta_data_item item; + bool remap_display_name = !metadata.get_item("title", item); - NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; - for(size_t i = 0; i < metadata.get_count(); ++i) { - @autoreleasepool { - const midi_meta_data_item &item = metadata[i]; - NSString *name = [guess_encoding_of_string(item.m_name.c_str()) lowercaseString]; - if(![name isEqualToString:@"type"]) { - if(remap_display_name && [name isEqualToString:@"display_name"]) - name = @"title"; - setDictionary(dict, name, guess_encoding_of_string(item.m_value.c_str())); + for(size_t i = 0; i < metadata.get_count(); ++i) { + @autoreleasepool { + const midi_meta_data_item &item = metadata[i]; + NSString *name = [guess_encoding_of_string(item.m_name.c_str()) lowercaseString]; + if(![name isEqualToString:@"type"]) { + if(remap_display_name && [name isEqualToString:@"display_name"]) + name = @"title"; + setDictionary(dict, name, guess_encoding_of_string(item.m_value.c_str())); + } } } - } - std::vector albumArt; + std::vector albumArt; - if(metadata.get_bitmap(albumArt)) { - @autoreleasepool { - [dict setObject:[NSData dataWithBytes:&albumArt[0] length:albumArt.size()] forKey:@"albumArt"]; + if(metadata.get_bitmap(albumArt)) { + @autoreleasepool { + [dict setObject:[NSData dataWithBytes:&albumArt[0] length:albumArt.size()] forKey:@"albumArt"]; + } } - } - return dict; + return dict; + } catch (std::exception &e) { + ALog(@"Exception caught while reading MIDI metadata: %s", e.what()); + return [NSDictionary dictionary]; + } } @end