From b025a21e133d5b72df753ddd48584aefed5a5846 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Fri, 1 Jul 2022 22:06:08 -0700 Subject: [PATCH] [Synthesizers] Implement default overrides Default time, fade, loop count, and sample rate may now be overridden. Synchronized preferences strings tables. Spanish translation of new options pending, new releases won't be pushed until they're complete. Signed-off-by: Christopher Snowhill --- Application/AppController.m | 5 + .../AdPlug/AdPlug.xcodeproj/project.pbxproj | 4 + Plugins/AdPlug/AdPlug/AdPlugDecoder.h | 2 + Plugins/AdPlug/AdPlug/AdPlugDecoder.mm | 17 +- Plugins/GME/GameDecoder.h | 2 +- Plugins/GME/GameDecoder.m | 33 +++- .../HighlyComplete/HCDecoder.mm | 13 +- Plugins/Hively/Hively/HVLDecoder.h | 2 + Plugins/Hively/Hively/HVLDecoder.m | 26 ++- Plugins/MIDI/MIDI/MIDIDecoder.h | 2 + Plugins/MIDI/MIDI/MIDIDecoder.mm | 27 +++- .../OpenMPT/OpenMPT.xcodeproj/project.pbxproj | 4 + Plugins/OpenMPT/OpenMPT/OMPTDecoder.h | 2 + Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm | 15 +- Plugins/libvgmPlayer/libvgmDecoder.h | 3 + Plugins/libvgmPlayer/libvgmDecoder.mm | 25 ++- Plugins/sidplay/SidDecoder.h | 2 + Plugins/sidplay/SidDecoder.mm | 22 ++- .../sidplay/sidplay.xcodeproj/project.pbxproj | 4 + Plugins/vgmstream/vgmstream/VGMDecoder.h | 2 + Plugins/vgmstream/vgmstream/VGMDecoder.m | 16 +- .../Preferences/Base.lproj/Preferences.xib | 152 ++++++++++++++++-- .../Preferences/GeneralPreferencesPlugin.m | 5 + .../Preferences.xcodeproj/project.pbxproj | 6 + .../TimeIntervalToStringTransformer.h | 16 ++ .../TimeIntervalToStringTransformer.m | 63 ++++++++ .../Preferences/en.lproj/Preferences.strings | 106 +++++++++--- .../Preferences/es.lproj/Preferences.strings | 41 +++++ 28 files changed, 538 insertions(+), 79 deletions(-) create mode 100644 Preferences/Preferences/TimeIntervalToStringTransformer.h create mode 100644 Preferences/Preferences/TimeIntervalToStringTransformer.m diff --git a/Application/AppController.m b/Application/AppController.m index c4d6ef244..bed8606da 100644 --- a/Application/AppController.m +++ b/Application/AppController.m @@ -558,6 +558,11 @@ static AppController *kAppController = nil; [userDefaultsValuesDict setObject:barColor forKey:@"spectrumBarColor"]; [userDefaultsValuesDict setObject:dotColor forKey:@"spectrumDotColor"]; + [userDefaultsValuesDict setObject:@(150.0) forKey:@"synthDefaultSeconds"]; + [userDefaultsValuesDict setObject:@(8.0) forKey:@"synthDefaultFadeSeconds"]; + [userDefaultsValuesDict setObject:@(2) forKey:@"synthDefaultLoopCount"]; + [userDefaultsValuesDict setObject:@(44100) forKey:@"synthSampleRate"]; + // Register and sync defaults [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict]; [[NSUserDefaults standardUserDefaults] synchronize]; diff --git a/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj b/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj index 40850999e..91d66de5b 100644 --- a/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj +++ b/Plugins/AdPlug/AdPlug.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 833A899A286FF2FD0022E036 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 833A8999286FF2FD0022E036 /* Cocoa.framework */; }; 833AFD3620E4ED9D00F0C21E /* libAdPlug.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83AA434020E4EC8C00E861B2 /* libAdPlug.framework */; }; 83747C6F2862DDDB0021245F /* Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 83747C6D2862DDDB0021245F /* Shared.xcconfig */; }; 83C2806320E4ECAD00823BF9 /* libAdPlug.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83AA434020E4EC8C00E861B2 /* libAdPlug.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -51,6 +52,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 833A8999286FF2FD0022E036 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 83747C6D2862DDDB0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83D3C5F3201C674D005564CB /* AdPlug.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AdPlug.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 83D3C5F6201C674D005564CB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -77,6 +79,7 @@ files = ( 83D3C6A6201D3951005564CB /* libbinio.framework in Frameworks */, 833AFD3620E4ED9D00F0C21E /* libAdPlug.framework in Frameworks */, + 833A899A286FF2FD0022E036 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -141,6 +144,7 @@ 83D3C602201C675D005564CB /* Frameworks */ = { isa = PBXGroup; children = ( + 833A8999286FF2FD0022E036 /* Cocoa.framework */, 83D3C6A7201D3951005564CB /* libbinio.framework */, 83D3C603201C6775005564CB /* libAdPlug.xcodeproj */, ); diff --git a/Plugins/AdPlug/AdPlug/AdPlugDecoder.h b/Plugins/AdPlug/AdPlug/AdPlugDecoder.h index fd18c40f5..fce827ef6 100644 --- a/Plugins/AdPlug/AdPlug/AdPlugDecoder.h +++ b/Plugins/AdPlug/AdPlug/AdPlugDecoder.h @@ -17,6 +17,8 @@ CPlayer* m_player; Copl* m_emu; + double sampleRate; + unsigned int subsong, samples_todo; id source; diff --git a/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm b/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm index 3045b3b16..6e57a2263 100644 --- a/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm +++ b/Plugins/AdPlug/AdPlug/AdPlugDecoder.mm @@ -47,7 +47,14 @@ static CAdPlugDatabase *g_database = NULL; - (BOOL)open:(id)s { [self setSource:s]; - m_emu = new CNemuopl(44100); + sampleRate = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthSampleRate"] doubleValue]; + if(sampleRate < 8000.0) { + sampleRate = 44100.0; + } else if(sampleRate > 192000.0) { + sampleRate = 192000.0; + } + + m_emu = new CNemuopl(sampleRate); NSString *path = [[s url] absoluteString]; NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch]; @@ -68,7 +75,7 @@ static CAdPlugDatabase *g_database = NULL; samples_todo = 0; - length = m_player->songlength(subsong) * 441 / 10; + length = m_player->songlength(subsong) * sampleRate / 1000.0; current_pos = 0; m_player->rewind(subsong); @@ -81,7 +88,7 @@ static CAdPlugDatabase *g_database = NULL; - (NSDictionary *)properties { return @{ @"bitrate": @(0), - @"sampleRate": @(44100.0), + @"sampleRate": @(sampleRate), @"totalFrames": @(length), @"bitsPerSample": @(16), // Samples are short @"floatingPoint": @(NO), @@ -106,7 +113,7 @@ static CAdPlugDatabase *g_database = NULL; if(!samples_todo) { running = m_player->update() && running; if(!dont_loop || running) { - samples_todo = 44100 / m_player->getrefresh(); + samples_todo = (int)ceil(sampleRate / m_player->getrefresh()); current_pos += samples_todo; } } @@ -132,7 +139,7 @@ static CAdPlugDatabase *g_database = NULL; while(current_pos < frame) { m_player->update(); - current_pos += 44100 / m_player->getrefresh(); + current_pos += (long)ceil(sampleRate / m_player->getrefresh()); } samples_todo = (UInt32)(frame - current_pos); diff --git a/Plugins/GME/GameDecoder.h b/Plugins/GME/GameDecoder.h index d2758957e..72ae4d69d 100644 --- a/Plugins/GME/GameDecoder.h +++ b/Plugins/GME/GameDecoder.h @@ -17,7 +17,7 @@ extern gme_err_t readCallback(void* data, void* out, int count); @interface GameDecoder : NSObject { Music_Emu* emu; id source; - long sampleRate; + double sampleRate; long length; long fade; NSString* codec; diff --git a/Plugins/GME/GameDecoder.m b/Plugins/GME/GameDecoder.m index 226ec93de..cec7ae0fa 100644 --- a/Plugins/GME/GameDecoder.m +++ b/Plugins/GME/GameDecoder.m @@ -53,10 +53,15 @@ gme_err_t readCallback(void *data, void *out, int count) { return NO; } - sampleRate = 44100; + sampleRate = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthSampleRate"] doubleValue]; + if(sampleRate < 8000.0) { + sampleRate = 44100.0; + } else if(sampleRate > 192000.0) { + sampleRate = 192000.0; + } if(type == gme_spc_type || type == gme_sfm_type) - sampleRate = 32000; + sampleRate = 32000.0; emu = gme_new_emu(type, (int)sampleRate); if(!emu) { @@ -109,16 +114,30 @@ gme_err_t readCallback(void *data, void *out, int count) { length = info->length; } else if(info->loop_length > 0) { DLog(@"Using loop length: %i", info->loop_length); - length = info->intro_length + 2 * info->loop_length; + int loopCount = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultLoopCount"] intValue]; + if(loopCount < 0) { + loopCount = 1; + } else if(loopCount > 10) { + loopCount = 10; + } + length = info->intro_length + loopCount * info->loop_length; } else { - length = 150000; + double defaultLength = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultSeconds"] doubleValue]; + if(defaultLength < 0) { + defaultLength = 150.0; + } + length = (int)ceil(defaultLength * 1000.0); DLog(@"Setting default: %li", length); } if(info->fade_length >= 0) { fade = info->fade_length; } else { - fade = 8000; + double defaultFade = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue]; + if(defaultFade < 0) { + defaultFade = 0; + } + fade = (int)ceil(defaultFade * 1000.0); } gme_free_info(info); @@ -143,7 +162,7 @@ gme_err_t readCallback(void *data, void *out, int count) { - (NSDictionary *)properties { return @{ @"bitrate": @(0), @"sampleRate": @(sampleRate), - @"totalFrames": @((long)(length * ((float)sampleRate * 0.001))), + @"totalFrames": @((long)(length * (sampleRate * 0.001))), @"bitsPerSample": @(sizeof(short) * 8), // Samples are short @"channels": @(2), // output from gme_play is in stereo @"seekable": @(YES), @@ -176,7 +195,7 @@ gme_err_t readCallback(void *data, void *out, int count) { - (long)seek:(long)frame { gme_err_t error; - error = gme_seek(emu, frame / 44.1); + error = gme_seek(emu, frame * sampleRate * 0.001); if(error) { return -1; } diff --git a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm index f3fa72d50..a81555e1a 100644 --- a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm +++ b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm @@ -1205,8 +1205,17 @@ static int usf_info(void *context, const char *name, const char *value) { tagFadeMs = info.tag_fade_ms; if(!tagLengthMs) { - tagLengthMs = (2 * 60 + 30) * 1000; - tagFadeMs = 8000; + double defaultLength = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultSeconds"] doubleValue]; + double defaultFade = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue]; + if(defaultLength < 0) { + defaultLength = 150.0; + } + if(defaultFade < 0) { + defaultFade = 0; + } + + tagLengthMs = (int)ceil(defaultLength * 1000.0); + tagFadeMs = (int)ceil(defaultFade * 1000.0); } replayGainAlbumGain = info.albumGain; diff --git a/Plugins/Hively/Hively/HVLDecoder.h b/Plugins/Hively/Hively/HVLDecoder.h index 5196001e5..1ed05141c 100644 --- a/Plugins/Hively/Hively/HVLDecoder.h +++ b/Plugins/Hively/Hively/HVLDecoder.h @@ -17,6 +17,8 @@ int32_t *buffer; int trackNumber; + double sampleRate; + long totalFrames; long framesLength; long framesFade; diff --git a/Plugins/Hively/Hively/HVLDecoder.m b/Plugins/Hively/Hively/HVLDecoder.m index 79326fa82..d6747800b 100644 --- a/Plugins/Hively/Hively/HVLDecoder.m +++ b/Plugins/Hively/Hively/HVLDecoder.m @@ -33,10 +33,17 @@ static void oneTimeInit(void) { if(size > UINT_MAX) return NO; + sampleRate = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthSampleRate"] doubleValue]; + if(sampleRate < 8000.0) { + sampleRate = 44100.0; + } else if(sampleRate > 192000.0) { + sampleRate = 192000.0; + } + void *data = malloc(size); [s read:data amount:size]; - tune = hvl_LoadTune(data, (uint32_t)size, 44100, 2); + tune = hvl_LoadTune(data, (uint32_t)size, (int)sampleRate, 2); free(data); if(!tune) return NO; @@ -62,14 +69,19 @@ static void oneTimeInit(void) { ++loops; } - framesLength = tune->ht_PlayingTime * 44100 / (tune->ht_SpeedMultiplier * 50); - framesFade = 44100 * 8; + double defaultFade = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue]; + if(defaultFade < 0.0) { + defaultFade = 0.0; + } + + framesLength = tune->ht_PlayingTime * sampleRate / (tune->ht_SpeedMultiplier * 50); + framesFade = (int)ceil(sampleRate * defaultFade); totalFrames = framesLength + framesFade; framesRead = 0; framesInBuffer = 0; - buffer = malloc(sizeof(int32_t) * (44100 / 50) * 2); + buffer = malloc(sizeof(int32_t) * ((int)ceil(sampleRate) / 50) * 2); hvl_InitSubsong(tune, trackNumber); @@ -81,7 +93,7 @@ static void oneTimeInit(void) { - (NSDictionary *)properties { return @{ @"bitrate": @(0), - @"sampleRate": @(44100), + @"sampleRate": @(sampleRate), @"totalFrames": @(totalFrames), @"bitsPerSample": @(32), @"floatingPoint": @(YES), @@ -121,7 +133,7 @@ static void oneTimeInit(void) { } } hvl_DecodeFrame(tune, (int8_t *)buffer, ((int8_t *)buffer) + 4, 8); - framesInBuffer = 44100 / 50; + framesInBuffer = (int)ceil(sampleRate / 50); } if(!repeatone && framesRead + total > framesLength) { @@ -156,7 +168,7 @@ static void oneTimeInit(void) { while(framesRead < frame) { hvl_play_irq(tune); - framesRead += 44100 / 50; + framesRead += (int)ceil(sampleRate / 50); } return framesRead; diff --git a/Plugins/MIDI/MIDI/MIDIDecoder.h b/Plugins/MIDI/MIDI/MIDIDecoder.h index d7446d51d..3664983ef 100644 --- a/Plugins/MIDI/MIDI/MIDIDecoder.h +++ b/Plugins/MIDI/MIDI/MIDIDecoder.h @@ -30,6 +30,8 @@ class BMPlayer; BOOL soundFontsAssigned; BOOL isLooped; + double sampleRate; + long totalFrames; long framesLength; long framesFade; diff --git a/Plugins/MIDI/MIDI/MIDIDecoder.mm b/Plugins/MIDI/MIDI/MIDIDecoder.mm index 28c270e63..1da27f543 100644 --- a/Plugins/MIDI/MIDI/MIDIDecoder.mm +++ b/Plugins/MIDI/MIDI/MIDIDecoder.mm @@ -46,6 +46,13 @@ static OSType getOSType(const char *in_) { return NO; } + sampleRate = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthSampleRate"] doubleValue]; + if(sampleRate < 8000.0) { + sampleRate = 44100.0; + } else if(sampleRate > 192000.0) { + sampleRate = 192000.0; + } + source = s; std::vector file_data; @@ -76,8 +83,12 @@ static OSType getOSType(const char *in_) { if(loopStart != 0 || loopEnd != framesLength) { // two loops and a fade + double defaultFade = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue]; + if(defaultFade < 0.0) { + defaultFade = 0.0; + } framesLength = loopStart + (loopEnd - loopStart) * 2; - framesFade = 8000; + framesFade = (int)ceil(defaultFade * 1000.0); isLooped = YES; } else { framesLength += 1000; @@ -85,8 +96,8 @@ static OSType getOSType(const char *in_) { isLooped = NO; } - framesLength = framesLength * 441 / 10; - framesFade = framesFade * 441 / 10; + framesLength = (int)ceil(framesLength * sampleRate * 0.001); + framesFade = (int)ceil(framesFade * sampleRate * 0.001); totalFrames = framesLength + framesFade; @@ -100,7 +111,7 @@ static OSType getOSType(const char *in_) { - (NSDictionary *)properties { return @{ @"bitrate": @(0), - @"sampleRate": @(44100), + @"sampleRate": @(sampleRate), @"totalFrames": @(totalFrames), @"bitsPerSample": @(32), @"floatingPoint": @(YES), @@ -203,7 +214,7 @@ static OSType getOSType(const char *in_) { resamplingSinc = true; bmplayer->setSincInterpolation(resamplingSinc); - bmplayer->setSampleRate(44100); + bmplayer->setSampleRate(sampleRate); if([soundFontPath length]) bmplayer->setFileSoundFont([soundFontPath UTF8String]); @@ -219,7 +230,7 @@ static OSType getOSType(const char *in_) { msplayer->set_extp(1); - msplayer->setSampleRate(44100); + msplayer->setSampleRate(sampleRate); } else if([[plugin substringToIndex:5] isEqualToString:@"OPL3W"]) { MSPlayer *msplayer = new MSPlayer; player = msplayer; @@ -230,7 +241,7 @@ static OSType getOSType(const char *in_) { msplayer->set_extp(1); - msplayer->setSampleRate(44100); + msplayer->setSampleRate(sampleRate); } else { const char *cplugin = [plugin UTF8String]; OSType componentSubType; @@ -243,7 +254,7 @@ static OSType getOSType(const char *in_) { auplayer = new AUPlayer; auplayer->setComponent(componentSubType, componentManufacturer); - auplayer->setSampleRate(44100); + auplayer->setSampleRate(sampleRate); if([soundFontPath length]) { auplayer->setSoundFont([soundFontPath UTF8String]); diff --git a/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj b/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj index f2c23cccb..40ece74ee 100644 --- a/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj +++ b/Plugins/OpenMPT/OpenMPT.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 833A899C286FF3150022E036 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 833A899B286FF3150022E036 /* Cocoa.framework */; }; 83747C1A2862DB2F0021245F /* Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 83747C182862DB2F0021245F /* Shared.xcconfig */; }; 83E5FE731FFF010C00659F0F /* OMPTDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83E5FE6D1FFF010B00659F0F /* OMPTDecoder.mm */; }; 83E5FE741FFF010C00659F0F /* OMPTContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83E5FE6F1FFF010B00659F0F /* OMPTContainer.mm */; }; @@ -47,6 +48,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 833A899B286FF3150022E036 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 83747C182862DB2F0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83E5EFA31FFEF78100659F0F /* OpenMPT.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenMPT.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 83E5EFA61FFEF78100659F0F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -67,6 +69,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 833A899C286FF3150022E036 /* Cocoa.framework in Frameworks */, 83F30AE8286EBD2A0005EF06 /* libOpenMPT.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -113,6 +116,7 @@ 83E5EFB21FFEF79000659F0F /* Frameworks */ = { isa = PBXGroup; children = ( + 833A899B286FF3150022E036 /* Cocoa.framework */, 83F30A81286EBB420005EF06 /* libOpenMPT.xcodeproj */, ); name = Frameworks; diff --git a/Plugins/OpenMPT/OpenMPT/OMPTDecoder.h b/Plugins/OpenMPT/OpenMPT/OMPTDecoder.h index e3dc5014c..91b42d597 100644 --- a/Plugins/OpenMPT/OpenMPT/OMPTDecoder.h +++ b/Plugins/OpenMPT/OpenMPT/OMPTDecoder.h @@ -19,6 +19,8 @@ id source; long length; + + double sampleRate; } - (void)setSource:(id)s; diff --git a/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm b/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm index defce6c1a..db410f2b5 100644 --- a/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm +++ b/Plugins/OpenMPT/OpenMPT/OMPTDecoder.mm @@ -39,6 +39,13 @@ static void g_push_archive_extensions(std::vector &list) { long size = [source tell]; [source seek:0 whence:SEEK_SET]; + sampleRate = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthSampleRate"] doubleValue]; + if(sampleRate < 8000.0) { + sampleRate = 44100.0; + } else if(sampleRate > 192000.0) { + sampleRate = 192000.0; + } + std::vector data(static_cast(size)); [source read:data.data() amount:size]; @@ -71,7 +78,7 @@ static void g_push_archive_extensions(std::vector &list) { mod->select_subsong(track_num); - length = mod->get_duration_seconds() * 44100.0; + length = mod->get_duration_seconds() * sampleRate; mod->set_repeat_count(IsRepeatOneSet() ? -1 : 0); mod->set_render_param(openmpt::module::RENDER_MASTERGAIN_MILLIBEL, 0); @@ -91,7 +98,7 @@ static void g_push_archive_extensions(std::vector &list) { - (NSDictionary *)properties { return @{ @"bitrate": @(0), - @"sampleRate": @(44100), + @"sampleRate": @(sampleRate), @"totalFrames": @(length), @"bitsPerSample": @(32), @"floatingPoint": @(YES), @@ -114,7 +121,7 @@ static void g_push_archive_extensions(std::vector &list) { if(framesToRender > frames) framesToRender = frames; - std::size_t count = mod->read_interleaved_stereo(44100, framesToRender, ((float *)buf) + total * 2); + std::size_t count = mod->read_interleaved_stereo(sampleRate, framesToRender, ((float *)buf) + total * 2); if(count == 0) break; @@ -128,7 +135,7 @@ static void g_push_archive_extensions(std::vector &list) { } - (long)seek:(long)frame { - mod->set_position_seconds(frame * (1.0 / 44100.0)); + mod->set_position_seconds(frame / sampleRate); return frame; } diff --git a/Plugins/libvgmPlayer/libvgmDecoder.h b/Plugins/libvgmPlayer/libvgmDecoder.h index af3c31a23..7a70bdf8e 100644 --- a/Plugins/libvgmPlayer/libvgmDecoder.h +++ b/Plugins/libvgmPlayer/libvgmDecoder.h @@ -19,6 +19,9 @@ DATA_LOADER* dLoad; PlayerA* mainPlr; id source; + double sampleRate; + long loopCount; + double fadeTime; long length; BOOL trackEnded; } diff --git a/Plugins/libvgmPlayer/libvgmDecoder.mm b/Plugins/libvgmPlayer/libvgmDecoder.mm index 46d35de58..0c88639c4 100644 --- a/Plugins/libvgmPlayer/libvgmDecoder.mm +++ b/Plugins/libvgmPlayer/libvgmDecoder.mm @@ -88,7 +88,6 @@ static void PlayerLogCallback(void* userParam, PlayerBase* player, UINT8 level, return; } -const int sampleRate = 44100; const int numChannels = 2; const int numBitsPerSample = 24; const int smplAlloc = 2048; @@ -112,8 +111,24 @@ const int masterVol = 0x10000; // Fixed point 16.16 return NO; } + sampleRate = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthSampleRate"] doubleValue]; + if(sampleRate < 8000.0) { + sampleRate = 44100.0; + } else if(sampleRate > 192000.0) { + sampleRate = 192000.0; + } + + loopCount = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultLoopCount"] longValue]; + if(loopCount < 1) { + loopCount = 1; + } else if(loopCount > 10) { + loopCount = 10; + } + + fadeTime = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue]; + BOOL repeatOne = IsRepeatOneSet(); - uint32_t maxLoops = repeatOne ? 0 : 2; + uint32_t maxLoops = repeatOne ? 0 : (uint32_t)loopCount; mainPlr = new PlayerA; mainPlr->RegisterPlayerEngine(new VGMPlayer); @@ -127,12 +142,12 @@ const int masterVol = 0x10000; // Fixed point 16.16 PlayerA::Config pCfg = mainPlr->GetConfiguration(); pCfg.masterVol = masterVol; pCfg.loopCount = maxLoops; - pCfg.fadeSmpls = sampleRate * 4; // fade over 4 seconds + pCfg.fadeSmpls = (int)ceil(sampleRate * fadeTime); // fade over configured duration pCfg.endSilenceSmpls = sampleRate / 2; // 0.5 seconds of silence at the end pCfg.pbSpeed = 1.0; mainPlr->SetConfiguration(pCfg); } - mainPlr->SetOutputSettings(sampleRate, numChannels, numBitsPerSample, smplAlloc); + mainPlr->SetOutputSettings((int)ceil(sampleRate), numChannels, numBitsPerSample, smplAlloc); [source seek:0 whence:SEEK_END]; size_t size = [source tell]; @@ -198,7 +213,7 @@ const int masterVol = 0x10000; // Fixed point 16.16 return 0; BOOL repeatOne = IsRepeatOneSet(); - uint32_t maxLoops = repeatOne ? 0 : 2; + uint32_t maxLoops = repeatOne ? 0 : (uint32_t)loopCount; PlayerBase* player = mainPlr->GetPlayer(); mainPlr->SetLoopCount(maxLoops); diff --git a/Plugins/sidplay/SidDecoder.h b/Plugins/sidplay/SidDecoder.h index 11c2ff0f4..d7e4776e1 100644 --- a/Plugins/sidplay/SidDecoder.h +++ b/Plugins/sidplay/SidDecoder.h @@ -29,6 +29,8 @@ NSString *currentUrl; BOOL hintAdded; + double sampleRate; + int n_channels; long renderedTotal; diff --git a/Plugins/sidplay/SidDecoder.mm b/Plugins/sidplay/SidDecoder.mm index 7998aa3a6..7c18ca2d8 100644 --- a/Plugins/sidplay/SidDecoder.mm +++ b/Plugins/sidplay/SidDecoder.mm @@ -166,6 +166,13 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) [self setSource:s]; + sampleRate = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthSampleRate"] doubleValue]; + if(sampleRate < 8000.0) { + sampleRate = 44100.0; + } else if(sampleRate > 192000.0) { + sampleRate = 192000.0; + } + NSString *path = [[s url] absoluteString]; NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch]; if(fragmentRange.location != NSNotFound) { @@ -195,7 +202,9 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) n_channels = 1; - length = 3 * 60 * 44100; + double defaultLength = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultSeconds"] doubleValue]; + + length = (int)ceil(sampleRate * defaultLength); tune->selectSong(track_num); @@ -224,7 +233,7 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) const SidTuneInfo *tuneInfo = tune->getInfo(); SidConfig conf = engine->config(); - conf.frequency = 44100; + conf.frequency = (int)ceil(sampleRate); conf.sidEmulation = builder; conf.playback = SidConfig::MONO; if(tuneInfo && (tuneInfo->sidChips() > 1)) @@ -236,8 +245,13 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) n_channels = 2; } + double defaultFade = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue]; + if(defaultFade < 0.0) { + defaultFade = 0.0; + } + renderedTotal = 0; - fadeTotal = fadeRemain = 44100 * 8; + fadeTotal = fadeRemain = (int)ceil(sampleRate * defaultFade); [self willChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"]; @@ -247,7 +261,7 @@ static void sidTuneLoader(const char *fileName, std::vector &bufferRef) - (NSDictionary *)properties { return @{ @"bitrate": @(0), - @"sampleRate": @(44100), + @"sampleRate": @(sampleRate), @"totalFrames": @(length), @"bitsPerSample": @(16), @"floatingPoint": @(NO), diff --git a/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj b/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj index 60954d4e9..378653b9a 100644 --- a/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj +++ b/Plugins/sidplay/sidplay.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 8314D8091A35654900EEE8E6 /* SidDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8314D8041A35654900EEE8E6 /* SidDecoder.mm */; }; 8314D80A1A35654900EEE8E6 /* SidMetadataReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8314D8061A35654900EEE8E6 /* SidMetadataReader.mm */; }; 8314D80B1A35654900EEE8E6 /* SidContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8314D8081A35654900EEE8E6 /* SidContainer.mm */; }; + 833A8998286FF2E30022E036 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 833A8996286FF2E30022E036 /* Cocoa.framework */; }; 836F5BEC1A357915002730CC /* roms.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 836F5BEA1A357915002730CC /* roms.cpp */; }; 83747C012862DA420021245F /* Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 83747BFF2862DA420021245F /* Shared.xcconfig */; }; EDBE911825E7EA01001EB4A4 /* sidplayfp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDBE8F0F25E7E74D001EB4A4 /* sidplayfp.framework */; }; @@ -51,6 +52,7 @@ 8314D80C1A35657700EEE8E6 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../../Audio/Plugin.h; sourceTree = ""; }; 8314D80D1A35658C00EEE8E6 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../../Utils/Logging.h; sourceTree = ""; }; 8314D80E1A3565AC00EEE8E6 /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../../Playlist/PlaylistController.h; sourceTree = ""; }; + 833A8996286FF2E30022E036 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 836F5BEA1A357915002730CC /* roms.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = roms.cpp; sourceTree = SOURCE_ROOT; }; 836F5BEB1A357915002730CC /* roms.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = roms.hpp; sourceTree = SOURCE_ROOT; }; 83747BFF2862DA420021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; @@ -62,6 +64,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 833A8998286FF2E30022E036 /* Cocoa.framework in Frameworks */, EDBE911825E7EA01001EB4A4 /* sidplayfp.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -117,6 +120,7 @@ 8314D64A1A354E4400EEE8E6 /* Frameworks */ = { isa = PBXGroup; children = ( + 833A8996286FF2E30022E036 /* Cocoa.framework */, EDBE8F0A25E7E74D001EB4A4 /* sidplayfp.xcodeproj */, ); name = Frameworks; diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.h b/Plugins/vgmstream/vgmstream/VGMDecoder.h index 20931edbd..0232f4808 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.h +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.h @@ -30,6 +30,8 @@ BOOL playForever; BOOL canPlayForever; + int loopCount; + double fadeTime; int sampleRate; int channels; int bitrate; diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.m b/Plugins/vgmstream/vgmstream/VGMDecoder.m index 9b39613b0..78ba9ac25 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.m +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.m @@ -234,6 +234,18 @@ static NSString *get_description_tag(const char *description, const char *tag, c - (BOOL)open:(id)s { int track_num = [[[s url] fragment] intValue]; + loopCount = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultLoopCount"] intValue]; + if(loopCount < 1) { + loopCount = 1; + } else if(loopCount > 10) { + loopCount = 10; + } + + fadeTime = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeTime"] doubleValue]; + if(fadeTime < 0.0) { + fadeTime = 0.0; + } + NSString *path = [[s url] absoluteString]; NSRange fragmentRange = [path rangeOfString:@"#" options:NSBackwardsSearch]; if(fragmentRange.location != NSNotFound) { @@ -262,8 +274,8 @@ static NSString *get_description_tag(const char *description, const char *tag, c vcfg.allow_play_forever = 1; vcfg.play_forever = playForever; - vcfg.loop_count = 2; - vcfg.fade_time = 10; + vcfg.loop_count = loopCount; + vcfg.fade_time = fadeTime; vcfg.fade_delay = 0; vcfg.ignore_loop = 0; diff --git a/Preferences/Preferences/Base.lproj/Preferences.xib b/Preferences/Preferences/Base.lproj/Preferences.xib index 3fd534d11..f5821f567 100644 --- a/Preferences/Preferences/Base.lproj/Preferences.xib +++ b/Preferences/Preferences/Base.lproj/Preferences.xib @@ -592,11 +592,11 @@ - + - + @@ -616,7 +616,7 @@ - + @@ -633,7 +633,7 @@ - + @@ -642,7 +642,7 @@ - + @@ -651,7 +651,7 @@ - + @@ -672,7 +672,7 @@ - + @@ -681,7 +681,7 @@ - + @@ -702,7 +702,7 @@ - + @@ -722,8 +722,138 @@ + + + + + + + + + + + + + + + + + + + + + TimeIntervalToStringTransformer + + + + + + + + + + + + + + + + TimeIntervalToStringTransformer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Preferences/Preferences/GeneralPreferencesPlugin.m b/Preferences/Preferences/GeneralPreferencesPlugin.m index 93ff07cd7..2064e63ab 100644 --- a/Preferences/Preferences/GeneralPreferencesPlugin.m +++ b/Preferences/Preferences/GeneralPreferencesPlugin.m @@ -9,6 +9,7 @@ #import "GeneralPreferencesPlugin.h" #import "ColorToValueTransformer.h" #import "PathToFileTransformer.h" +#import "TimeIntervalToStringTransformer.h" @implementation GeneralPreferencesPlugin @@ -20,6 +21,10 @@ NSValueTransformer *colorToValueTransformer = [[ColorToValueTransformer alloc] init]; [NSValueTransformer setValueTransformer:colorToValueTransformer forName:@"ColorToValueTransformer"]; + + NSValueTransformer *timeIntervalToStringTransformer = [[TimeIntervalToStringTransformer alloc] init]; + [NSValueTransformer setValueTransformer:timeIntervalToStringTransformer + forName:@"TimeIntervalToStringTransformer"]; } + (NSArray *)preferencePanes { diff --git a/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj b/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj index 5530aba55..4cbc84040 100644 --- a/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj +++ b/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 8307D31728606EAF000FF8EB /* growl@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8307D31328606EAF000FF8EB /* growl@2x.png */; }; 8307D31828606EAF000FF8EB /* general.png in Resources */ = {isa = PBXBuildFile; fileRef = 8307D31428606EAF000FF8EB /* general.png */; }; 8307D31928606EAF000FF8EB /* growl.png in Resources */ = {isa = PBXBuildFile; fileRef = 8307D31528606EAF000FF8EB /* growl.png */; }; + 833A899F286FF3850022E036 /* TimeIntervalToStringTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 833A899E286FF3850022E036 /* TimeIntervalToStringTransformer.m */; }; 83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */; }; 8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */; }; 837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */; }; @@ -102,6 +103,8 @@ 8307D31328606EAF000FF8EB /* growl@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "growl@2x.png"; path = "Icons/growl@2x.png"; sourceTree = ""; }; 8307D31428606EAF000FF8EB /* general.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = general.png; path = Icons/general.png; sourceTree = ""; }; 8307D31528606EAF000FF8EB /* growl.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = growl.png; path = Icons/growl.png; sourceTree = ""; }; + 833A899D286FF3850022E036 /* TimeIntervalToStringTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TimeIntervalToStringTransformer.h; sourceTree = ""; }; + 833A899E286FF3850022E036 /* TimeIntervalToStringTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TimeIntervalToStringTransformer.m; sourceTree = ""; }; 833F681B1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; 833F681C1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 8347435D20E6D58800063D45 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Preferences.strings; sourceTree = ""; }; @@ -313,6 +316,8 @@ 83F27E731810E45D00CEF538 /* PathToFileTransformer.m */, 83A3B72A283AE04800CC6593 /* ColorToValueTransformer.h */, 83A3B72B283AE04800CC6593 /* ColorToValueTransformer.m */, + 833A899D286FF3850022E036 /* TimeIntervalToStringTransformer.h */, + 833A899E286FF3850022E036 /* TimeIntervalToStringTransformer.m */, ); name = Transformers; sourceTree = ""; @@ -487,6 +492,7 @@ 83A3B72C283AE04800CC6593 /* ColorToValueTransformer.m in Sources */, 837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */, 17C6433F0B8A783F00C53518 /* OutputPane.m in Sources */, + 833A899F286FF3850022E036 /* TimeIntervalToStringTransformer.m in Sources */, 99F1813F0DE01D7A00FD5FFB /* PlaylistBehaviorArrayController.m in Sources */, 8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */, ); diff --git a/Preferences/Preferences/TimeIntervalToStringTransformer.h b/Preferences/Preferences/TimeIntervalToStringTransformer.h new file mode 100644 index 000000000..6c1dd7cca --- /dev/null +++ b/Preferences/Preferences/TimeIntervalToStringTransformer.h @@ -0,0 +1,16 @@ +// +// TimeIntervalToStringTransformer.h +// Preferences +// +// Created by Christopher Snowhill on 7/1/22. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface TimeIntervalToStringTransformer : NSValueTransformer + +@end + +NS_ASSUME_NONNULL_END diff --git a/Preferences/Preferences/TimeIntervalToStringTransformer.m b/Preferences/Preferences/TimeIntervalToStringTransformer.m new file mode 100644 index 000000000..ee4975259 --- /dev/null +++ b/Preferences/Preferences/TimeIntervalToStringTransformer.m @@ -0,0 +1,63 @@ +// +// TimeIntervalToStringTransformer.m +// Preferences +// +// Created by Christopher Snowhill on 7/1/22. +// + +#import "TimeIntervalToStringTransformer.h" + +#import + +@implementation TimeIntervalToStringTransformer ++ (Class)transformedValueClass { + return [NSString class]; +} ++ (BOOL)allowsReverseTransformation { + return YES; +} + +// Convert from string to NSURL +- (id)reverseTransformedValue:(id)value { + if(value == nil) return nil; + + if([value isKindOfClass:[NSString class]]) { + NSString *theString = (NSString *)value; + + NSArray *components = [theString componentsSeparatedByString:@":"]; + + double interval = 0.0; + + for(size_t i = 0, j = [components count]; i < j; ++i) { + interval += ([components[j - i - 1] doubleValue]) * pow(60.0, i); + } + + return @(interval); + } + + return nil; +} + +- (id)transformedValue:(id)value { + if(value == nil) return @""; + + if([value isKindOfClass:[NSNumber class]]) { + NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init]; + [formatter setAllowedUnits:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond]; + double secondsValue = [value doubleValue]; + double fractionValue = fmod(secondsValue, 1.0); + secondsValue = (double)(int)secondsValue; + NSString *wholePart = [formatter stringFromTimeInterval:(NSTimeInterval)secondsValue]; + NSUInteger fractionMillis = (int)(fractionValue * 1000.0); + if(fractionMillis >= 1) { + NSString *fractionPart = [NSString stringWithFormat:@".%03lu", fractionMillis]; + fractionPart = [fractionPart stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithRange:NSMakeRange('0', 1)]]; + return [wholePart stringByAppendingString:fractionPart]; + } + return wholePart; + } + + return @""; +} + +@end diff --git a/Preferences/Preferences/en.lproj/Preferences.strings b/Preferences/Preferences/en.lproj/Preferences.strings index a8ed1973a..dd1dff5d8 100644 --- a/Preferences/Preferences/en.lproj/Preferences.strings +++ b/Preferences/Preferences/en.lproj/Preferences.strings @@ -11,18 +11,6 @@ /* Class = "NSMenuItem"; title = "Item3"; ObjectID = "64"; */ "64.title" = "Item3"; -/* Class = "NSMenu"; title = "OtherViews"; ObjectID = "107"; */ -"107.title" = "OtherViews"; - -/* Class = "NSMenuItem"; title = "Stable"; ObjectID = "108"; */ -"108.title" = "Stable"; - -/* Class = "NSMenuItem"; title = "Unstable"; ObjectID = "109"; */ -"109.title" = "Unstable"; - -/* Class = "NSMenuItem"; title = "Nightly"; ObjectID = "110"; */ -"110.title" = "Nightly"; - /* Class = "NSTextFieldCell"; title = "Play:"; ObjectID = "198"; */ "198.title" = "Play:"; @@ -35,9 +23,6 @@ /* Class = "NSButtonCell"; title = "Automatically check for updates on startup"; ObjectID = "207"; */ "207.title" = "Automatically check for updates on startup"; -/* Class = "NSTextFieldCell"; title = "Update Feed:"; ObjectID = "209"; */ -"209.title" = "Update Feed:"; - /* Class = "NSTextFieldCell"; title = "Output Device: "; ObjectID = "211"; */ "211.title" = "Output Device: "; @@ -80,15 +65,9 @@ /* Class = "NSMenuItem"; title = "Item 2"; ObjectID = "1Yq-6f-Uho"; */ "1Yq-6f-Uho.title" = "Item 2"; -/* Class = "NSButtonCell"; title = "Enable Last.fm support (Last.fm client must be installed)"; ObjectID = "2N5-DH-IO6"; */ -"2N5-DH-IO6.title" = "Enable Last.fm support (Last.fm client must be installed)"; - /* Class = "NSMenuItem"; title = "Item 1"; ObjectID = "3Gx-cs-3B0"; */ "3Gx-cs-3B0.title" = "Item 1"; -/* Class = "NSButtonCell"; title = "Allow Last.fm client to control media keys"; ObjectID = "4Yi-67-ivc"; */ -"4Yi-67-ivc.title" = "Allow Last.fm client to control media keys"; - /* Class = "NSMenuItem"; title = "Item 2"; ObjectID = "99B-Tx-dPH"; */ "99B-Tx-dPH.title" = "Item 2"; @@ -164,5 +143,86 @@ /* Class = "NSButtonCell"; title = "Select a SoundFont"; ObjectID = "yeL-9c-lFq"; */ "yeL-9c-lFq.title" = "Select a SoundFont"; -/* Class = "NSButtonCell"; title = "Automatically launch Last.fm client"; ObjectID = "ze8-9p-SeX"; */ -"ze8-9p-SeX.title" = "Automatically launch Last.fm client"; +/* Class = "NSTextFieldCell"; title = "Hz"; ObjectID = "0Am-5Y-EKq"; */ +"0Am-5Y-EKq.title" = "Hz"; + +/* Class = "NSButtonCell"; title = "Reset to defaults"; ObjectID = "1y7-iZ-BhE"; */ +"1y7-iZ-BhE.title" = "Reset to defaults"; + +/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "7un-em-D8r"; */ +"7un-em-D8r.title" = "Table View Cell"; + +/* Class = "NSTextFieldCell"; title = "Sample rate:"; ObjectID = "A9I-fr-vHp"; */ +"A9I-fr-vHp.title" = "Sample rate:"; + +/* Class = "NSTextFieldCell"; title = "Default play time:"; ObjectID = "AQZ-ku-F8u"; */ +"AQZ-ku-F8u.title" = "Default play time:"; + +/* Class = "NSTextFieldCell"; title = "Spectrum bars"; ObjectID = "Bll-IJ-lje"; */ +"Bll-IJ-lje.title" = "Spectrum bars"; + +/* Class = "NSTextFieldCell"; title = "Spectrum peaks"; ObjectID = "CQI-YZ-B3V"; */ +"CQI-YZ-B3V.title" = "Spectrum peaks"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "Dhd-k8-ZXq"; */ +"Dhd-k8-ZXq.title" = "Text Cell"; + +/* Class = "NSTextFieldCell"; title = "Default loop count:"; ObjectID = "Fgm-Vs-tgU"; */ +"Fgm-Vs-tgU.title" = "Default loop count:"; + +/* Class = "NSMenuItem"; title = "Delete Invalid Paths"; ObjectID = "JU5-o7-jid"; */ +"JU5-o7-jid.title" = "Delete Invalid Paths"; + +/* Class = "NSMenuItem"; title = "Add Path"; ObjectID = "JxP-0t-mTB"; */ +"JxP-0t-mTB.title" = "Add Path"; + +/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "LwT-Qb-47r"; */ +"LwT-Qb-47r.title" = "Table View Cell"; + +/* Class = "NSTextFieldCell"; title = "(will be preferred if possible)"; ObjectID = "POG-ai-6D2"; */ +"POG-ai-6D2.title" = "(will be preferred if possible)"; + +/* Class = "NSButtonCell"; title = "Quit when playback completes"; ObjectID = "SBA-J5-rEd"; */ +"SBA-J5-rEd.title" = "Quit when playback completes"; + +/* Class = "NSTextFieldCell"; title = "Default fade time:"; ObjectID = "UdW-qd-A0x"; */ +"UdW-qd-A0x.title" = "Default fade time:"; + +/* Class = "NSTableColumn"; headerCell.title = "Path"; ObjectID = "Yz2-Ee-bZ0"; */ +"Yz2-Ee-bZ0.headerCell.title" = "Path"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "bWQ-dT-X3w"; */ +"bWQ-dT-X3w.title" = "Text Cell"; + +/* Class = "NSButtonCell"; title = "Limit volume control to 100%"; ObjectID = "ds2-aw-ebU"; */ +"ds2-aw-ebU.title" = "Limit volume control to 100%"; + +/* Class = "NSButtonCell"; title = "Spectrum 2D view"; ObjectID = "gXL-j6-df0"; */ +"gXL-j6-df0.title" = "Spectrum 2D view"; + +/* Class = "NSTextFieldCell"; title = "hh:mm:ss.ms"; ObjectID = "klv-Wh-0ur"; */ +"klv-Wh-0ur.title" = "hh:mm:ss.ms"; + +/* Class = "NSTextFieldCell"; title = "hh:mm:ss.ms"; ObjectID = "zaI-0m-tQf"; */ +"zaI-0m-tQf.title" = "hh:mm:ss.ms"; + +/* Class = "NSTableColumn"; headerCell.title = "Valid"; ObjectID = "lEg-E3-TBs"; */ +"lEg-E3-TBs.headerCell.title" = "Valid"; + +/* Class = "NSMenuItem"; title = "Delete Path"; ObjectID = "nva-pz-xSS"; */ +"nva-pz-xSS.title" = "Delete Path"; + +/* Class = "NSMenuItem"; title = "Suggest Paths"; ObjectID = "qjI-dK-nfG"; */ +"qjI-dK-nfG.title" = "Suggest Paths"; + +/* Class = "NSButtonCell"; title = "Allow insecure SSL connections"; ObjectID = "sva-DV-ina"; */ +"sva-DV-ina.title" = "Allow insecure SSL connections"; + +/* Class = "NSButtonCell"; title = "Show stop button"; ObjectID = "vMI-lj-Lrz"; */ +"vMI-lj-Lrz.title" = "Show stop button"; + +/* Class = "NSTextFieldCell"; title = "Folder access paths:"; ObjectID = "wWm-AD-cD4"; */ +"wWm-AD-cD4.title" = "Folder access paths:"; + +/* Class = "NSButtonCell"; title = "Send crash reports and usage data"; ObjectID = "zQ2-6O-3Og"; */ +"zQ2-6O-3Og.title" = "Send crash reports and usage data"; diff --git a/Preferences/Preferences/es.lproj/Preferences.strings b/Preferences/Preferences/es.lproj/Preferences.strings index c1a4a4de6..815f4ff6e 100644 --- a/Preferences/Preferences/es.lproj/Preferences.strings +++ b/Preferences/Preferences/es.lproj/Preferences.strings @@ -199,3 +199,44 @@ /* Class = "NSButtonCell"; title = "Send crash reports and usage data"; ObjectID = "zQ2-6O-3Og"; */ "zQ2-6O-3Og.title" = "Enviar informes de fallas y datos de uso"; +/* Class = "NSTextFieldCell"; title = "Default loop count:"; ObjectID = "Fgm-Vs-tgU"; */ +"Fgm-Vs-tgU.title" = "Default loop count:"; + +/* Class = "NSTextFieldCell"; title = "Hz"; ObjectID = "0Am-5Y-EKq"; */ +"0Am-5Y-EKq.title" = "Hz"; + +/* Class = "NSMenuItem"; title = "Item 3"; ObjectID = "1Cb-TU-E0q"; */ +"1Cb-TU-E0q.title" = "Item 3"; + +/* Class = "NSMenuItem"; title = "Item 2"; ObjectID = "1Yq-6f-Uho"; */ +"1Yq-6f-Uho.title" = "Item 2"; + +/* Class = "NSButtonCell"; title = "Reset to defaults"; ObjectID = "1y7-iZ-BhE"; */ +"1y7-iZ-BhE.title" = "Reset to defaults"; + +/* Class = "NSMenuItem"; title = "Item 1"; ObjectID = "3Gx-cs-3B0"; */ +"3Gx-cs-3B0.title" = "Item 1"; + +/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "7un-em-D8r"; */ +"7un-em-D8r.title" = "Celda de vista de tabla"; + +/* Class = "NSMenuItem"; title = "Item 2"; ObjectID = "99B-Tx-dPH"; */ +"99B-Tx-dPH.title" = "Item 2"; + +/* Class = "NSTextFieldCell"; title = "Sample rate:"; ObjectID = "A9I-fr-vHp"; */ +"A9I-fr-vHp.title" = "Sample rate:"; + +/* Class = "NSTextFieldCell"; title = "Default play time:"; ObjectID = "AQZ-ku-F8u"; */ +"AQZ-ku-F8u.title" = "Default play time:"; + +/* Class = "NSTextFieldCell"; title = "(will be preferred if possible)"; ObjectID = "POG-ai-6D2"; */ +"POG-ai-6D2.title" = "(will be preferred if possible)"; + +/* Class = "NSTextFieldCell"; title = "Default fade time:"; ObjectID = "UdW-qd-A0x"; */ +"UdW-qd-A0x.title" = "Default fade time:"; + +/* Class = "NSTextFieldCell"; title = "hh:mm:ss.ms"; ObjectID = "klv-Wh-0ur"; */ +"klv-Wh-0ur.title" = "hh:mm:ss.ms"; + +/* Class = "NSTextFieldCell"; title = "hh:mm:ss.ms"; ObjectID = "zaI-0m-tQf"; */ +"zaI-0m-tQf.title" = "hh:mm:ss.ms";