Cocoa Port:
- Refactor audio playback code for better code modularity. - Improve overall performance of audio playback. - Fix compile issue with the legacy build. - Add a method for setting the emulator core's file paths directly by using a dictionary. This method can be used as an alternative to reading FileTypeInfo.plist. - Add file handling support for the upcoming OpenEmu Plug-in build target.
This commit is contained in:
parent
ab53131bd8
commit
8a7fd2445f
|
@ -392,6 +392,14 @@
|
||||||
ABBF053114B5436E00E505A0 /* cocoa_file.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABBF052F14B5436E00E505A0 /* cocoa_file.mm */; };
|
ABBF053114B5436E00E505A0 /* cocoa_file.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABBF052F14B5436E00E505A0 /* cocoa_file.mm */; };
|
||||||
ABBF053214B5436E00E505A0 /* cocoa_file.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABBF052F14B5436E00E505A0 /* cocoa_file.mm */; };
|
ABBF053214B5436E00E505A0 /* cocoa_file.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABBF052F14B5436E00E505A0 /* cocoa_file.mm */; };
|
||||||
ABBF053314B5436E00E505A0 /* cocoa_file.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABBF052F14B5436E00E505A0 /* cocoa_file.mm */; };
|
ABBF053314B5436E00E505A0 /* cocoa_file.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABBF052F14B5436E00E505A0 /* cocoa_file.mm */; };
|
||||||
|
ABD0A5661501AC5C0074A094 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5621501AC5C0074A094 /* coreaudiosound.cpp */; };
|
||||||
|
ABD0A5671501AC5C0074A094 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5631501AC5C0074A094 /* ringbuffer.cpp */; };
|
||||||
|
ABD0A5681501AC5C0074A094 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5621501AC5C0074A094 /* coreaudiosound.cpp */; };
|
||||||
|
ABD0A5691501AC5C0074A094 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5631501AC5C0074A094 /* ringbuffer.cpp */; };
|
||||||
|
ABD0A56A1501AC5C0074A094 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5621501AC5C0074A094 /* coreaudiosound.cpp */; };
|
||||||
|
ABD0A56B1501AC5C0074A094 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5631501AC5C0074A094 /* ringbuffer.cpp */; };
|
||||||
|
ABD0A56C1501AC5C0074A094 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5621501AC5C0074A094 /* coreaudiosound.cpp */; };
|
||||||
|
ABD0A56D1501AC5C0074A094 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5631501AC5C0074A094 /* ringbuffer.cpp */; };
|
||||||
ABE240FF14BE3169006EA2D5 /* cocoa_input_legacy.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABE240F414BE3169006EA2D5 /* cocoa_input_legacy.mm */; };
|
ABE240FF14BE3169006EA2D5 /* cocoa_input_legacy.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABE240F414BE3169006EA2D5 /* cocoa_input_legacy.mm */; };
|
||||||
ABE2410014BE3169006EA2D5 /* input_legacy.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABE240F614BE3169006EA2D5 /* input_legacy.mm */; };
|
ABE2410014BE3169006EA2D5 /* input_legacy.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABE240F614BE3169006EA2D5 /* input_legacy.mm */; };
|
||||||
ABE2410114BE3169006EA2D5 /* nds_control_legacy.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABE240F814BE3169006EA2D5 /* nds_control_legacy.mm */; };
|
ABE2410114BE3169006EA2D5 /* nds_control_legacy.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABE240F814BE3169006EA2D5 /* nds_control_legacy.mm */; };
|
||||||
|
@ -787,6 +795,10 @@
|
||||||
ABBF04CD14B51BC900E505A0 /* Romanian */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Romanian; path = translations/Romanian.lproj/Localizable.strings; sourceTree = "<group>"; };
|
ABBF04CD14B51BC900E505A0 /* Romanian */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Romanian; path = translations/Romanian.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
ABBF052F14B5436E00E505A0 /* cocoa_file.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_file.mm; sourceTree = "<group>"; };
|
ABBF052F14B5436E00E505A0 /* cocoa_file.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_file.mm; sourceTree = "<group>"; };
|
||||||
ABBF053B14B543B600E505A0 /* cocoa_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_file.h; sourceTree = "<group>"; };
|
ABBF053B14B543B600E505A0 /* cocoa_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_file.h; sourceTree = "<group>"; };
|
||||||
|
ABD0A5621501AC5C0074A094 /* coreaudiosound.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = coreaudiosound.cpp; sourceTree = "<group>"; };
|
||||||
|
ABD0A5631501AC5C0074A094 /* ringbuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ringbuffer.cpp; sourceTree = "<group>"; };
|
||||||
|
ABD0A5641501AC5C0074A094 /* coreaudiosound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coreaudiosound.h; sourceTree = "<group>"; };
|
||||||
|
ABD0A5651501AC5C0074A094 /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ringbuffer.h; sourceTree = "<group>"; };
|
||||||
ABE240E514BE30FC006EA2D5 /* Info (Legacy Debug).plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info (Legacy Debug).plist"; sourceTree = "<group>"; };
|
ABE240E514BE30FC006EA2D5 /* Info (Legacy Debug).plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info (Legacy Debug).plist"; sourceTree = "<group>"; };
|
||||||
ABE240E614BE30FC006EA2D5 /* Info (Legacy).plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info (Legacy).plist"; sourceTree = "<group>"; };
|
ABE240E614BE30FC006EA2D5 /* Info (Legacy).plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info (Legacy).plist"; sourceTree = "<group>"; };
|
||||||
ABE240F314BE3169006EA2D5 /* cocoa_input_legacy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_input_legacy.h; sourceTree = "<group>"; };
|
ABE240F314BE3169006EA2D5 /* cocoa_input_legacy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_input_legacy.h; sourceTree = "<group>"; };
|
||||||
|
@ -870,15 +882,19 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
ABC3ADEC14B7DC6E00D5B13D /* userinterface */,
|
ABC3ADEC14B7DC6E00D5B13D /* userinterface */,
|
||||||
|
ABD0A5621501AC5C0074A094 /* coreaudiosound.cpp */,
|
||||||
|
ABD0A5631501AC5C0074A094 /* ringbuffer.cpp */,
|
||||||
ABF4007E14B4F1C000578AE7 /* sndOSX.cpp */,
|
ABF4007E14B4F1C000578AE7 /* sndOSX.cpp */,
|
||||||
ABBF053B14B543B600E505A0 /* cocoa_file.h */,
|
ABBF053B14B543B600E505A0 /* cocoa_file.h */,
|
||||||
ABF95B4714B4F4FC007912B8 /* cocoa_globals.h */,
|
ABF95B4714B4F4FC007912B8 /* cocoa_globals.h */,
|
||||||
ABE240F314BE3169006EA2D5 /* cocoa_input_legacy.h */,
|
ABE240F314BE3169006EA2D5 /* cocoa_input_legacy.h */,
|
||||||
AB8FE37414B652EC009E20B1 /* cocoa_util.h */,
|
AB8FE37414B652EC009E20B1 /* cocoa_util.h */,
|
||||||
|
ABD0A5641501AC5C0074A094 /* coreaudiosound.h */,
|
||||||
ABE240F514BE3169006EA2D5 /* input_legacy.h */,
|
ABE240F514BE3169006EA2D5 /* input_legacy.h */,
|
||||||
AB8FE30A14B647D6009E20B1 /* macosx_10_4_compat.h */,
|
AB8FE30A14B647D6009E20B1 /* macosx_10_4_compat.h */,
|
||||||
ABE240F714BE3169006EA2D5 /* nds_control_legacy.h */,
|
ABE240F714BE3169006EA2D5 /* nds_control_legacy.h */,
|
||||||
ABE240F914BE3169006EA2D5 /* preferences_legacy.h */,
|
ABE240F914BE3169006EA2D5 /* preferences_legacy.h */,
|
||||||
|
ABD0A5651501AC5C0074A094 /* ringbuffer.h */,
|
||||||
ABE240FB14BE3169006EA2D5 /* screen_state_legacy.h */,
|
ABE240FB14BE3169006EA2D5 /* screen_state_legacy.h */,
|
||||||
AB06CB49135B8A4D00E977B3 /* sndOSX.h */,
|
AB06CB49135B8A4D00E977B3 /* sndOSX.h */,
|
||||||
ABE240FD14BE3169006EA2D5 /* video_output_view_legacy.h */,
|
ABE240FD14BE3169006EA2D5 /* video_output_view_legacy.h */,
|
||||||
|
@ -1744,6 +1760,8 @@
|
||||||
ABE2410E14BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
ABE2410E14BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||||
ABE2410F14BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
ABE2410F14BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||||
ABE2411014BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
ABE2411014BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||||
|
ABD0A5681501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||||
|
ABD0A5691501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1851,6 +1869,8 @@
|
||||||
ABE2411414BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
ABE2411414BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||||
ABE2411514BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
ABE2411514BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||||
ABE2411614BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
ABE2411614BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||||
|
ABD0A56C1501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||||
|
ABD0A56D1501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1958,6 +1978,8 @@
|
||||||
ABE2410214BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
ABE2410214BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||||
ABE2410314BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
ABE2410314BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||||
ABE2410414BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
ABE2410414BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||||
|
ABD0A5661501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||||
|
ABD0A5671501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -2065,6 +2087,8 @@
|
||||||
ABE2410814BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
ABE2410814BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||||
ABE2410914BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
ABE2410914BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||||
ABE2410A14BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
ABE2410A14BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||||
|
ABD0A56A1501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||||
|
ABD0A56B1501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -296,6 +296,10 @@
|
||||||
ABC5720D1344346600E7B0B1 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97324FDCFA39411CA2CEA /* AppKit.framework */; };
|
ABC5720D1344346600E7B0B1 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97324FDCFA39411CA2CEA /* AppKit.framework */; };
|
||||||
ABC572101344347000E7B0B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97325FDCFA39411CA2CEA /* Foundation.framework */; };
|
ABC572101344347000E7B0B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97325FDCFA39411CA2CEA /* Foundation.framework */; };
|
||||||
ABC719E2138CB25E002827A9 /* DefaultKeyMappings.plist in Resources */ = {isa = PBXBuildFile; fileRef = ABC719E1138CB25E002827A9 /* DefaultKeyMappings.plist */; };
|
ABC719E2138CB25E002827A9 /* DefaultKeyMappings.plist in Resources */ = {isa = PBXBuildFile; fileRef = ABC719E1138CB25E002827A9 /* DefaultKeyMappings.plist */; };
|
||||||
|
ABD0A5381501AA5A0074A094 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5341501AA5A0074A094 /* coreaudiosound.cpp */; };
|
||||||
|
ABD0A5391501AA5A0074A094 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5351501AA5A0074A094 /* ringbuffer.cpp */; };
|
||||||
|
ABD0A53A1501AA5A0074A094 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5341501AA5A0074A094 /* coreaudiosound.cpp */; };
|
||||||
|
ABD0A53B1501AA5A0074A094 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD0A5351501AA5A0074A094 /* ringbuffer.cpp */; };
|
||||||
ABD1041C1346652500AF11D1 /* cocoa_input.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD104111346652500AF11D1 /* cocoa_input.mm */; };
|
ABD1041C1346652500AF11D1 /* cocoa_input.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD104111346652500AF11D1 /* cocoa_input.mm */; };
|
||||||
ABD1041D1346652500AF11D1 /* cocoa_core.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD104121346652500AF11D1 /* cocoa_core.mm */; };
|
ABD1041D1346652500AF11D1 /* cocoa_core.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD104121346652500AF11D1 /* cocoa_core.mm */; };
|
||||||
ABD1041E1346652500AF11D1 /* cocoa_rom.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD104131346652500AF11D1 /* cocoa_rom.mm */; };
|
ABD1041E1346652500AF11D1 /* cocoa_rom.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABD104131346652500AF11D1 /* cocoa_rom.mm */; };
|
||||||
|
@ -530,6 +534,10 @@
|
||||||
ABC570D0134431CE00E7B0B1 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
|
ABC570D0134431CE00E7B0B1 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
|
||||||
ABC570D4134431DA00E7B0B1 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
ABC570D4134431DA00E7B0B1 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||||
ABC719E1138CB25E002827A9 /* DefaultKeyMappings.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DefaultKeyMappings.plist; sourceTree = "<group>"; };
|
ABC719E1138CB25E002827A9 /* DefaultKeyMappings.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DefaultKeyMappings.plist; sourceTree = "<group>"; };
|
||||||
|
ABD0A5341501AA5A0074A094 /* coreaudiosound.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = coreaudiosound.cpp; sourceTree = "<group>"; };
|
||||||
|
ABD0A5351501AA5A0074A094 /* ringbuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ringbuffer.cpp; sourceTree = "<group>"; };
|
||||||
|
ABD0A5361501AA5A0074A094 /* coreaudiosound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coreaudiosound.h; sourceTree = "<group>"; };
|
||||||
|
ABD0A5371501AA5A0074A094 /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ringbuffer.h; sourceTree = "<group>"; };
|
||||||
ABD103FE1346652500AF11D1 /* cocoa_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_core.h; sourceTree = "<group>"; };
|
ABD103FE1346652500AF11D1 /* cocoa_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_core.h; sourceTree = "<group>"; };
|
||||||
ABD103FF1346652500AF11D1 /* cocoa_input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_input.h; sourceTree = "<group>"; };
|
ABD103FF1346652500AF11D1 /* cocoa_input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_input.h; sourceTree = "<group>"; };
|
||||||
ABD104001346652500AF11D1 /* cocoa_rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_rom.h; sourceTree = "<group>"; };
|
ABD104001346652500AF11D1 /* cocoa_rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_rom.h; sourceTree = "<group>"; };
|
||||||
|
@ -776,6 +784,8 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
AB3ACB6514C2361100D7D192 /* userinterface */,
|
AB3ACB6514C2361100D7D192 /* userinterface */,
|
||||||
|
ABD0A5341501AA5A0074A094 /* coreaudiosound.cpp */,
|
||||||
|
ABD0A5351501AA5A0074A094 /* ringbuffer.cpp */,
|
||||||
ABD104141346652500AF11D1 /* sndOSX.cpp */,
|
ABD104141346652500AF11D1 /* sndOSX.cpp */,
|
||||||
AB817A35143EE2DB00A7DFE9 /* videofilter.cpp */,
|
AB817A35143EE2DB00A7DFE9 /* videofilter.cpp */,
|
||||||
ABA6574914511EC90077E5E9 /* cocoa_cheat.h */,
|
ABA6574914511EC90077E5E9 /* cocoa_cheat.h */,
|
||||||
|
@ -790,13 +800,15 @@
|
||||||
ABD104001346652500AF11D1 /* cocoa_rom.h */,
|
ABD104001346652500AF11D1 /* cocoa_rom.h */,
|
||||||
AB80E050142BC4FA00A52038 /* cocoa_util.h */,
|
AB80E050142BC4FA00A52038 /* cocoa_util.h */,
|
||||||
ABE5DFE3143FB1DA00835AD8 /* cocoa_videofilter.h */,
|
ABE5DFE3143FB1DA00835AD8 /* cocoa_videofilter.h */,
|
||||||
|
ABD0A5361501AA5A0074A094 /* coreaudiosound.h */,
|
||||||
|
ABD0A5371501AA5A0074A094 /* ringbuffer.h */,
|
||||||
ABD104011346652500AF11D1 /* sndOSX.h */,
|
ABD104011346652500AF11D1 /* sndOSX.h */,
|
||||||
AB817A34143EE2DB00A7DFE9 /* videofilter.h */,
|
AB817A34143EE2DB00A7DFE9 /* videofilter.h */,
|
||||||
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
|
||||||
ABA6574A14511EC90077E5E9 /* cocoa_cheat.mm */,
|
ABA6574A14511EC90077E5E9 /* cocoa_cheat.mm */,
|
||||||
ABD104121346652500AF11D1 /* cocoa_core.mm */,
|
ABD104121346652500AF11D1 /* cocoa_core.mm */,
|
||||||
AB58F32C1364F44B0074C376 /* cocoa_file.mm */,
|
AB58F32C1364F44B0074C376 /* cocoa_file.mm */,
|
||||||
ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */,
|
ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */,
|
||||||
|
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
||||||
ABD104111346652500AF11D1 /* cocoa_input.mm */,
|
ABD104111346652500AF11D1 /* cocoa_input.mm */,
|
||||||
ABD9A46413DB99B300777194 /* cocoa_mic.mm */,
|
ABD9A46413DB99B300777194 /* cocoa_mic.mm */,
|
||||||
AB3E34C8134AF4500056477A /* cocoa_output.mm */,
|
AB3E34C8134AF4500056477A /* cocoa_output.mm */,
|
||||||
|
@ -1665,6 +1677,8 @@
|
||||||
ABFE150B14C92FF5005D6699 /* hq4x.cpp in Sources */,
|
ABFE150B14C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||||
ABFE150D14C92FF5005D6699 /* lq2x.cpp in Sources */,
|
ABFE150D14C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||||
ABFE150E14C92FF5005D6699 /* scanline.cpp in Sources */,
|
ABFE150E14C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||||
|
ABD0A5381501AA5A0074A094 /* coreaudiosound.cpp in Sources */,
|
||||||
|
ABD0A5391501AA5A0074A094 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1787,6 +1801,8 @@
|
||||||
ABFE151314C92FF5005D6699 /* hq4x.cpp in Sources */,
|
ABFE151314C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||||
ABFE151514C92FF5005D6699 /* lq2x.cpp in Sources */,
|
ABFE151514C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||||
ABFE151614C92FF5005D6699 /* scanline.cpp in Sources */,
|
ABFE151614C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||||
|
ABD0A53A1501AA5A0074A094 /* coreaudiosound.cpp in Sources */,
|
||||||
|
ABD0A53B1501AA5A0074A094 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -104,6 +104,12 @@
|
||||||
AB0F29C914BE7213009ABC6F /* Icon_Speaker_420x420.png in Resources */ = {isa = PBXBuildFile; fileRef = AB0F29A514BE7213009ABC6F /* Icon_Speaker_420x420.png */; };
|
AB0F29C914BE7213009ABC6F /* Icon_Speaker_420x420.png in Resources */ = {isa = PBXBuildFile; fileRef = AB0F29A514BE7213009ABC6F /* Icon_Speaker_420x420.png */; };
|
||||||
AB15CA7214A29EE500B8A6A4 /* cpu_detect_x86_gcc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABAD3E6613AF1D6D00502E1E /* cpu_detect_x86_gcc.cpp */; };
|
AB15CA7214A29EE500B8A6A4 /* cpu_detect_x86_gcc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABAD3E6613AF1D6D00502E1E /* cpu_detect_x86_gcc.cpp */; };
|
||||||
AB181D0013B66889006CA82D /* datetime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD1FF1F1345ACBF00AF11D1 /* datetime.cpp */; };
|
AB181D0013B66889006CA82D /* datetime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD1FF1F1345ACBF00AF11D1 /* datetime.cpp */; };
|
||||||
|
AB1B9E631501A78000464647 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */; };
|
||||||
|
AB1B9E641501A78000464647 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */; };
|
||||||
|
AB1B9E651501A78000464647 /* coreaudiosound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */; };
|
||||||
|
AB1B9E661501A78000464647 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B9E601501A78000464647 /* ringbuffer.cpp */; };
|
||||||
|
AB1B9E671501A78000464647 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B9E601501A78000464647 /* ringbuffer.cpp */; };
|
||||||
|
AB1B9E681501A78000464647 /* ringbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B9E601501A78000464647 /* ringbuffer.cpp */; };
|
||||||
AB1F468413A0ADE400B80DE6 /* SndOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD1FF7A1345ACFA00AF11D1 /* SndOut.cpp */; };
|
AB1F468413A0ADE400B80DE6 /* SndOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD1FF7A1345ACFA00AF11D1 /* SndOut.cpp */; };
|
||||||
AB1F469813A0AE2F00B80DE6 /* Timestretcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD1FF9B1345ACFA00AF11D1 /* Timestretcher.cpp */; };
|
AB1F469813A0AE2F00B80DE6 /* Timestretcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD1FF9B1345ACFA00AF11D1 /* Timestretcher.cpp */; };
|
||||||
AB350B6A1478A5B3007165AC /* cocoa_hid.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB350B691478A5B3007165AC /* cocoa_hid.mm */; };
|
AB350B6A1478A5B3007165AC /* cocoa_hid.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB350B691478A5B3007165AC /* cocoa_hid.mm */; };
|
||||||
|
@ -648,6 +654,10 @@
|
||||||
AB0F29A314BE7213009ABC6F /* Icon_RotateCW_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_RotateCW_420x420.png; path = images/Icon_RotateCW_420x420.png; sourceTree = "<group>"; };
|
AB0F29A314BE7213009ABC6F /* Icon_RotateCW_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_RotateCW_420x420.png; path = images/Icon_RotateCW_420x420.png; sourceTree = "<group>"; };
|
||||||
AB0F29A414BE7213009ABC6F /* Icon_ShowHUD_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_ShowHUD_420x420.png; path = images/Icon_ShowHUD_420x420.png; sourceTree = "<group>"; };
|
AB0F29A414BE7213009ABC6F /* Icon_ShowHUD_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_ShowHUD_420x420.png; path = images/Icon_ShowHUD_420x420.png; sourceTree = "<group>"; };
|
||||||
AB0F29A514BE7213009ABC6F /* Icon_Speaker_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_Speaker_420x420.png; path = images/Icon_Speaker_420x420.png; sourceTree = "<group>"; };
|
AB0F29A514BE7213009ABC6F /* Icon_Speaker_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_Speaker_420x420.png; path = images/Icon_Speaker_420x420.png; sourceTree = "<group>"; };
|
||||||
|
AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = coreaudiosound.cpp; sourceTree = SOURCE_ROOT; };
|
||||||
|
AB1B9E601501A78000464647 /* ringbuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ringbuffer.cpp; sourceTree = SOURCE_ROOT; };
|
||||||
|
AB1B9E611501A78000464647 /* coreaudiosound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coreaudiosound.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
AB1B9E621501A78000464647 /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ringbuffer.h; sourceTree = SOURCE_ROOT; };
|
||||||
AB350B681478A5B3007165AC /* cocoa_hid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_hid.h; sourceTree = "<group>"; };
|
AB350B681478A5B3007165AC /* cocoa_hid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_hid.h; sourceTree = "<group>"; };
|
||||||
AB350B691478A5B3007165AC /* cocoa_hid.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_hid.mm; sourceTree = "<group>"; };
|
AB350B691478A5B3007165AC /* cocoa_hid.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_hid.mm; sourceTree = "<group>"; };
|
||||||
AB350BA41478AC96007165AC /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
|
AB350BA41478AC96007165AC /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
|
||||||
|
@ -985,6 +995,8 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
AB3ACB6514C2361100D7D192 /* userinterface */,
|
AB3ACB6514C2361100D7D192 /* userinterface */,
|
||||||
|
AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */,
|
||||||
|
AB1B9E601501A78000464647 /* ringbuffer.cpp */,
|
||||||
ABD104141346652500AF11D1 /* sndOSX.cpp */,
|
ABD104141346652500AF11D1 /* sndOSX.cpp */,
|
||||||
AB817A35143EE2DB00A7DFE9 /* videofilter.cpp */,
|
AB817A35143EE2DB00A7DFE9 /* videofilter.cpp */,
|
||||||
ABA6574914511EC90077E5E9 /* cocoa_cheat.h */,
|
ABA6574914511EC90077E5E9 /* cocoa_cheat.h */,
|
||||||
|
@ -999,13 +1011,15 @@
|
||||||
ABD104001346652500AF11D1 /* cocoa_rom.h */,
|
ABD104001346652500AF11D1 /* cocoa_rom.h */,
|
||||||
AB80E050142BC4FA00A52038 /* cocoa_util.h */,
|
AB80E050142BC4FA00A52038 /* cocoa_util.h */,
|
||||||
ABE5DFE3143FB1DA00835AD8 /* cocoa_videofilter.h */,
|
ABE5DFE3143FB1DA00835AD8 /* cocoa_videofilter.h */,
|
||||||
|
AB1B9E611501A78000464647 /* coreaudiosound.h */,
|
||||||
|
AB1B9E621501A78000464647 /* ringbuffer.h */,
|
||||||
ABD104011346652500AF11D1 /* sndOSX.h */,
|
ABD104011346652500AF11D1 /* sndOSX.h */,
|
||||||
AB817A34143EE2DB00A7DFE9 /* videofilter.h */,
|
AB817A34143EE2DB00A7DFE9 /* videofilter.h */,
|
||||||
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
|
||||||
ABA6574A14511EC90077E5E9 /* cocoa_cheat.mm */,
|
ABA6574A14511EC90077E5E9 /* cocoa_cheat.mm */,
|
||||||
ABD104121346652500AF11D1 /* cocoa_core.mm */,
|
ABD104121346652500AF11D1 /* cocoa_core.mm */,
|
||||||
AB58F32C1364F44B0074C376 /* cocoa_file.mm */,
|
AB58F32C1364F44B0074C376 /* cocoa_file.mm */,
|
||||||
ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */,
|
ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */,
|
||||||
|
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
||||||
ABD104111346652500AF11D1 /* cocoa_input.mm */,
|
ABD104111346652500AF11D1 /* cocoa_input.mm */,
|
||||||
ABD9A46413DB99B300777194 /* cocoa_mic.mm */,
|
ABD9A46413DB99B300777194 /* cocoa_mic.mm */,
|
||||||
AB3E34C8134AF4500056477A /* cocoa_output.mm */,
|
AB3E34C8134AF4500056477A /* cocoa_output.mm */,
|
||||||
|
@ -1554,7 +1568,7 @@
|
||||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0420;
|
LastUpgradeCheck = 0430;
|
||||||
ORGANIZATIONNAME = "DeSmuME Team";
|
ORGANIZATIONNAME = "DeSmuME Team";
|
||||||
};
|
};
|
||||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME (XCode 4)" */;
|
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME (XCode 4)" */;
|
||||||
|
@ -1990,6 +2004,8 @@
|
||||||
ABFE150B14C92FF5005D6699 /* hq4x.cpp in Sources */,
|
ABFE150B14C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||||
ABFE150D14C92FF5005D6699 /* lq2x.cpp in Sources */,
|
ABFE150D14C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||||
ABFE150E14C92FF5005D6699 /* scanline.cpp in Sources */,
|
ABFE150E14C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||||
|
AB1B9E631501A78000464647 /* coreaudiosound.cpp in Sources */,
|
||||||
|
AB1B9E661501A78000464647 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -2112,6 +2128,8 @@
|
||||||
ABFE151314C92FF5005D6699 /* hq4x.cpp in Sources */,
|
ABFE151314C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||||
ABFE151514C92FF5005D6699 /* lq2x.cpp in Sources */,
|
ABFE151514C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||||
ABFE151614C92FF5005D6699 /* scanline.cpp in Sources */,
|
ABFE151614C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||||
|
AB1B9E641501A78000464647 /* coreaudiosound.cpp in Sources */,
|
||||||
|
AB1B9E671501A78000464647 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -2234,6 +2252,8 @@
|
||||||
ABB715FB14E386740027FE88 /* hq4x.cpp in Sources */,
|
ABB715FB14E386740027FE88 /* hq4x.cpp in Sources */,
|
||||||
ABB715FC14E386740027FE88 /* lq2x.cpp in Sources */,
|
ABB715FC14E386740027FE88 /* lq2x.cpp in Sources */,
|
||||||
ABB715FD14E386740027FE88 /* scanline.cpp in Sources */,
|
ABB715FD14E386740027FE88 /* scanline.cpp in Sources */,
|
||||||
|
AB1B9E651501A78000464647 /* coreaudiosound.cpp in Sources */,
|
||||||
|
AB1B9E681501A78000464647 /* ringbuffer.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -2389,7 +2409,6 @@
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
INFOPLIST_FILE = Info.plist;
|
INFOPLIST_FILE = Info.plist;
|
||||||
LLVM_LTO = NO;
|
|
||||||
PRODUCT_NAME = DeSmuME;
|
PRODUCT_NAME = DeSmuME;
|
||||||
SDKROOT = macosx10.7;
|
SDKROOT = macosx10.7;
|
||||||
STRIP_INSTALLED_PRODUCT = NO;
|
STRIP_INSTALLED_PRODUCT = NO;
|
||||||
|
|
|
@ -39,6 +39,13 @@
|
||||||
<key>Save State</key>
|
<key>Save State</key>
|
||||||
<string>${APPSUPPORT}</string>
|
<string>${APPSUPPORT}</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>OpenEmu</key>
|
||||||
|
<dict>
|
||||||
|
<key>ROM Save</key>
|
||||||
|
<string>${OPENEMU}</string>
|
||||||
|
<key>Save State</key>
|
||||||
|
<string>${OPENEMU}</string>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>DirectoryNames</key>
|
<key>DirectoryNames</key>
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSMutableDictionary *) URLDictionary;
|
||||||
|
+ (void) addURLToURLDictionary:(NSURL *)theURL groupKey:(NSString *)groupKey fileKind:(NSString *)fileKind;
|
||||||
|
+ (void) removeURLFromURLDictionaryByGroupKey:(NSString *)groupKey fileKind:(NSString *)fileKind;
|
||||||
+ (BOOL) loadState:(NSURL *)saveStateURL;
|
+ (BOOL) loadState:(NSURL *)saveStateURL;
|
||||||
+ (BOOL) saveState:(NSURL *)saveStateURL;
|
+ (BOOL) saveState:(NSURL *)saveStateURL;
|
||||||
+ (BOOL) loadRom:(NSURL *)romURL;
|
+ (BOOL) loadRom:(NSURL *)romURL;
|
||||||
|
@ -38,6 +41,8 @@
|
||||||
+ (BOOL) romSaveExists:(NSURL *)romURL;
|
+ (BOOL) romSaveExists:(NSURL *)romURL;
|
||||||
+ (BOOL) romSaveExistsWithRom:(NSURL *)romURL;
|
+ (BOOL) romSaveExistsWithRom:(NSURL *)romURL;
|
||||||
+ (void) setupAllFilePaths;
|
+ (void) setupAllFilePaths;
|
||||||
|
+ (void) setupAllFilePathsWithURLDictionary:(NSString *)URLDictionaryKey;
|
||||||
|
+ (void) setupAllFilePathsForVersion:(NSString *)versionString port:(NSString *)portString;
|
||||||
+ (BOOL) setupAllAppDirectories;
|
+ (BOOL) setupAllAppDirectories;
|
||||||
+ (NSURL *) saveStateURL;
|
+ (NSURL *) saveStateURL;
|
||||||
+ (BOOL) saveScreenshot:(NSURL *)fileURL bitmapData:(NSBitmapImageRep *)bitmapImageRep fileType:(NSBitmapImageFileType)fileType;
|
+ (BOOL) saveScreenshot:(NSURL *)fileURL bitmapData:(NSBitmapImageRep *)bitmapImageRep fileType:(NSBitmapImageFileType)fileType;
|
||||||
|
|
|
@ -28,6 +28,110 @@
|
||||||
|
|
||||||
@implementation CocoaDSFile
|
@implementation CocoaDSFile
|
||||||
|
|
||||||
|
// Global dictionary that can be used for storing URLs.
|
||||||
|
//
|
||||||
|
// Usually, it's best to add directory paths to FileTypeInfo.plist, and then
|
||||||
|
// use directoryByKind:version:port for getting a URL, but this method only
|
||||||
|
// works for application build targets. Other target types, such as plug-in
|
||||||
|
// targets, don't read FileTypeInfo.plist correctly, so we include a global
|
||||||
|
// URL dictionary so that we can manually set and get URLs at runtime.
|
||||||
|
static NSMutableDictionary *_gURLDictionary = nil;
|
||||||
|
|
||||||
|
/********************************************************************************************
|
||||||
|
URLDictionary
|
||||||
|
|
||||||
|
Returns the global URL dictionary.
|
||||||
|
|
||||||
|
Takes:
|
||||||
|
Nothing.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A reference to the NSMutableDictionary URLDictionary.
|
||||||
|
|
||||||
|
Details:
|
||||||
|
This should always be used for getting the global URL dictionary. Never try to
|
||||||
|
reference the global URL dictionary directly, since this may change between
|
||||||
|
versions. The first time this method is called, it will automatically allocate
|
||||||
|
the memory for the global URL dictionary.
|
||||||
|
********************************************************************************************/
|
||||||
|
+ (NSMutableDictionary *) URLDictionary
|
||||||
|
{
|
||||||
|
if (_gURLDictionary == nil)
|
||||||
|
{
|
||||||
|
_gURLDictionary = [[NSMutableDictionary alloc] initWithCapacity:8];
|
||||||
|
}
|
||||||
|
|
||||||
|
return _gURLDictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************
|
||||||
|
addURLToURLDictionary:groupKey:fileKind:
|
||||||
|
|
||||||
|
Adds a URL to the global URL dictionary.
|
||||||
|
|
||||||
|
Takes:
|
||||||
|
theURL - An NSURL used to store a URL into the dictionary.
|
||||||
|
groupKey - An NSString that represents the key used to group a set URLs together.
|
||||||
|
fileKind - An NSString that represents the file type.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
|
||||||
|
Details:
|
||||||
|
This should always be used for adding a URL to the global URL dictionary. Never
|
||||||
|
try to add a URL directly, since this may change between versions.
|
||||||
|
********************************************************************************************/
|
||||||
|
+ (void) addURLToURLDictionary:(NSURL *)theURL groupKey:(NSString *)groupKey fileKind:(NSString *)fileKind
|
||||||
|
{
|
||||||
|
if (theURL == nil || groupKey == nil || fileKind == nil)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *urlDictionary = [CocoaDSFile URLDictionary];
|
||||||
|
|
||||||
|
NSMutableDictionary *groupDictionary = (NSMutableDictionary *)[urlDictionary valueForKey:groupKey];
|
||||||
|
if (groupDictionary == nil)
|
||||||
|
{
|
||||||
|
groupDictionary = [NSMutableDictionary dictionaryWithCapacity:16];
|
||||||
|
[urlDictionary setValue:groupDictionary forKey:groupKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
[groupDictionary setValue:theURL forKey:fileKind];
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************
|
||||||
|
removeURLFromURLDictionaryByGroupKey:fileKind:
|
||||||
|
|
||||||
|
Removes a URL from the global URL dictionary.
|
||||||
|
|
||||||
|
Takes:
|
||||||
|
groupKey - An NSString that represents the key used to group a set URLs together.
|
||||||
|
fileKind - An NSString that represents the file type.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
|
||||||
|
Details:
|
||||||
|
This should always be used for removing a URL from the global URL dictionary.
|
||||||
|
Never try to remove a URL directly, since this may change between versions.
|
||||||
|
********************************************************************************************/
|
||||||
|
+ (void) removeURLFromURLDictionaryByGroupKey:(NSString *)groupKey fileKind:(NSString *)fileKind
|
||||||
|
{
|
||||||
|
if (groupKey == nil || fileKind == nil)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *urlDictionary = [CocoaDSFile URLDictionary];
|
||||||
|
|
||||||
|
NSMutableDictionary *groupDictionary = (NSMutableDictionary *)[urlDictionary valueForKey:groupKey];
|
||||||
|
if (groupDictionary != nil)
|
||||||
|
{
|
||||||
|
[groupDictionary setValue:nil forKey:fileKind];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+ (BOOL) loadState:(NSURL *)saveStateURL
|
+ (BOOL) loadState:(NSURL *)saveStateURL
|
||||||
{
|
{
|
||||||
BOOL result = NO;
|
BOOL result = NO;
|
||||||
|
@ -107,6 +211,7 @@
|
||||||
|
|
||||||
switch (fileTypeID)
|
switch (fileTypeID)
|
||||||
{
|
{
|
||||||
|
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||||
case ROMSAVEFORMAT_DESMUME:
|
case ROMSAVEFORMAT_DESMUME:
|
||||||
{
|
{
|
||||||
NSString *destinationPath = [[destinationURL path] stringByAppendingPathExtension:@FILE_EXT_ROM_SAVE];
|
NSString *destinationPath = [[destinationURL path] stringByAppendingPathExtension:@FILE_EXT_ROM_SAVE];
|
||||||
|
@ -115,7 +220,7 @@
|
||||||
[fileManager release];
|
[fileManager release];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
case ROMSAVEFORMAT_NOGBA:
|
case ROMSAVEFORMAT_NOGBA:
|
||||||
{
|
{
|
||||||
const char *destinationPath = [[[destinationURL path] stringByAppendingPathExtension:@FILE_EXT_ROM_SAVE_NOGBA] cStringUsingEncoding:NSUTF8StringEncoding];
|
const char *destinationPath = [[[destinationURL path] stringByAppendingPathExtension:@FILE_EXT_ROM_SAVE_NOGBA] cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
@ -191,57 +296,174 @@
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************
|
||||||
|
setupAllFilePaths
|
||||||
|
|
||||||
|
Sets up all application file paths using the current version of the default port.
|
||||||
|
|
||||||
|
Takes:
|
||||||
|
Nothing.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
|
||||||
|
Details:
|
||||||
|
This method uses setupAllFilePathsForVersion:port: for its implementation.
|
||||||
|
********************************************************************************************/
|
||||||
+ (void) setupAllFilePaths
|
+ (void) setupAllFilePaths
|
||||||
{
|
{
|
||||||
NSURL *romURL = [CocoaDSFile directoryURLByKind:@"ROM"];
|
[CocoaDSFile setupAllFilePathsForVersion:nil port:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************
|
||||||
|
setupAllFilePathsForVersion:port:
|
||||||
|
|
||||||
|
Sets up all application file paths, reading the paths from FileTypeInfo.plist.
|
||||||
|
|
||||||
|
Takes:
|
||||||
|
versionString - An NSString that represents the application version. If nil is
|
||||||
|
used, this method assumes the current version.
|
||||||
|
portString - An NSString that represents the port version. If nil is used, this
|
||||||
|
method assumes the default port version.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
|
||||||
|
Details:
|
||||||
|
This is an Objective-C to C wrapper function for assigning file paths to the
|
||||||
|
emulation layer.
|
||||||
|
********************************************************************************************/
|
||||||
|
+ (void) setupAllFilePathsForVersion:(NSString *)versionString port:(NSString *)portString
|
||||||
|
{
|
||||||
|
NSURL *romURL = [CocoaDSFile directoryURLByKind:@"ROM" version:versionString port:portString];
|
||||||
if (romURL != nil)
|
if (romURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToRoms, [[romURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToRoms, [[romURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *romSaveURL = [CocoaDSFile directoryURLByKind:@"ROM Save"];
|
NSURL *romSaveURL = [CocoaDSFile directoryURLByKind:@"ROM Save" version:versionString port:portString];
|
||||||
if (romSaveURL != nil)
|
if (romSaveURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToBattery, [[romSaveURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToBattery, [[romSaveURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *saveStateURL = [CocoaDSFile directoryURLByKind:@"Save State"];
|
NSURL *saveStateURL = [CocoaDSFile directoryURLByKind:@"Save State" version:versionString port:portString];
|
||||||
if (saveStateURL != nil)
|
if (saveStateURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToStates, [[saveStateURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToStates, [[saveStateURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *screenshotURL = [CocoaDSFile directoryURLByKind:@"Screenshot"];
|
NSURL *screenshotURL = [CocoaDSFile directoryURLByKind:@"Screenshot" version:versionString port:portString];
|
||||||
if (screenshotURL != nil)
|
if (screenshotURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToScreenshots, [[screenshotURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToScreenshots, [[screenshotURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *aviURL = [CocoaDSFile directoryURLByKind:@"Video"];
|
NSURL *aviURL = [CocoaDSFile directoryURLByKind:@"Video" version:versionString port:portString];
|
||||||
if (aviURL != nil)
|
if (aviURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToAviFiles, [[aviURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToAviFiles, [[aviURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *cheatURL = [CocoaDSFile directoryURLByKind:@"Cheat"];
|
NSURL *cheatURL = [CocoaDSFile directoryURLByKind:@"Cheat" version:versionString port:portString];
|
||||||
if (cheatURL != nil)
|
if (cheatURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToCheats, [[cheatURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToCheats, [[cheatURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *soundSamplesURL = [CocoaDSFile directoryURLByKind:@"Sound Sample"];
|
NSURL *soundSamplesURL = [CocoaDSFile directoryURLByKind:@"Sound Sample" version:versionString port:portString];
|
||||||
if (soundSamplesURL != nil)
|
if (soundSamplesURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToSounds, [[soundSamplesURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToSounds, [[soundSamplesURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *firmwareURL = [CocoaDSFile directoryURLByKind:@"Firmware Configuration"];
|
NSURL *firmwareURL = [CocoaDSFile directoryURLByKind:@"Firmware Configuration" version:versionString port:portString];
|
||||||
if (firmwareURL != nil)
|
if (firmwareURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToFirmware, [[firmwareURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToFirmware, [[firmwareURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL *luaURL = [CocoaDSFile directoryURLByKind:@"Lua Script"];
|
NSURL *luaURL = [CocoaDSFile directoryURLByKind:@"Lua Script" version:versionString port:portString];
|
||||||
|
if (luaURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToLua, [[luaURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************
|
||||||
|
setupAllFilePathsWithURLDictionary:
|
||||||
|
|
||||||
|
Sets up all application file paths using the global URLDictionary. This method exists
|
||||||
|
in the case where reading the paths from FileTypeInfo.plist impossible or impractical.
|
||||||
|
|
||||||
|
Takes:
|
||||||
|
URLDictionaryKey - An NSString that is a group key to the URLDictionary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
|
||||||
|
Details:
|
||||||
|
This is an Objective-C to C wrapper function for assigning file paths to the
|
||||||
|
emulation layer.
|
||||||
|
********************************************************************************************/
|
||||||
|
+ (void) setupAllFilePathsWithURLDictionary:(NSString *)URLDictionaryKey
|
||||||
|
{
|
||||||
|
if (URLDictionaryKey == nil)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *URLDictionary = (NSDictionary *)[(NSDictionary *)[CocoaDSFile URLDictionary] valueForKey:URLDictionaryKey];
|
||||||
|
|
||||||
|
NSURL *romURL = (NSURL *)[URLDictionary valueForKey:@"ROM"];
|
||||||
|
if (romURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToRoms, [[romURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *romSaveURL = (NSURL *)[URLDictionary valueForKey:@"ROM Save"];
|
||||||
|
if (romSaveURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToBattery, [[romSaveURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *saveStateURL = (NSURL *)[URLDictionary valueForKey:@"Save State"];
|
||||||
|
if (saveStateURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToStates, [[saveStateURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *screenshotURL = (NSURL *)[URLDictionary valueForKey:@"Screenshot"];
|
||||||
|
if (screenshotURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToScreenshots, [[screenshotURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *aviURL = (NSURL *)[URLDictionary valueForKey:@"Video"];
|
||||||
|
if (aviURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToAviFiles, [[aviURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *cheatURL = (NSURL *)[URLDictionary valueForKey:@"Cheat"];
|
||||||
|
if (cheatURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToCheats, [[cheatURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *soundSamplesURL = (NSURL *)[URLDictionary valueForKey:@"Sound Sample"];
|
||||||
|
if (soundSamplesURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToSounds, [[soundSamplesURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *firmwareURL = (NSURL *)[URLDictionary valueForKey:@"Firmware Configuration"];
|
||||||
|
if (firmwareURL != nil)
|
||||||
|
{
|
||||||
|
strlcpy(path.pathToFirmware, [[firmwareURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *luaURL = (NSURL *)[URLDictionary valueForKey:@"Lua Script"];
|
||||||
if (luaURL != nil)
|
if (luaURL != nil)
|
||||||
{
|
{
|
||||||
strlcpy(path.pathToLua, [[luaURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
strlcpy(path.pathToLua, [[luaURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||||
|
@ -283,6 +505,11 @@
|
||||||
result = NO;
|
result = NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ([dirPath isEqualToString:@PATH_OPEN_EMU])
|
||||||
|
{
|
||||||
|
// OpenEmu uses its own directory structure, so no need to setup here.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if ([dirPath isEqualToString:@PATH_WITH_ROM])
|
else if ([dirPath isEqualToString:@PATH_WITH_ROM])
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -583,6 +810,14 @@
|
||||||
{
|
{
|
||||||
fileURL = [CocoaDSFile userAppSupportURL:dirName version:lookupVersionStr];
|
fileURL = [CocoaDSFile userAppSupportURL:dirName version:lookupVersionStr];
|
||||||
}
|
}
|
||||||
|
else if ([dirPath isEqualToString:@PATH_OPEN_EMU])
|
||||||
|
{
|
||||||
|
NSMutableDictionary *urlDictionary = (NSMutableDictionary *)[[CocoaDSFile URLDictionary] valueForKey:dirPath];
|
||||||
|
if (urlDictionary != nil)
|
||||||
|
{
|
||||||
|
fileURL = (NSURL *)[urlDictionary valueForKey:fileKind];
|
||||||
|
}
|
||||||
|
}
|
||||||
else if ([dirPath isEqualToString:@PATH_WITH_ROM])
|
else if ([dirPath isEqualToString:@PATH_WITH_ROM])
|
||||||
{
|
{
|
||||||
return fileURL;
|
return fileURL;
|
||||||
|
|
|
@ -113,6 +113,7 @@
|
||||||
|
|
||||||
#define PATH_CONFIG_DIRECTORY_0_9_6 "~/.config/desmume"
|
#define PATH_CONFIG_DIRECTORY_0_9_6 "~/.config/desmume"
|
||||||
#define PATH_USER_APP_SUPPORT "${APPSUPPORT}"
|
#define PATH_USER_APP_SUPPORT "${APPSUPPORT}"
|
||||||
|
#define PATH_OPEN_EMU "${OPENEMU}"
|
||||||
#define PATH_WITH_ROM "${WITHROM}"
|
#define PATH_WITH_ROM "${WITHROM}"
|
||||||
|
|
||||||
#define FILE_EXT_FIRMWARE_CONFIG "dfc"
|
#define FILE_EXT_FIRMWARE_CONFIG "dfc"
|
||||||
|
@ -162,8 +163,9 @@
|
||||||
|
|
||||||
#define SPU_SAMPLE_RATE 44100 // Samples per second
|
#define SPU_SAMPLE_RATE 44100 // Samples per second
|
||||||
#define SPU_SAMPLE_RESOLUTION 16 // Bits per sample; must be a multiple of 8
|
#define SPU_SAMPLE_RESOLUTION 16 // Bits per sample; must be a multiple of 8
|
||||||
#define SPU_STEREO_SAMPLE_SIZE ((SPU_SAMPLE_RESOLUTION / 8) * 2) // Bytes per sample, multiply by 2 for stereo
|
#define SPU_NUMBER_CHANNELS 2 // Number of channels
|
||||||
#define SPU_BUFFER_BYTES ((SPU_SAMPLE_RATE / DS_FRAMES_PER_SECOND) * SPU_STEREO_SAMPLE_SIZE)
|
#define SPU_SAMPLE_SIZE ((SPU_SAMPLE_RESOLUTION / 8) * SPU_NUMBER_CHANNELS) // Bytes per sample, multiplied by the number of channels
|
||||||
|
#define SPU_BUFFER_BYTES ((SPU_SAMPLE_RATE / DS_FRAMES_PER_SECOND) * SPU_SAMPLE_SIZE)
|
||||||
|
|
||||||
#define CLOCKWISE_DEGREES(x) (360.0 - x) // Converts an angle in degrees from normal-direction to clockwise-direction.
|
#define CLOCKWISE_DEGREES(x) (360.0 - x) // Converts an angle in degrees from normal-direction to clockwise-direction.
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,6 @@
|
||||||
- (id) initWithVolume:(CGFloat)vol;
|
- (id) initWithVolume:(CGFloat)vol;
|
||||||
- (void) dealloc;
|
- (void) dealloc;
|
||||||
|
|
||||||
+ (BOOL) startupSPU;
|
|
||||||
+ (void) shutdownSPU;
|
|
||||||
+ (BOOL) isSPUStarted;
|
|
||||||
|
|
||||||
- (void) setVolume:(float)vol;
|
- (void) setVolume:(float)vol;
|
||||||
- (float) volume;
|
- (float) volume;
|
||||||
- (void) setAudioOutputEngine:(NSInteger)methodID;
|
- (void) setAudioOutputEngine:(NSInteger)methodID;
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#import "cocoa_util.h"
|
#import "cocoa_util.h"
|
||||||
|
|
||||||
#include <OpenGL/OpenGL.h>
|
#include <OpenGL/OpenGL.h>
|
||||||
#include "sndOSX.h"
|
|
||||||
|
|
||||||
#include "../NDSSystem.h"
|
#include "../NDSSystem.h"
|
||||||
#include "../GPU.h"
|
#include "../GPU.h"
|
||||||
|
@ -40,12 +39,6 @@ GPU3DInterface *core3DList[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
SoundInterface_struct *SNDCoreList[] = {
|
|
||||||
&SNDDummy,
|
|
||||||
&SNDOSX,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
@implementation CocoaDSOutput
|
@implementation CocoaDSOutput
|
||||||
|
|
||||||
@synthesize isStateChanged;
|
@synthesize isStateChanged;
|
||||||
|
@ -133,8 +126,6 @@ SoundInterface_struct *SNDCoreList[] = {
|
||||||
|
|
||||||
@synthesize bufferSize;
|
@synthesize bufferSize;
|
||||||
|
|
||||||
static BOOL isSPUStarted = NO;
|
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
return [self initWithVolume:MAX_VOLUME];
|
return [self initWithVolume:MAX_VOLUME];
|
||||||
|
@ -161,7 +152,7 @@ static BOOL isSPUStarted = NO;
|
||||||
[property setValue:[NSNumber numberWithFloat:(float)vol] forKey:@"volume"];
|
[property setValue:[NSNumber numberWithFloat:(float)vol] forKey:@"volume"];
|
||||||
[property setValue:[NSNumber numberWithBool:NO] forKey:@"mute"];
|
[property setValue:[NSNumber numberWithBool:NO] forKey:@"mute"];
|
||||||
[property setValue:[NSNumber numberWithInteger:0] forKey:@"filter"];
|
[property setValue:[NSNumber numberWithInteger:0] forKey:@"filter"];
|
||||||
[property setValue:[NSNumber numberWithInteger:SNDCORE_OSX] forKey:@"audioOutputEngine"];
|
[property setValue:[NSNumber numberWithInteger:SNDCORE_DUMMY] forKey:@"audioOutputEngine"];
|
||||||
[property setValue:[NSNumber numberWithBool:NO] forKey:@"spuAdvancedLogic"];
|
[property setValue:[NSNumber numberWithBool:NO] forKey:@"spuAdvancedLogic"];
|
||||||
[property setValue:[NSNumber numberWithInteger:SPUInterpolation_None] forKey:@"spuInterpolationMode"];
|
[property setValue:[NSNumber numberWithInteger:SPUInterpolation_None] forKey:@"spuInterpolationMode"];
|
||||||
[property setValue:[NSNumber numberWithInteger:SPU_SYNC_MODE_DUAL_SYNC_ASYNC] forKey:@"spuSyncMode"];
|
[property setValue:[NSNumber numberWithInteger:SPU_SYNC_MODE_DUAL_SYNC_ASYNC] forKey:@"spuSyncMode"];
|
||||||
|
@ -175,43 +166,6 @@ static BOOL isSPUStarted = NO;
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL) startupSPU
|
|
||||||
{
|
|
||||||
NSInteger result = -1;
|
|
||||||
|
|
||||||
if (isSPUStarted)
|
|
||||||
{
|
|
||||||
return isSPUStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
SNDOSXStartup();
|
|
||||||
|
|
||||||
result = SPU_ChangeSoundCore(SNDCORE_OSX, (int)SPU_BUFFER_BYTES);
|
|
||||||
if(result == -1)
|
|
||||||
{
|
|
||||||
SPU_ChangeSoundCore(SNDCORE_DUMMY, 0);
|
|
||||||
isSPUStarted = NO;
|
|
||||||
return isSPUStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
SPU_SetVolume(0);
|
|
||||||
isSPUStarted = YES;
|
|
||||||
|
|
||||||
return isSPUStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) shutdownSPU
|
|
||||||
{
|
|
||||||
SPU_ChangeSoundCore(SNDCORE_DUMMY, 0);
|
|
||||||
SNDOSXShutdown();
|
|
||||||
isSPUStarted = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BOOL) isSPUStarted
|
|
||||||
{
|
|
||||||
return isSPUStarted;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setVolume:(float)vol
|
- (void) setVolume:(float)vol
|
||||||
{
|
{
|
||||||
if (vol < 0.0f)
|
if (vol < 0.0f)
|
||||||
|
@ -227,12 +181,7 @@ static BOOL isSPUStarted = NO;
|
||||||
[property setValue:[NSNumber numberWithFloat:vol] forKey:@"volume"];
|
[property setValue:[NSNumber numberWithFloat:vol] forKey:@"volume"];
|
||||||
OSSpinLockUnlock(&spinlockVolume);
|
OSSpinLockUnlock(&spinlockVolume);
|
||||||
|
|
||||||
if (isSPUStarted)
|
SPU_SetVolume((int)vol);
|
||||||
{
|
|
||||||
//pthread_mutex_lock(self.mutexOutputFrame);
|
|
||||||
SPU_SetVolume((int)vol);
|
|
||||||
//pthread_mutex_unlock(self.mutexOutputFrame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float) volume
|
- (float) volume
|
||||||
|
@ -253,15 +202,10 @@ static BOOL isSPUStarted = NO;
|
||||||
pthread_mutex_lock(self.mutexOutputFrame);
|
pthread_mutex_lock(self.mutexOutputFrame);
|
||||||
|
|
||||||
NSInteger result = -1;
|
NSInteger result = -1;
|
||||||
switch (methodID)
|
|
||||||
|
if (methodID != SNDCORE_DUMMY)
|
||||||
{
|
{
|
||||||
case SNDCORE_OSX:
|
result = SPU_ChangeSoundCore(methodID, (int)SPU_BUFFER_BYTES);
|
||||||
result = SPU_ChangeSoundCore(methodID, (int)SPU_BUFFER_BYTES);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
SPU_ChangeSoundCore(SNDCORE_DUMMY, 0);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result == -1)
|
if(result == -1)
|
||||||
|
@ -377,16 +321,13 @@ static BOOL isSPUStarted = NO;
|
||||||
{
|
{
|
||||||
[property setValue:[NSNumber numberWithBool:mute] forKey:@"mute"];
|
[property setValue:[NSNumber numberWithBool:mute] forKey:@"mute"];
|
||||||
|
|
||||||
if (isSPUStarted)
|
if (mute)
|
||||||
{
|
{
|
||||||
if (mute)
|
SPU_SetVolume(0);
|
||||||
{
|
}
|
||||||
SPU_SetVolume(0);
|
else
|
||||||
}
|
{
|
||||||
else
|
SPU_SetVolume((int)[self volume]);
|
||||||
{
|
|
||||||
SPU_SetVolume((int)[self volume]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,16 +341,6 @@ static BOOL isSPUStarted = NO;
|
||||||
[property setValue:[NSNumber numberWithInteger:filter] forKey:@"filter"];
|
[property setValue:[NSNumber numberWithInteger:filter] forKey:@"filter"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) runThread:(id)object
|
|
||||||
{
|
|
||||||
[CocoaDSSpeaker startupSPU];
|
|
||||||
SPU_SetVolume((int)[self volume]);
|
|
||||||
|
|
||||||
[super runThread:object];
|
|
||||||
|
|
||||||
[CocoaDSSpeaker shutdownSPU];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)handlePortMessage:(NSPortMessage*)portMessage
|
- (void)handlePortMessage:(NSPortMessage*)portMessage
|
||||||
{
|
{
|
||||||
NSInteger message = (NSInteger)[portMessage msgid];
|
NSInteger message = (NSInteger)[portMessage msgid];
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2012 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "coreaudiosound.h"
|
||||||
|
#include "cocoa_globals.h"
|
||||||
|
|
||||||
|
CoreAudioSound::CoreAudioSound(size_t bufferSamples, size_t sampleSize)
|
||||||
|
{
|
||||||
|
OSStatus error = noErr;
|
||||||
|
|
||||||
|
_spinlockAU = (OSSpinLock *)malloc(sizeof(OSSpinLock));
|
||||||
|
*_spinlockAU = OS_SPINLOCK_INIT;
|
||||||
|
|
||||||
|
_buffer = new RingBuffer(bufferSamples, sampleSize);
|
||||||
|
_volume = 1.0f;
|
||||||
|
|
||||||
|
// Create a new audio unit
|
||||||
|
ComponentDescription desc;
|
||||||
|
desc.componentType = kAudioUnitType_Output;
|
||||||
|
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||||
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||||
|
desc.componentFlags = 0;
|
||||||
|
desc.componentFlagsMask = 0;
|
||||||
|
|
||||||
|
Component comp = FindNextComponent(NULL, &desc);
|
||||||
|
if (comp == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = OpenAComponent(comp, &_au);
|
||||||
|
if (comp == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the render callback
|
||||||
|
AURenderCallbackStruct callback;
|
||||||
|
callback.inputProc = &RenderCallback;
|
||||||
|
callback.inputProcRefCon = _buffer;
|
||||||
|
|
||||||
|
error = AudioUnitSetProperty(_au,
|
||||||
|
kAudioUnitProperty_SetRenderCallback,
|
||||||
|
kAudioUnitScope_Input,
|
||||||
|
0,
|
||||||
|
&callback,
|
||||||
|
sizeof(callback) );
|
||||||
|
|
||||||
|
if(error != noErr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the audio unit for audio streaming
|
||||||
|
AudioStreamBasicDescription audio_format;
|
||||||
|
audio_format.mSampleRate = SPU_SAMPLE_RATE;
|
||||||
|
audio_format.mFormatID = kAudioFormatLinearPCM;
|
||||||
|
audio_format.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
|
||||||
|
audio_format.mBytesPerPacket = SPU_SAMPLE_SIZE;
|
||||||
|
audio_format.mFramesPerPacket = 1;
|
||||||
|
audio_format.mBytesPerFrame = SPU_SAMPLE_SIZE;
|
||||||
|
audio_format.mChannelsPerFrame = SPU_NUMBER_CHANNELS;
|
||||||
|
audio_format.mBitsPerChannel = SPU_SAMPLE_RESOLUTION;
|
||||||
|
|
||||||
|
error = AudioUnitSetProperty(_au,
|
||||||
|
kAudioUnitProperty_StreamFormat,
|
||||||
|
kAudioUnitScope_Input,
|
||||||
|
0,
|
||||||
|
&audio_format,
|
||||||
|
sizeof(audio_format) );
|
||||||
|
|
||||||
|
if(error != noErr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize our new audio unit
|
||||||
|
error = AudioUnitInitialize(_au);
|
||||||
|
if(error != noErr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreAudioSound::~CoreAudioSound()
|
||||||
|
{
|
||||||
|
OSSpinLockLock(_spinlockAU);
|
||||||
|
|
||||||
|
if(_au != NULL)
|
||||||
|
{
|
||||||
|
AudioOutputUnitStop(_au);
|
||||||
|
AudioUnitUninitialize(_au);
|
||||||
|
_au = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSSpinLockUnlock(_spinlockAU);
|
||||||
|
|
||||||
|
delete _buffer;
|
||||||
|
_buffer = NULL;
|
||||||
|
|
||||||
|
free(_spinlockAU);
|
||||||
|
_spinlockAU = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RingBuffer* CoreAudioSound::getBuffer()
|
||||||
|
{
|
||||||
|
return this->_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioSound::start()
|
||||||
|
{
|
||||||
|
this->clearBuffer();
|
||||||
|
|
||||||
|
OSSpinLockLock(this->_spinlockAU);
|
||||||
|
AudioUnitReset(this->_au, kAudioUnitScope_Global, 0);
|
||||||
|
AudioOutputUnitStart(this->_au);
|
||||||
|
OSSpinLockUnlock(this->_spinlockAU);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioSound::stop()
|
||||||
|
{
|
||||||
|
OSSpinLockLock(this->_spinlockAU);
|
||||||
|
AudioOutputUnitStop(this->_au);
|
||||||
|
OSSpinLockUnlock(this->_spinlockAU);
|
||||||
|
|
||||||
|
this->clearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioSound::writeToBuffer(const void *buffer, size_t numberBytes)
|
||||||
|
{
|
||||||
|
this->getBuffer()->write(buffer, numberBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioSound::clearBuffer()
|
||||||
|
{
|
||||||
|
this->_buffer->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioSound::mute()
|
||||||
|
{
|
||||||
|
OSSpinLockLock(this->_spinlockAU);
|
||||||
|
AudioUnitSetParameter(this->_au, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, 0.0f, 0);
|
||||||
|
OSSpinLockUnlock(this->_spinlockAU);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioSound::unmute()
|
||||||
|
{
|
||||||
|
OSSpinLockLock(this->_spinlockAU);
|
||||||
|
AudioUnitSetParameter(this->_au, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, this->_volume, 0);
|
||||||
|
OSSpinLockUnlock(this->_spinlockAU);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CoreAudioSound::getAvailableSamples()
|
||||||
|
{
|
||||||
|
return this->_buffer->getAvailableElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
float CoreAudioSound::getVolume()
|
||||||
|
{
|
||||||
|
return this->_volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioSound::setVolume(float vol)
|
||||||
|
{
|
||||||
|
this->_volume = vol;
|
||||||
|
|
||||||
|
OSSpinLockLock(this->_spinlockAU);
|
||||||
|
AudioUnitSetParameter(this->_au, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, vol, 0);
|
||||||
|
OSSpinLockUnlock(this->_spinlockAU);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus RenderCallback(void *inRefCon,
|
||||||
|
AudioUnitRenderActionFlags *ioActionFlags,
|
||||||
|
const AudioTimeStamp *inTimeStamp,
|
||||||
|
UInt32 inBusNumber,
|
||||||
|
UInt32 inNumberFrames,
|
||||||
|
AudioBufferList *ioData)
|
||||||
|
{
|
||||||
|
RingBuffer *__restrict__ audioBuffer = (RingBuffer *)inRefCon;
|
||||||
|
UInt8 *__restrict__ playbackBuffer = (UInt8 *)ioData->mBuffers[0].mData;
|
||||||
|
const size_t totalReadSize = inNumberFrames * audioBuffer->getElementSize();
|
||||||
|
const size_t bytesRead = audioBuffer->read(playbackBuffer, totalReadSize);
|
||||||
|
|
||||||
|
// Pad any remaining samples.
|
||||||
|
if (bytesRead < totalReadSize)
|
||||||
|
{
|
||||||
|
memset(playbackBuffer + bytesRead, 0, totalReadSize - bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy to other channels.
|
||||||
|
for (UInt32 channel = 1; channel < ioData->mNumberBuffers; channel++)
|
||||||
|
{
|
||||||
|
memcpy(ioData->mBuffers[channel].mData, playbackBuffer, ioData->mBuffers[0].mDataByteSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return noErr;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2012 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COREAUDIOSOUND_
|
||||||
|
#define _COREAUDIOSOUND_
|
||||||
|
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
#include <AudioUnit/AudioUnit.h>
|
||||||
|
#include <AudioToolbox/AudioToolbox.h>
|
||||||
|
#include <libkern/OSAtomic.h>
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
|
class CoreAudioSound
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
AudioUnit _au;
|
||||||
|
RingBuffer *_buffer;
|
||||||
|
OSSpinLock *_spinlockAU;
|
||||||
|
float _volume;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreAudioSound(size_t bufferSamples, size_t sampleSize);
|
||||||
|
~CoreAudioSound();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
void writeToBuffer(const void *buffer, size_t numberBytes);
|
||||||
|
void clearBuffer();
|
||||||
|
size_t getAvailableSamples();
|
||||||
|
RingBuffer* getBuffer();
|
||||||
|
void mute();
|
||||||
|
void unmute();
|
||||||
|
float getVolume();
|
||||||
|
void setVolume(float vol);
|
||||||
|
};
|
||||||
|
|
||||||
|
OSStatus RenderCallback(void *inRefCon,
|
||||||
|
AudioUnitRenderActionFlags *ioActionFlags,
|
||||||
|
const AudioTimeStamp *inTimeStamp,
|
||||||
|
UInt32 inBusNumber,
|
||||||
|
UInt32 inNumberFrames,
|
||||||
|
AudioBufferList *ioData);
|
||||||
|
|
||||||
|
#endif
|
|
@ -53,12 +53,6 @@ GPU3DInterface *core3DList[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
SoundInterface_struct *SNDCoreList[] = {
|
|
||||||
&SNDDummy,
|
|
||||||
&SNDOSX,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NDS_fw_config_data macDS_firmware;
|
struct NDS_fw_config_data macDS_firmware;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2012 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
|
|
||||||
|
RingBuffer::RingBuffer(size_t numberElements, size_t newBufferElementSize)
|
||||||
|
{
|
||||||
|
_buffer = (uint8_t *)calloc(numberElements + 1, newBufferElementSize);
|
||||||
|
_bufferSize = (numberElements + 1) * newBufferElementSize;
|
||||||
|
_numElements = numberElements;
|
||||||
|
_elementSize = newBufferElementSize;
|
||||||
|
|
||||||
|
_readPosition = newBufferElementSize - 1;
|
||||||
|
_writePosition = newBufferElementSize;
|
||||||
|
_bufferFillSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RingBuffer::~RingBuffer()
|
||||||
|
{
|
||||||
|
free(_buffer);
|
||||||
|
_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RingBuffer::clear()
|
||||||
|
{
|
||||||
|
this->_readPosition = this->_elementSize - 1;
|
||||||
|
this->_writePosition = this->_elementSize;
|
||||||
|
this->_bufferFillSize = 0;
|
||||||
|
memset(_buffer, 0, this->_bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RingBuffer::read(void *__restrict__ destBuffer, size_t requestedNumberBytes)
|
||||||
|
{
|
||||||
|
if (destBuffer == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hiBufferAvailable = 0;
|
||||||
|
size_t loBufferAvailable = 0;
|
||||||
|
|
||||||
|
const uint8_t *__restrict__ inputData = this->_buffer;
|
||||||
|
size_t inputDataReadPos = this->_readPosition;
|
||||||
|
const size_t inputDataWritePos = this->_writePosition;
|
||||||
|
const size_t inputDataSize = this->_bufferSize;
|
||||||
|
|
||||||
|
// Check buffer availability
|
||||||
|
if (inputDataReadPos < inputDataWritePos)
|
||||||
|
{
|
||||||
|
hiBufferAvailable = inputDataWritePos - inputDataReadPos - 1;
|
||||||
|
}
|
||||||
|
else if (inputDataReadPos > inputDataWritePos)
|
||||||
|
{
|
||||||
|
hiBufferAvailable = inputDataSize - inputDataReadPos - 1;
|
||||||
|
loBufferAvailable = inputDataWritePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounds check for buffer overrun
|
||||||
|
if (requestedNumberBytes > hiBufferAvailable + loBufferAvailable)
|
||||||
|
{
|
||||||
|
requestedNumberBytes = hiBufferAvailable + loBufferAvailable;
|
||||||
|
requestedNumberBytes -= requestedNumberBytes % this->_elementSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy ring buffer to destination buffer
|
||||||
|
if (requestedNumberBytes <= hiBufferAvailable)
|
||||||
|
{
|
||||||
|
memcpy(destBuffer, inputData + inputDataReadPos + 1, requestedNumberBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(destBuffer, inputData + inputDataReadPos + 1, hiBufferAvailable);
|
||||||
|
memcpy((uint8_t *)destBuffer + hiBufferAvailable, inputData, requestedNumberBytes - hiBufferAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance the read position
|
||||||
|
inputDataReadPos += requestedNumberBytes;
|
||||||
|
if (inputDataReadPos >= inputDataSize)
|
||||||
|
{
|
||||||
|
inputDataReadPos -= inputDataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->_readPosition = inputDataReadPos;
|
||||||
|
|
||||||
|
// Decrease the fill size now that we're done reading.
|
||||||
|
OSAtomicAdd32Barrier(-(int32_t)requestedNumberBytes, &this->_bufferFillSize);
|
||||||
|
|
||||||
|
return requestedNumberBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RingBuffer::write(const void *__restrict__ srcBuffer, size_t requestedNumberBytes)
|
||||||
|
{
|
||||||
|
if (srcBuffer == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hiBufferAvailable = 0;
|
||||||
|
size_t loBufferAvailable = 0;
|
||||||
|
|
||||||
|
uint8_t *__restrict__ inputData = this->_buffer;
|
||||||
|
const size_t inputDataReadPos = this->_readPosition;
|
||||||
|
size_t inputDataWritePos = this->_writePosition;
|
||||||
|
const size_t inputDataSize = this->_bufferSize;
|
||||||
|
|
||||||
|
// Check buffer availability.
|
||||||
|
if (inputDataWritePos >= inputDataReadPos)
|
||||||
|
{
|
||||||
|
hiBufferAvailable = inputDataSize - inputDataWritePos;
|
||||||
|
loBufferAvailable = inputDataReadPos;
|
||||||
|
|
||||||
|
// Subtract a sample's worth of bytes
|
||||||
|
if (loBufferAvailable > 0)
|
||||||
|
{
|
||||||
|
loBufferAvailable -= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hiBufferAvailable -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // (inputDataWritePos < inputDataReadPos)
|
||||||
|
{
|
||||||
|
hiBufferAvailable = inputDataReadPos - inputDataWritePos - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounds check for buffer overrun
|
||||||
|
if (requestedNumberBytes > hiBufferAvailable + loBufferAvailable)
|
||||||
|
{
|
||||||
|
requestedNumberBytes = hiBufferAvailable + loBufferAvailable;
|
||||||
|
requestedNumberBytes -= requestedNumberBytes % this->_elementSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase the fill size before writing anything.
|
||||||
|
OSAtomicAdd32Barrier((int32_t)requestedNumberBytes, &this->_bufferFillSize);
|
||||||
|
|
||||||
|
// Copy source buffer to ring buffer.
|
||||||
|
if (requestedNumberBytes <= hiBufferAvailable)
|
||||||
|
{
|
||||||
|
memcpy(inputData + inputDataWritePos, srcBuffer, requestedNumberBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(inputData + inputDataWritePos, srcBuffer, hiBufferAvailable);
|
||||||
|
memcpy(inputData, (uint8_t *)srcBuffer + hiBufferAvailable, requestedNumberBytes - hiBufferAvailable);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance the write position.
|
||||||
|
inputDataWritePos += requestedNumberBytes;
|
||||||
|
if (inputDataWritePos >= inputDataSize)
|
||||||
|
{
|
||||||
|
inputDataWritePos -= inputDataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->_writePosition = inputDataWritePos;
|
||||||
|
|
||||||
|
return requestedNumberBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RingBuffer::getAvailableElements()
|
||||||
|
{
|
||||||
|
return ((this->_bufferSize - this->_bufferFillSize) / this->_elementSize) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RingBuffer::getElementSize()
|
||||||
|
{
|
||||||
|
return this->_elementSize;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2012 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RINGBUFFER_
|
||||||
|
#define _RINGBUFFER_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libkern/OSAtomic.h>
|
||||||
|
|
||||||
|
|
||||||
|
class RingBuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t *_buffer;
|
||||||
|
uint8_t *_bufferEnd;
|
||||||
|
size_t _bufferSize;
|
||||||
|
size_t _numElements;
|
||||||
|
size_t _elementSize;
|
||||||
|
int32_t _bufferFillSize;
|
||||||
|
size_t _readPosition;
|
||||||
|
size_t _writePosition;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RingBuffer(size_t numberElements, size_t newBufferElementSize);
|
||||||
|
~RingBuffer();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
size_t read(void *__restrict__ destBuffer, size_t requestedNumberBytes);
|
||||||
|
size_t write(const void *__restrict__ srcBuffer, size_t requestedNumberBytes);
|
||||||
|
size_t getAvailableElements();
|
||||||
|
size_t getElementSize();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -18,592 +18,17 @@
|
||||||
|
|
||||||
#include "sndOSX.h"
|
#include "sndOSX.h"
|
||||||
|
|
||||||
#include <CoreServices/CoreServices.h>
|
#include "coreaudiosound.h"
|
||||||
#include <AudioUnit/AudioUnit.h>
|
|
||||||
#include <AudioToolbox/AudioToolbox.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "cocoa_globals.h"
|
#include "cocoa_globals.h"
|
||||||
|
|
||||||
|
|
||||||
//globals
|
// Global sound playback manager
|
||||||
static AudioUnit output_unit = NULL; //pointer to our audio device
|
static CoreAudioSound *coreAudioPlaybackManager = NULL;
|
||||||
static UInt8 *sound_data = NULL; //buffer where we hold data between getting it from the emulator and sending it to the device
|
|
||||||
static size_t sound_buffer_size = 0; //size in bytes of sound_data
|
|
||||||
static size_t sound_offset = SPU_STEREO_SAMPLE_SIZE; //position in the buffer that we have copied to from the emu
|
|
||||||
static size_t sound_position = 0; //position in the buffer that we have played to
|
|
||||||
static float current_volume_scalar = 1.0f; //for volume/muting
|
|
||||||
|
|
||||||
//file output
|
|
||||||
static bool file_open = false;
|
|
||||||
//static ExtAudioFileRef outfile;
|
|
||||||
|
|
||||||
static pthread_mutex_t *mutexSoundData = NULL;
|
|
||||||
static pthread_mutex_t *mutexAudioUnit = NULL;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//This is the callback where we will stick the sound data we've gotten from
|
|
||||||
//the emulator into a core audio buffer to be processed and sent to the sound driver
|
|
||||||
|
|
||||||
OSStatus soundMixer(void *inRefCon,
|
|
||||||
AudioUnitRenderActionFlags *ioActionFlags,
|
|
||||||
const AudioTimeStamp *inTimeStamp,
|
|
||||||
UInt32 inBusNumber,
|
|
||||||
UInt32 inNumberFrames,
|
|
||||||
AudioBufferList *ioData)
|
|
||||||
{
|
|
||||||
//printf("SOUND CALLBACK %u off%u pos%u\n", inNumberFrames * 4, sound_offset, sound_position);
|
|
||||||
UInt8 *__restrict__ outputData = (UInt8 *)ioData->mBuffers[0].mData;
|
|
||||||
const size_t copySize = inNumberFrames * SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
size_t hiBufferAvailable = 0;
|
|
||||||
size_t loBufferAvailable = 0;
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexSoundData);
|
|
||||||
|
|
||||||
if(sound_data != NULL)
|
|
||||||
{
|
|
||||||
const UInt8 *__restrict__ inputData = sound_data;
|
|
||||||
const size_t inputDataReadPos = sound_position;
|
|
||||||
const size_t inputDataWritePos = sound_offset;
|
|
||||||
const size_t inputDataSize = sound_buffer_size;
|
|
||||||
|
|
||||||
// Determine buffer availability
|
|
||||||
if (inputDataReadPos < inputDataWritePos)
|
|
||||||
{
|
|
||||||
hiBufferAvailable = inputDataWritePos - inputDataReadPos - 1;
|
|
||||||
}
|
|
||||||
else if (inputDataReadPos > inputDataWritePos)
|
|
||||||
{
|
|
||||||
hiBufferAvailable = inputDataSize - inputDataReadPos - 1;
|
|
||||||
loBufferAvailable = inputDataWritePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy sound data from buffer
|
|
||||||
if (copySize <= hiBufferAvailable)
|
|
||||||
{
|
|
||||||
memcpy(outputData, inputData + inputDataReadPos + 1, copySize);
|
|
||||||
sound_position += copySize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(outputData, inputData + inputDataReadPos + 1, hiBufferAvailable);
|
|
||||||
|
|
||||||
if (copySize - hiBufferAvailable <= loBufferAvailable)
|
|
||||||
{
|
|
||||||
memcpy(outputData + hiBufferAvailable, inputData, copySize - hiBufferAvailable);
|
|
||||||
sound_position = copySize - hiBufferAvailable - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(outputData + hiBufferAvailable, inputData, loBufferAvailable);
|
|
||||||
if (inputDataWritePos == 0)
|
|
||||||
{
|
|
||||||
sound_position = inputDataSize - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sound_position = inputDataWritePos - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pad any remaining samples with null samples
|
|
||||||
const size_t totalAvailable = hiBufferAvailable + loBufferAvailable;
|
|
||||||
if (copySize > totalAvailable)
|
|
||||||
{
|
|
||||||
memset(outputData + totalAvailable, 0, copySize - totalAvailable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memset(outputData, 0, copySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
|
|
||||||
//copy to other channels
|
|
||||||
for (UInt32 channel = 1; channel < ioData->mNumberBuffers; channel++)
|
|
||||||
{
|
|
||||||
memcpy(ioData->mBuffers[channel].mData, outputData, ioData->mBuffers[0].mDataByteSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
//record to file
|
|
||||||
if(file_open)
|
|
||||||
{
|
|
||||||
//ExtAudioFileWrite(outfile, inNumberFrames, ioData);
|
|
||||||
}
|
|
||||||
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void SNDOSXStartup()
|
|
||||||
{
|
|
||||||
OSStatus error = noErr;
|
|
||||||
|
|
||||||
if (mutexSoundData == NULL)
|
|
||||||
{
|
|
||||||
mutexSoundData = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
|
|
||||||
pthread_mutex_init(mutexSoundData, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutexAudioUnit == NULL)
|
|
||||||
{
|
|
||||||
mutexAudioUnit = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
|
|
||||||
pthread_mutex_init(mutexAudioUnit, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Setup the sound buffer -------------------------------------------
|
|
||||||
pthread_mutex_lock(mutexSoundData);
|
|
||||||
|
|
||||||
sound_data = (UInt8 *)calloc((SPU_SAMPLE_RATE / DS_FRAMES_PER_SECOND) + 1, SPU_STEREO_SAMPLE_SIZE);
|
|
||||||
if(sound_data == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sound_position = 0;
|
|
||||||
sound_offset = SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
sound_buffer_size = ((SPU_SAMPLE_RATE / DS_FRAMES_PER_SECOND) + 1) * SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
|
|
||||||
//grab the default audio unit -------------------------
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
current_volume_scalar = 1.0f;
|
|
||||||
|
|
||||||
ComponentDescription desc;
|
|
||||||
desc.componentType = kAudioUnitType_Output;
|
|
||||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
|
||||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
|
||||||
desc.componentFlags = 0;
|
|
||||||
desc.componentFlagsMask = 0;
|
|
||||||
|
|
||||||
Component comp = FindNextComponent(NULL, &desc);
|
|
||||||
if (comp == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = OpenAComponent(comp, &output_unit);
|
|
||||||
if (comp == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//then setup the callback where we will send the audio -------
|
|
||||||
|
|
||||||
AURenderCallbackStruct callback;
|
|
||||||
callback.inputProc = soundMixer;
|
|
||||||
callback.inputProcRefCon = NULL;
|
|
||||||
|
|
||||||
error = AudioUnitSetProperty(output_unit,
|
|
||||||
kAudioUnitProperty_SetRenderCallback,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&callback,
|
|
||||||
sizeof(callback) );
|
|
||||||
|
|
||||||
if(error != noErr)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//now begin running the audio unit-- ----------------------
|
|
||||||
|
|
||||||
AudioStreamBasicDescription audio_format;
|
|
||||||
audio_format.mSampleRate = SPU_SAMPLE_RATE;
|
|
||||||
audio_format.mFormatID = kAudioFormatLinearPCM;
|
|
||||||
audio_format.mFormatFlags = kAudioFormatFlagIsSignedInteger
|
|
||||||
| kAudioFormatFlagsNativeEndian
|
|
||||||
| kLinearPCMFormatFlagIsPacked;
|
|
||||||
audio_format.mBytesPerPacket = 4;
|
|
||||||
audio_format.mFramesPerPacket = 1;
|
|
||||||
audio_format.mBytesPerFrame = 4;
|
|
||||||
audio_format.mChannelsPerFrame = 2;
|
|
||||||
audio_format.mBitsPerChannel = SPU_SAMPLE_RESOLUTION;
|
|
||||||
|
|
||||||
error = AudioUnitSetProperty(output_unit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&audio_format,
|
|
||||||
sizeof(audio_format) );
|
|
||||||
|
|
||||||
if(error != noErr)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize unit
|
|
||||||
error = AudioUnitInitialize(output_unit);
|
|
||||||
if(error != noErr)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
|
|
||||||
//we call the CFRunLoopRunInMode to service any notifications that the audio
|
|
||||||
//system has to deal with
|
|
||||||
//CFRunLoopRunInMode(kCFRunLoopDefaultMode, 2, false);
|
|
||||||
//verify_noerr (AudioOutputUnitStop (output_unit));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SNDOSXShutdown()
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
//closes the audio unit (errors are ignored here)
|
|
||||||
if(output_unit != NULL)
|
|
||||||
{
|
|
||||||
AudioOutputUnitStop(output_unit);
|
|
||||||
AudioUnitUninitialize(output_unit);
|
|
||||||
output_unit = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexSoundData);
|
|
||||||
|
|
||||||
if(sound_data != NULL)
|
|
||||||
{
|
|
||||||
free(sound_data);
|
|
||||||
sound_data = NULL;
|
|
||||||
sound_position = 0;
|
|
||||||
sound_offset = SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
sound_buffer_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
|
|
||||||
if (mutexSoundData != NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_destroy(mutexSoundData);
|
|
||||||
free(mutexSoundData);
|
|
||||||
mutexSoundData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutexAudioUnit != NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_destroy(mutexAudioUnit);
|
|
||||||
free(mutexAudioUnit);
|
|
||||||
mutexAudioUnit = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SNDOSXInit(int buffer_size)
|
|
||||||
{
|
|
||||||
OSStatus error = noErr;
|
|
||||||
const size_t singleSampleSize = SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
UInt8 *newSoundData = NULL;
|
|
||||||
|
|
||||||
//Setup the sound buffer -------------------------------------------
|
|
||||||
pthread_mutex_lock(mutexSoundData);
|
|
||||||
|
|
||||||
//add one more since sound position can never catch up to
|
|
||||||
//sound_offset - because if they were the same it would signify
|
|
||||||
//that the buffer is empty
|
|
||||||
|
|
||||||
sound_buffer_size = buffer_size + singleSampleSize;
|
|
||||||
|
|
||||||
newSoundData = (UInt8 *)realloc(sound_data, sound_buffer_size);
|
|
||||||
if(newSoundData == NULL)
|
|
||||||
{
|
|
||||||
free(sound_data);
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(newSoundData, 0, sound_buffer_size);
|
|
||||||
sound_data = newSoundData;
|
|
||||||
sound_position = 0;
|
|
||||||
sound_offset = singleSampleSize;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
|
||||||
|
|
||||||
//Start the rendering
|
|
||||||
//The DefaultOutputUnit will do any format conversions to the format of the default device
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if (output_unit != NULL)
|
|
||||||
{
|
|
||||||
AudioUnitReset(output_unit, kAudioUnitScope_Global, 0);
|
|
||||||
|
|
||||||
error = AudioOutputUnitStart(output_unit);
|
|
||||||
if(error != noErr)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void SNDOSXDeInit()
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(output_unit != NULL)
|
|
||||||
{
|
|
||||||
AudioOutputUnitStop(output_unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
|
|
||||||
SNDOSXClearBuffer();
|
|
||||||
SNDOSXCloseFile(); //end recording to file if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int SNDOSXReset()
|
|
||||||
{
|
|
||||||
SNDOSXClearBuffer();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples)
|
|
||||||
{
|
|
||||||
const size_t singleSampleSize = SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
size_t copySize = num_samples * singleSampleSize;
|
|
||||||
size_t hiBufferAvailable = 0; // Buffer space ahead of offset
|
|
||||||
size_t loBufferAvailable = 0; // Buffer space before read position
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexSoundData);
|
|
||||||
|
|
||||||
if(sound_data == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt8 *__restrict__ inputData = sound_data;
|
|
||||||
const size_t inputDataReadPos = sound_position;
|
|
||||||
const size_t inputDataWritePos = sound_offset;
|
|
||||||
const size_t inputDataSize = sound_buffer_size;
|
|
||||||
|
|
||||||
if (inputDataWritePos >= inputDataReadPos)
|
|
||||||
{
|
|
||||||
hiBufferAvailable = inputDataSize - inputDataWritePos;
|
|
||||||
loBufferAvailable = inputDataReadPos;
|
|
||||||
|
|
||||||
// Subtract a sample's worth of bytes
|
|
||||||
if (loBufferAvailable > 0)
|
|
||||||
{
|
|
||||||
loBufferAvailable -= 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hiBufferAvailable -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // (inputDataWritePos < inputDataReadPos)
|
|
||||||
{
|
|
||||||
hiBufferAvailable = inputDataReadPos - inputDataWritePos - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copySize > hiBufferAvailable + loBufferAvailable)
|
|
||||||
{
|
|
||||||
//this shouldn't happen as the emulator core generally asks how much
|
|
||||||
//space is available before sending stuff, but just in case
|
|
||||||
int bytesShort = copySize - hiBufferAvailable - loBufferAvailable;
|
|
||||||
|
|
||||||
printf("SNDOSXUpdateAudio() ERROR: Not enough space in buffer -- %i bytes short.\n", bytesShort);
|
|
||||||
|
|
||||||
copySize = hiBufferAvailable + loBufferAvailable;
|
|
||||||
copySize -= copySize % singleSampleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copySize <= hiBufferAvailable)
|
|
||||||
{
|
|
||||||
memcpy(inputData + inputDataWritePos, buffer, copySize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(inputData + inputDataWritePos, buffer, hiBufferAvailable);
|
|
||||||
memcpy(inputData, ((UInt8 *)buffer) + hiBufferAvailable, copySize - hiBufferAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance the offset
|
|
||||||
sound_offset += copySize;
|
|
||||||
if (sound_offset >= inputDataSize)
|
|
||||||
{
|
|
||||||
sound_offset -= inputDataSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
u32 SNDOSXGetAudioSpace()
|
|
||||||
{
|
|
||||||
const size_t singleSampleSize = SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
size_t free_space = 0;
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexSoundData);
|
|
||||||
|
|
||||||
if(sound_data == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sound_offset >= sound_position)
|
|
||||||
{
|
|
||||||
free_space = (sound_buffer_size - sound_offset) + sound_position;
|
|
||||||
}
|
|
||||||
else // (sound_offset < sound_position)
|
|
||||||
{
|
|
||||||
free_space = sound_position - sound_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
|
|
||||||
if (free_space >= singleSampleSize)
|
|
||||||
{
|
|
||||||
free_space -= singleSampleSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
free_space = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (u32)(free_space / singleSampleSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void SNDOSXMuteAudio()
|
|
||||||
{
|
|
||||||
OSStatus error = noErr;
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(output_unit == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, 0, 0);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(error != noErr)
|
|
||||||
{
|
|
||||||
printf("SNDOSXMuteAudio() ERROR: Could not set Audio Unit parameter -- Volume=0.0%%\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void SNDOSXUnMuteAudio()
|
|
||||||
{
|
|
||||||
OSStatus error = noErr;
|
|
||||||
float volumeScalar = 0.0f;
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(output_unit == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
volumeScalar = current_volume_scalar;
|
|
||||||
error = AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, volumeScalar, 0);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(error != noErr)
|
|
||||||
{
|
|
||||||
printf("SNDOSXUnMuteAudio() ERROR: Could not set Audio Unit parameter -- Volume=%1.1f%%\n", volumeScalar * 100.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void SNDOSXSetVolume(int volume)
|
|
||||||
{
|
|
||||||
OSStatus error = noErr;
|
|
||||||
float newVolumeScalar = (float)volume / 100.0f;
|
|
||||||
|
|
||||||
if(volume > 100)
|
|
||||||
{
|
|
||||||
newVolumeScalar = 1.0f;
|
|
||||||
}
|
|
||||||
else if(volume < 0)
|
|
||||||
{
|
|
||||||
newVolumeScalar = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(output_unit == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_volume_scalar = newVolumeScalar;
|
|
||||||
error = AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, newVolumeScalar, 0);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(error != noErr)
|
|
||||||
{
|
|
||||||
printf("SNDOSXSetVolume() ERROR: Could not set Audio Unit parameter -- Volume=%1.1f%%\n", newVolumeScalar * 100.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SNDOSXClearBuffer()
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(mutexSoundData);
|
|
||||||
|
|
||||||
if(sound_data != NULL)
|
|
||||||
{
|
|
||||||
memset(sound_data, 0, sound_buffer_size);
|
|
||||||
sound_position = 0;
|
|
||||||
sound_offset = SPU_STEREO_SAMPLE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
|
|
||||||
pthread_mutex_lock(mutexAudioUnit);
|
|
||||||
|
|
||||||
if(output_unit != NULL)
|
|
||||||
{
|
|
||||||
AudioUnitReset(output_unit, kAudioUnitScope_Global, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexAudioUnit);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
// Sound interface to the SPU
|
||||||
SoundInterface_struct SNDOSX = {
|
SoundInterface_struct SNDOSX = {
|
||||||
SNDCORE_OSX,
|
SNDCORE_OSX,
|
||||||
"Core Audio Sound Interface",
|
"OS X Core Audio Sound Interface",
|
||||||
SNDOSXInit,
|
SNDOSXInit,
|
||||||
SNDOSXDeInit,
|
SNDOSXDeInit,
|
||||||
SNDOSXUpdateAudio,
|
SNDOSXUpdateAudio,
|
||||||
|
@ -614,99 +39,102 @@ SoundInterface_struct SNDOSX = {
|
||||||
SNDOSXClearBuffer
|
SNDOSXClearBuffer
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
SoundInterface_struct *SNDCoreList[] = {
|
||||||
//Sound recording
|
&SNDDummy,
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
&SNDOSX,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
bool SNDOSXOpenFile(void *fname)
|
int SNDOSXInit(int buffer_size)
|
||||||
{
|
{
|
||||||
/*
|
if (coreAudioPlaybackManager != NULL)
|
||||||
if(sound_data == NULL)return false;
|
|
||||||
|
|
||||||
SNDOSXCloseFile();
|
|
||||||
|
|
||||||
if(!fname)return false;
|
|
||||||
|
|
||||||
NSString *filename = (NSString*)fname;
|
|
||||||
FSRef ref;
|
|
||||||
|
|
||||||
if(FSPathMakeRef((const UInt8*)[[filename stringByDeletingLastPathComponent] fileSystemRepresentation], &ref, NULL) != noErr)
|
|
||||||
{
|
{
|
||||||
SNDOSXStopRecording();
|
CoreAudioSound *oldcoreAudioPlaybackManager = coreAudioPlaybackManager;
|
||||||
return false;
|
coreAudioPlaybackManager = new CoreAudioSound(buffer_size / SPU_SAMPLE_SIZE, SPU_SAMPLE_SIZE);
|
||||||
|
delete oldcoreAudioPlaybackManager;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
AudioStreamBasicDescription audio_format;
|
{
|
||||||
audio_format.mSampleRate = SPU_SAMPLE_RATE;
|
coreAudioPlaybackManager = new CoreAudioSound(buffer_size / SPU_SAMPLE_SIZE, SPU_SAMPLE_SIZE);
|
||||||
audio_format.mFormatID = kAudioFormatLinearPCM;
|
}
|
||||||
audio_format.mFormatFlags = kAudioFormatFlagIsSignedInteger
|
|
||||||
| kAudioFormatFlagsNativeEndian
|
coreAudioPlaybackManager->start();
|
||||||
| kLinearPCMFormatFlagIsPacked;
|
|
||||||
audio_format.mBytesPerPacket = 4;
|
return 0;
|
||||||
audio_format.mFramesPerPacket = 1;
|
|
||||||
audio_format.mBytesPerFrame = 4;
|
|
||||||
audio_format.mChannelsPerFrame = 2;
|
|
||||||
audio_format.mBitsPerChannel = SPU_SAMPLE_RESOLUTION;
|
|
||||||
|
|
||||||
if(ExtAudioFileCreateNew(&ref, (CFStringRef)[[filename pathComponents] lastObject], kAudioFileWAVEType, &audio_format, NULL, &outfile) != noErr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
file_open = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
*/
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SNDOSXStartRecording()
|
void SNDOSXDeInit()
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(mutexSoundData);
|
delete coreAudioPlaybackManager;
|
||||||
|
coreAudioPlaybackManager = NULL;
|
||||||
if(sound_data == NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SNDOSXStopRecording()
|
int SNDOSXReset()
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(mutexSoundData);
|
SNDOSXClearBuffer();
|
||||||
|
|
||||||
if(sound_data == NULL)
|
return 0;
|
||||||
{
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SNDOSXCloseFile()
|
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(mutexSoundData);
|
if (coreAudioPlaybackManager != NULL)
|
||||||
|
|
||||||
if(sound_data == NULL)
|
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
coreAudioPlaybackManager->writeToBuffer(buffer, coreAudioPlaybackManager->getBuffer()->getElementSize() * (size_t)num_samples);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(file_open)
|
u32 SNDOSXGetAudioSpace()
|
||||||
|
{
|
||||||
|
u32 availableSamples = 0;
|
||||||
|
|
||||||
|
if (coreAudioPlaybackManager != NULL)
|
||||||
{
|
{
|
||||||
file_open = false;
|
availableSamples = (u32)coreAudioPlaybackManager->getAvailableSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableSamples;
|
||||||
|
}
|
||||||
|
|
||||||
//if it's rendering sound, wait until it's not
|
void SNDOSXMuteAudio()
|
||||||
//so we dont close the file while writing to it
|
{
|
||||||
|
if (coreAudioPlaybackManager != NULL)
|
||||||
|
{
|
||||||
|
coreAudioPlaybackManager->mute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SNDOSXUnMuteAudio()
|
||||||
|
{
|
||||||
|
if (coreAudioPlaybackManager != NULL)
|
||||||
|
{
|
||||||
|
coreAudioPlaybackManager->unmute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SNDOSXSetVolume(int volume)
|
||||||
|
{
|
||||||
|
if (coreAudioPlaybackManager != NULL)
|
||||||
|
{
|
||||||
|
float newVolumeScalar = (float)volume / 100.0f;
|
||||||
|
|
||||||
// Do something here, just not implemented yet...
|
if(volume > 100)
|
||||||
|
{
|
||||||
//ExtAudioFileDispose(outfile);
|
newVolumeScalar = 1.0f;
|
||||||
|
}
|
||||||
|
else if(volume < 0)
|
||||||
|
{
|
||||||
|
newVolumeScalar = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
coreAudioPlaybackManager->setVolume(newVolumeScalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(mutexSoundData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
void SNDOSXClearBuffer()
|
||||||
|
{
|
||||||
|
if (coreAudioPlaybackManager != NULL)
|
||||||
|
{
|
||||||
|
coreAudioPlaybackManager->clearBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2007 Jeff Bland
|
Copyright (C) 2007 Jeff Bland
|
||||||
Copyright (C) 2007-2011 DeSmuME team
|
Copyright (C) 2007-2012 DeSmuME team
|
||||||
|
|
||||||
This file is free software: you can redistribute it and/or modify
|
This file is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,30 +16,25 @@
|
||||||
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _OSXSOUNDINTERFACE_
|
||||||
|
#define _OSXSOUNDINTERFACE_
|
||||||
|
|
||||||
#include "../SPU.h"
|
#include "../SPU.h"
|
||||||
|
|
||||||
#define SNDCORE_OSX 58325 //hopefully this is unique number
|
#define SNDCORE_OSX 58325 //hopefully this is unique number
|
||||||
|
|
||||||
|
// Sound interface to the SPU
|
||||||
// This is the sound interface so the emulator core can send us sound info and whatnot
|
|
||||||
extern SoundInterface_struct SNDOSX;
|
extern SoundInterface_struct SNDOSX;
|
||||||
|
|
||||||
// Sound interface extensions for CoreAudio
|
// Core Audio functions for the sound interface
|
||||||
void SNDOSXStartup();
|
int SNDOSXInit(int buffer_size);
|
||||||
void SNDOSXShutdown();
|
void SNDOSXDeInit();
|
||||||
int SNDOSXInit(int buffer_size);
|
int SNDOSXReset();
|
||||||
void SNDOSXDeInit();
|
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples);
|
||||||
int SNDOSXReset();
|
u32 SNDOSXGetAudioSpace();
|
||||||
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples);
|
void SNDOSXMuteAudio();
|
||||||
u32 SNDOSXGetAudioSpace();
|
void SNDOSXUnMuteAudio();
|
||||||
void SNDOSXMuteAudio();
|
void SNDOSXSetVolume(int volume);
|
||||||
void SNDOSXUnMuteAudio();
|
void SNDOSXClearBuffer();
|
||||||
void SNDOSXSetVolume(int volume);
|
|
||||||
void SNDOSXClearBuffer();
|
|
||||||
|
|
||||||
// Recording
|
#endif // _OSXSOUNDINTERFACE_
|
||||||
// Not supported as of 2011/12/28 - rogerman
|
|
||||||
bool SNDOSXOpenFile(void *fname); //opens a file for recording (if filename is the currently opened one, it will restart the file), fname is an NSString
|
|
||||||
void SNDOSXStartRecording(); //begins recording to the currently open file if there is an open file
|
|
||||||
void SNDOSXStopRecording(); //pauses recording (you can continue recording later)
|
|
||||||
void SNDOSXCloseFile(); //closes the file, making sure it's saved
|
|
||||||
|
|
|
@ -188,8 +188,7 @@
|
||||||
[NSThread detachNewThreadSelector:@selector(runThread:) toTarget:newSpeaker withObject:nil];
|
[NSThread detachNewThreadSelector:@selector(runThread:) toTarget:newSpeaker withObject:nil];
|
||||||
|
|
||||||
// Wait until the GPU and SPU are finished starting up.
|
// Wait until the GPU and SPU are finished starting up.
|
||||||
while (!([CocoaDSSpeaker isSPUStarted] &&
|
while ([newComboDisplay thread] == nil || [newSpeaker thread] == nil)
|
||||||
[newComboDisplay thread] != nil && [newSpeaker thread] != nil))
|
|
||||||
{
|
{
|
||||||
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
|
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,8 +117,6 @@ void joinThread_gdb(void *thread_handle)
|
||||||
|
|
||||||
[aboutWindowController setContent:aboutWindowProperties];
|
[aboutWindowController setContent:aboutWindowProperties];
|
||||||
|
|
||||||
SNDOSXStartup();
|
|
||||||
|
|
||||||
//Set default values for all preferences
|
//Set default values for all preferences
|
||||||
//(this wont override saved preferences as
|
//(this wont override saved preferences as
|
||||||
//they work in different preference domains)
|
//they work in different preference domains)
|
||||||
|
@ -192,8 +190,6 @@ void joinThread_gdb(void *thread_handle)
|
||||||
|
|
||||||
[cdsCore release];
|
[cdsCore release];
|
||||||
[cdsCoreController setContent:nil];
|
[cdsCoreController setContent:nil];
|
||||||
|
|
||||||
SNDOSXShutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction) showSupportFolderInFinder:(id)sender
|
- (IBAction) showSupportFolderInFinder:(id)sender
|
||||||
|
|
Loading…
Reference in New Issue