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 */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
|
@ -787,6 +795,10 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -870,15 +882,19 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
ABC3ADEC14B7DC6E00D5B13D /* userinterface */,
|
||||
ABD0A5621501AC5C0074A094 /* coreaudiosound.cpp */,
|
||||
ABD0A5631501AC5C0074A094 /* ringbuffer.cpp */,
|
||||
ABF4007E14B4F1C000578AE7 /* sndOSX.cpp */,
|
||||
ABBF053B14B543B600E505A0 /* cocoa_file.h */,
|
||||
ABF95B4714B4F4FC007912B8 /* cocoa_globals.h */,
|
||||
ABE240F314BE3169006EA2D5 /* cocoa_input_legacy.h */,
|
||||
AB8FE37414B652EC009E20B1 /* cocoa_util.h */,
|
||||
ABD0A5641501AC5C0074A094 /* coreaudiosound.h */,
|
||||
ABE240F514BE3169006EA2D5 /* input_legacy.h */,
|
||||
AB8FE30A14B647D6009E20B1 /* macosx_10_4_compat.h */,
|
||||
ABE240F714BE3169006EA2D5 /* nds_control_legacy.h */,
|
||||
ABE240F914BE3169006EA2D5 /* preferences_legacy.h */,
|
||||
ABD0A5651501AC5C0074A094 /* ringbuffer.h */,
|
||||
ABE240FB14BE3169006EA2D5 /* screen_state_legacy.h */,
|
||||
AB06CB49135B8A4D00E977B3 /* sndOSX.h */,
|
||||
ABE240FD14BE3169006EA2D5 /* video_output_view_legacy.h */,
|
||||
|
@ -1744,6 +1760,8 @@
|
|||
ABE2410E14BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||
ABE2410F14BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||
ABE2411014BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||
ABD0A5681501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||
ABD0A5691501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1851,6 +1869,8 @@
|
|||
ABE2411414BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||
ABE2411514BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||
ABE2411614BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||
ABD0A56C1501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||
ABD0A56D1501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1958,6 +1978,8 @@
|
|||
ABE2410214BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||
ABE2410314BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||
ABE2410414BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||
ABD0A5661501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||
ABD0A5671501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2065,6 +2087,8 @@
|
|||
ABE2410814BE3169006EA2D5 /* preferences_legacy.mm in Sources */,
|
||||
ABE2410914BE3169006EA2D5 /* screen_state_legacy.m in Sources */,
|
||||
ABE2410A14BE3169006EA2D5 /* video_output_view_legacy.mm in Sources */,
|
||||
ABD0A56A1501AC5C0074A094 /* coreaudiosound.cpp in Sources */,
|
||||
ABD0A56B1501AC5C0074A094 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -296,6 +296,10 @@
|
|||
ABC5720D1344346600E7B0B1 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97324FDCFA39411CA2CEA /* AppKit.framework */; };
|
||||
ABC572101344347000E7B0B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97325FDCFA39411CA2CEA /* Foundation.framework */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
|
@ -530,6 +534,10 @@
|
|||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -776,6 +784,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
AB3ACB6514C2361100D7D192 /* userinterface */,
|
||||
ABD0A5341501AA5A0074A094 /* coreaudiosound.cpp */,
|
||||
ABD0A5351501AA5A0074A094 /* ringbuffer.cpp */,
|
||||
ABD104141346652500AF11D1 /* sndOSX.cpp */,
|
||||
AB817A35143EE2DB00A7DFE9 /* videofilter.cpp */,
|
||||
ABA6574914511EC90077E5E9 /* cocoa_cheat.h */,
|
||||
|
@ -790,13 +800,15 @@
|
|||
ABD104001346652500AF11D1 /* cocoa_rom.h */,
|
||||
AB80E050142BC4FA00A52038 /* cocoa_util.h */,
|
||||
ABE5DFE3143FB1DA00835AD8 /* cocoa_videofilter.h */,
|
||||
ABD0A5361501AA5A0074A094 /* coreaudiosound.h */,
|
||||
ABD0A5371501AA5A0074A094 /* ringbuffer.h */,
|
||||
ABD104011346652500AF11D1 /* sndOSX.h */,
|
||||
AB817A34143EE2DB00A7DFE9 /* videofilter.h */,
|
||||
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
||||
ABA6574A14511EC90077E5E9 /* cocoa_cheat.mm */,
|
||||
ABD104121346652500AF11D1 /* cocoa_core.mm */,
|
||||
AB58F32C1364F44B0074C376 /* cocoa_file.mm */,
|
||||
ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */,
|
||||
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
||||
ABD104111346652500AF11D1 /* cocoa_input.mm */,
|
||||
ABD9A46413DB99B300777194 /* cocoa_mic.mm */,
|
||||
AB3E34C8134AF4500056477A /* cocoa_output.mm */,
|
||||
|
@ -1665,6 +1677,8 @@
|
|||
ABFE150B14C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||
ABFE150D14C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||
ABFE150E14C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||
ABD0A5381501AA5A0074A094 /* coreaudiosound.cpp in Sources */,
|
||||
ABD0A5391501AA5A0074A094 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1787,6 +1801,8 @@
|
|||
ABFE151314C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||
ABFE151514C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||
ABFE151614C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||
ABD0A53A1501AA5A0074A094 /* coreaudiosound.cpp in Sources */,
|
||||
ABD0A53B1501AA5A0074A094 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -104,6 +104,12 @@
|
|||
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 */; };
|
||||
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 */; };
|
||||
AB1F469813A0AE2F00B80DE6 /* Timestretcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABD1FF9B1345ACFA00AF11D1 /* Timestretcher.cpp */; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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; };
|
||||
|
@ -985,6 +995,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
AB3ACB6514C2361100D7D192 /* userinterface */,
|
||||
AB1B9E5F1501A78000464647 /* coreaudiosound.cpp */,
|
||||
AB1B9E601501A78000464647 /* ringbuffer.cpp */,
|
||||
ABD104141346652500AF11D1 /* sndOSX.cpp */,
|
||||
AB817A35143EE2DB00A7DFE9 /* videofilter.cpp */,
|
||||
ABA6574914511EC90077E5E9 /* cocoa_cheat.h */,
|
||||
|
@ -999,13 +1011,15 @@
|
|||
ABD104001346652500AF11D1 /* cocoa_rom.h */,
|
||||
AB80E050142BC4FA00A52038 /* cocoa_util.h */,
|
||||
ABE5DFE3143FB1DA00835AD8 /* cocoa_videofilter.h */,
|
||||
AB1B9E611501A78000464647 /* coreaudiosound.h */,
|
||||
AB1B9E621501A78000464647 /* ringbuffer.h */,
|
||||
ABD104011346652500AF11D1 /* sndOSX.h */,
|
||||
AB817A34143EE2DB00A7DFE9 /* videofilter.h */,
|
||||
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
||||
ABA6574A14511EC90077E5E9 /* cocoa_cheat.mm */,
|
||||
ABD104121346652500AF11D1 /* cocoa_core.mm */,
|
||||
AB58F32C1364F44B0074C376 /* cocoa_file.mm */,
|
||||
ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */,
|
||||
AB350B691478A5B3007165AC /* cocoa_hid.mm */,
|
||||
ABD104111346652500AF11D1 /* cocoa_input.mm */,
|
||||
ABD9A46413DB99B300777194 /* cocoa_mic.mm */,
|
||||
AB3E34C8134AF4500056477A /* cocoa_output.mm */,
|
||||
|
@ -1554,7 +1568,7 @@
|
|||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0420;
|
||||
LastUpgradeCheck = 0430;
|
||||
ORGANIZATIONNAME = "DeSmuME Team";
|
||||
};
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME (XCode 4)" */;
|
||||
|
@ -1990,6 +2004,8 @@
|
|||
ABFE150B14C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||
ABFE150D14C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||
ABFE150E14C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||
AB1B9E631501A78000464647 /* coreaudiosound.cpp in Sources */,
|
||||
AB1B9E661501A78000464647 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2112,6 +2128,8 @@
|
|||
ABFE151314C92FF5005D6699 /* hq4x.cpp in Sources */,
|
||||
ABFE151514C92FF5005D6699 /* lq2x.cpp in Sources */,
|
||||
ABFE151614C92FF5005D6699 /* scanline.cpp in Sources */,
|
||||
AB1B9E641501A78000464647 /* coreaudiosound.cpp in Sources */,
|
||||
AB1B9E671501A78000464647 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2234,6 +2252,8 @@
|
|||
ABB715FB14E386740027FE88 /* hq4x.cpp in Sources */,
|
||||
ABB715FC14E386740027FE88 /* lq2x.cpp in Sources */,
|
||||
ABB715FD14E386740027FE88 /* scanline.cpp in Sources */,
|
||||
AB1B9E651501A78000464647 /* coreaudiosound.cpp in Sources */,
|
||||
AB1B9E681501A78000464647 /* ringbuffer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2389,7 +2409,6 @@
|
|||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
LLVM_LTO = NO;
|
||||
PRODUCT_NAME = DeSmuME;
|
||||
SDKROOT = macosx10.7;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
|
|
|
@ -39,6 +39,13 @@
|
|||
<key>Save State</key>
|
||||
<string>${APPSUPPORT}</string>
|
||||
</dict>
|
||||
<key>OpenEmu</key>
|
||||
<dict>
|
||||
<key>ROM Save</key>
|
||||
<string>${OPENEMU}</string>
|
||||
<key>Save State</key>
|
||||
<string>${OPENEMU}</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<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) saveState:(NSURL *)saveStateURL;
|
||||
+ (BOOL) loadRom:(NSURL *)romURL;
|
||||
|
@ -38,6 +41,8 @@
|
|||
+ (BOOL) romSaveExists:(NSURL *)romURL;
|
||||
+ (BOOL) romSaveExistsWithRom:(NSURL *)romURL;
|
||||
+ (void) setupAllFilePaths;
|
||||
+ (void) setupAllFilePathsWithURLDictionary:(NSString *)URLDictionaryKey;
|
||||
+ (void) setupAllFilePathsForVersion:(NSString *)versionString port:(NSString *)portString;
|
||||
+ (BOOL) setupAllAppDirectories;
|
||||
+ (NSURL *) saveStateURL;
|
||||
+ (BOOL) saveScreenshot:(NSURL *)fileURL bitmapData:(NSBitmapImageRep *)bitmapImageRep fileType:(NSBitmapImageFileType)fileType;
|
||||
|
|
|
@ -28,6 +28,110 @@
|
|||
|
||||
@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 result = NO;
|
||||
|
@ -107,6 +211,7 @@
|
|||
|
||||
switch (fileTypeID)
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||
case ROMSAVEFORMAT_DESMUME:
|
||||
{
|
||||
NSString *destinationPath = [[destinationURL path] stringByAppendingPathExtension:@FILE_EXT_ROM_SAVE];
|
||||
|
@ -115,7 +220,7 @@
|
|||
[fileManager release];
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
case ROMSAVEFORMAT_NOGBA:
|
||||
{
|
||||
const char *destinationPath = [[[destinationURL path] stringByAppendingPathExtension:@FILE_EXT_ROM_SAVE_NOGBA] cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
|
@ -191,57 +296,174 @@
|
|||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
strlcpy(path.pathToLua, [[luaURL path] cStringUsingEncoding:NSUTF8StringEncoding], MAX_PATH);
|
||||
|
@ -283,6 +505,11 @@
|
|||
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])
|
||||
{
|
||||
continue;
|
||||
|
@ -583,6 +810,14 @@
|
|||
{
|
||||
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])
|
||||
{
|
||||
return fileURL;
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
|
||||
#define PATH_CONFIG_DIRECTORY_0_9_6 "~/.config/desmume"
|
||||
#define PATH_USER_APP_SUPPORT "${APPSUPPORT}"
|
||||
#define PATH_OPEN_EMU "${OPENEMU}"
|
||||
#define PATH_WITH_ROM "${WITHROM}"
|
||||
|
||||
#define FILE_EXT_FIRMWARE_CONFIG "dfc"
|
||||
|
@ -162,8 +163,9 @@
|
|||
|
||||
#define SPU_SAMPLE_RATE 44100 // Samples per second
|
||||
#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_BUFFER_BYTES ((SPU_SAMPLE_RATE / DS_FRAMES_PER_SECOND) * SPU_STEREO_SAMPLE_SIZE)
|
||||
#define SPU_NUMBER_CHANNELS 2 // Number of channels
|
||||
#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.
|
||||
|
||||
|
|
|
@ -62,10 +62,6 @@
|
|||
- (id) initWithVolume:(CGFloat)vol;
|
||||
- (void) dealloc;
|
||||
|
||||
+ (BOOL) startupSPU;
|
||||
+ (void) shutdownSPU;
|
||||
+ (BOOL) isSPUStarted;
|
||||
|
||||
- (void) setVolume:(float)vol;
|
||||
- (float) volume;
|
||||
- (void) setAudioOutputEngine:(NSInteger)methodID;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#import "cocoa_util.h"
|
||||
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include "sndOSX.h"
|
||||
|
||||
#include "../NDSSystem.h"
|
||||
#include "../GPU.h"
|
||||
|
@ -40,12 +39,6 @@ GPU3DInterface *core3DList[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
SoundInterface_struct *SNDCoreList[] = {
|
||||
&SNDDummy,
|
||||
&SNDOSX,
|
||||
NULL
|
||||
};
|
||||
|
||||
@implementation CocoaDSOutput
|
||||
|
||||
@synthesize isStateChanged;
|
||||
|
@ -133,8 +126,6 @@ SoundInterface_struct *SNDCoreList[] = {
|
|||
|
||||
@synthesize bufferSize;
|
||||
|
||||
static BOOL isSPUStarted = NO;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithVolume:MAX_VOLUME];
|
||||
|
@ -161,7 +152,7 @@ static BOOL isSPUStarted = NO;
|
|||
[property setValue:[NSNumber numberWithFloat:(float)vol] forKey:@"volume"];
|
||||
[property setValue:[NSNumber numberWithBool:NO] forKey:@"mute"];
|
||||
[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 numberWithInteger:SPUInterpolation_None] forKey:@"spuInterpolationMode"];
|
||||
[property setValue:[NSNumber numberWithInteger:SPU_SYNC_MODE_DUAL_SYNC_ASYNC] forKey:@"spuSyncMode"];
|
||||
|
@ -175,43 +166,6 @@ static BOOL isSPUStarted = NO;
|
|||
[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
|
||||
{
|
||||
if (vol < 0.0f)
|
||||
|
@ -227,12 +181,7 @@ static BOOL isSPUStarted = NO;
|
|||
[property setValue:[NSNumber numberWithFloat:vol] forKey:@"volume"];
|
||||
OSSpinLockUnlock(&spinlockVolume);
|
||||
|
||||
if (isSPUStarted)
|
||||
{
|
||||
//pthread_mutex_lock(self.mutexOutputFrame);
|
||||
SPU_SetVolume((int)vol);
|
||||
//pthread_mutex_unlock(self.mutexOutputFrame);
|
||||
}
|
||||
SPU_SetVolume((int)vol);
|
||||
}
|
||||
|
||||
- (float) volume
|
||||
|
@ -253,15 +202,10 @@ static BOOL isSPUStarted = NO;
|
|||
pthread_mutex_lock(self.mutexOutputFrame);
|
||||
|
||||
NSInteger result = -1;
|
||||
switch (methodID)
|
||||
|
||||
if (methodID != SNDCORE_DUMMY)
|
||||
{
|
||||
case SNDCORE_OSX:
|
||||
result = SPU_ChangeSoundCore(methodID, (int)SPU_BUFFER_BYTES);
|
||||
break;
|
||||
|
||||
default:
|
||||
SPU_ChangeSoundCore(SNDCORE_DUMMY, 0);
|
||||
break;
|
||||
result = SPU_ChangeSoundCore(methodID, (int)SPU_BUFFER_BYTES);
|
||||
}
|
||||
|
||||
if(result == -1)
|
||||
|
@ -377,16 +321,13 @@ static BOOL isSPUStarted = NO;
|
|||
{
|
||||
[property setValue:[NSNumber numberWithBool:mute] forKey:@"mute"];
|
||||
|
||||
if (isSPUStarted)
|
||||
if (mute)
|
||||
{
|
||||
if (mute)
|
||||
{
|
||||
SPU_SetVolume(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SPU_SetVolume((int)[self volume]);
|
||||
}
|
||||
SPU_SetVolume(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SPU_SetVolume((int)[self volume]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,16 +341,6 @@ static BOOL isSPUStarted = NO;
|
|||
[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
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
SoundInterface_struct *SNDCoreList[] = {
|
||||
&SNDDummy,
|
||||
&SNDOSX,
|
||||
NULL
|
||||
};
|
||||
|
||||
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 <CoreServices/CoreServices.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "coreaudiosound.h"
|
||||
#include "cocoa_globals.h"
|
||||
|
||||
|
||||
//globals
|
||||
static AudioUnit output_unit = NULL; //pointer to our audio device
|
||||
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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Global sound playback manager
|
||||
static CoreAudioSound *coreAudioPlaybackManager = NULL;
|
||||
|
||||
// Sound interface to the SPU
|
||||
SoundInterface_struct SNDOSX = {
|
||||
SNDCORE_OSX,
|
||||
"Core Audio Sound Interface",
|
||||
"OS X Core Audio Sound Interface",
|
||||
SNDOSXInit,
|
||||
SNDOSXDeInit,
|
||||
SNDOSXUpdateAudio,
|
||||
|
@ -614,99 +39,102 @@ SoundInterface_struct SNDOSX = {
|
|||
SNDOSXClearBuffer
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//Sound recording
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
SoundInterface_struct *SNDCoreList[] = {
|
||||
&SNDDummy,
|
||||
&SNDOSX,
|
||||
NULL
|
||||
};
|
||||
|
||||
bool SNDOSXOpenFile(void *fname)
|
||||
int SNDOSXInit(int buffer_size)
|
||||
{
|
||||
/*
|
||||
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)
|
||||
if (coreAudioPlaybackManager != NULL)
|
||||
{
|
||||
SNDOSXStopRecording();
|
||||
return false;
|
||||
CoreAudioSound *oldcoreAudioPlaybackManager = coreAudioPlaybackManager;
|
||||
coreAudioPlaybackManager = new CoreAudioSound(buffer_size / SPU_SAMPLE_SIZE, SPU_SAMPLE_SIZE);
|
||||
delete oldcoreAudioPlaybackManager;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(ExtAudioFileCreateNew(&ref, (CFStringRef)[[filename pathComponents] lastObject], kAudioFileWAVEType, &audio_format, NULL, &outfile) != noErr)
|
||||
return false;
|
||||
|
||||
file_open = true;
|
||||
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
else
|
||||
{
|
||||
coreAudioPlaybackManager = new CoreAudioSound(buffer_size / SPU_SAMPLE_SIZE, SPU_SAMPLE_SIZE);
|
||||
}
|
||||
|
||||
coreAudioPlaybackManager->start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SNDOSXStartRecording()
|
||||
void SNDOSXDeInit()
|
||||
{
|
||||
pthread_mutex_lock(mutexSoundData);
|
||||
|
||||
if(sound_data == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
delete coreAudioPlaybackManager;
|
||||
coreAudioPlaybackManager = NULL;
|
||||
}
|
||||
|
||||
void SNDOSXStopRecording()
|
||||
int SNDOSXReset()
|
||||
{
|
||||
pthread_mutex_lock(mutexSoundData);
|
||||
|
||||
if(sound_data == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
SNDOSXClearBuffer();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SNDOSXCloseFile()
|
||||
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples)
|
||||
{
|
||||
pthread_mutex_lock(mutexSoundData);
|
||||
|
||||
if(sound_data == NULL)
|
||||
if (coreAudioPlaybackManager != NULL)
|
||||
{
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
return;
|
||||
coreAudioPlaybackManager->writeToBuffer(buffer, coreAudioPlaybackManager->getBuffer()->getElementSize() * (size_t)num_samples);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
//so we dont close the file while writing to it
|
||||
void SNDOSXMuteAudio()
|
||||
{
|
||||
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...
|
||||
|
||||
//ExtAudioFileDispose(outfile);
|
||||
if(volume > 100)
|
||||
{
|
||||
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-2011 DeSmuME team
|
||||
Copyright (C) 2007-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
|
||||
|
@ -16,30 +16,25 @@
|
|||
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _OSXSOUNDINTERFACE_
|
||||
#define _OSXSOUNDINTERFACE_
|
||||
|
||||
#include "../SPU.h"
|
||||
|
||||
#define SNDCORE_OSX 58325 //hopefully this is unique number
|
||||
|
||||
|
||||
// This is the sound interface so the emulator core can send us sound info and whatnot
|
||||
// Sound interface to the SPU
|
||||
extern SoundInterface_struct SNDOSX;
|
||||
|
||||
// Sound interface extensions for CoreAudio
|
||||
void SNDOSXStartup();
|
||||
void SNDOSXShutdown();
|
||||
int SNDOSXInit(int buffer_size);
|
||||
void SNDOSXDeInit();
|
||||
int SNDOSXReset();
|
||||
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples);
|
||||
u32 SNDOSXGetAudioSpace();
|
||||
void SNDOSXMuteAudio();
|
||||
void SNDOSXUnMuteAudio();
|
||||
void SNDOSXSetVolume(int volume);
|
||||
void SNDOSXClearBuffer();
|
||||
// Core Audio functions for the sound interface
|
||||
int SNDOSXInit(int buffer_size);
|
||||
void SNDOSXDeInit();
|
||||
int SNDOSXReset();
|
||||
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples);
|
||||
u32 SNDOSXGetAudioSpace();
|
||||
void SNDOSXMuteAudio();
|
||||
void SNDOSXUnMuteAudio();
|
||||
void SNDOSXSetVolume(int volume);
|
||||
void SNDOSXClearBuffer();
|
||||
|
||||
// Recording
|
||||
// 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
|
||||
#endif // _OSXSOUNDINTERFACE_
|
||||
|
|
|
@ -188,8 +188,7 @@
|
|||
[NSThread detachNewThreadSelector:@selector(runThread:) toTarget:newSpeaker withObject:nil];
|
||||
|
||||
// Wait until the GPU and SPU are finished starting up.
|
||||
while (!([CocoaDSSpeaker isSPUStarted] &&
|
||||
[newComboDisplay thread] != nil && [newSpeaker thread] != nil))
|
||||
while ([newComboDisplay thread] == nil || [newSpeaker thread] == nil)
|
||||
{
|
||||
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
|
||||
}
|
||||
|
|
|
@ -117,8 +117,6 @@ void joinThread_gdb(void *thread_handle)
|
|||
|
||||
[aboutWindowController setContent:aboutWindowProperties];
|
||||
|
||||
SNDOSXStartup();
|
||||
|
||||
//Set default values for all preferences
|
||||
//(this wont override saved preferences as
|
||||
//they work in different preference domains)
|
||||
|
@ -192,8 +190,6 @@ void joinThread_gdb(void *thread_handle)
|
|||
|
||||
[cdsCore release];
|
||||
[cdsCoreController setContent:nil];
|
||||
|
||||
SNDOSXShutdown();
|
||||
}
|
||||
|
||||
- (IBAction) showSupportFolderInFinder:(id)sender
|
||||
|
|
Loading…
Reference in New Issue