Cocoa Port:
- Major rewrite of the OS X Core Audio backend code! This brings performance improvements, bug fixes, and general code cleanup. - Remove all Objective-C code from sndOSX.mm, and change into a pure C++ file. - Fixed audio noise issues that intermittently occurred while the emulation was running. This most often occurred after a ROM has been loaded. - Fix possible crash on application exit.
This commit is contained in:
parent
861308954f
commit
719e210de6
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
Copyright (C) 2011 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/>.
|
||||
*/
|
||||
|
||||
#define STRING_DESMUME_WEBSITE "http://www.desmume.org"
|
||||
#define STRING_DESMUME_FORUM_SITE "http://forums.desmume.org/index.php"
|
||||
#define STRING_DESMUME_BUG_SITE "http://sourceforge.net/tracker/?group_id=164579&atid=832291"
|
||||
|
||||
#define NSSTRING_TITLE_OPEN_ROM_PANEL NSLocalizedString(@"Open ROM", nil)
|
||||
#define NSSTRING_TITLE_OPEN_STATE_FILE_PANEL NSLocalizedString(@"Open State File", nil)
|
||||
#define NSSTRING_TITLE_SAVE_STATE_FILE_PANEL NSLocalizedString(@"Save State File", nil)
|
||||
#define NSSTRING_TITLE_IMPORT_BACKUP_MEMORY_PANEL NSLocalizedString(@"Import Backup Memory", nil)
|
||||
#define NSSTRING_TITLE_EXPORT_BACKUP_MEMORY_PANEL NSLocalizedString(@"Export Backup Memory", nil)
|
||||
#define NSSTRING_TITLE_SELECT_ROM_PANEL NSLocalizedString(@"Select ROM", nil)
|
||||
#define NSSTRING_TITLE_SELECT_ADVANSCENE_DB_PANEL NSLocalizedString(@"Select ADVANsCEne Database", nil)
|
||||
#define NSSTRING_TITLE_SELECT_R4_CHEAT_DB_PANEL NSLocalizedString(@"Select R4 Cheat Database", nil)
|
||||
#define NSSTRING_TITLE_SELECT_ARM7_IMAGE_PANEL NSLocalizedString(@"Select ARM7 BIOS Image", nil)
|
||||
#define NSSTRING_TITLE_SELECT_ARM9_IMAGE_PANEL NSLocalizedString(@"Select ARM9 BIOS Image", nil)
|
||||
#define NSSTRING_TITLE_SELECT_FIRMWARE_IMAGE_PANEL NSLocalizedString(@"Select Firmware Image", nil)
|
||||
|
||||
#define NSSTRING_TITLE_EXECUTE_CONTROL NSLocalizedString(@"Execute", nil)
|
||||
#define NSSTRING_TITLE_PAUSE_CONTROL NSLocalizedString(@"Pause", nil)
|
||||
#define NSSTRING_TITLE_DISABLE_SPEED_LIMIT NSLocalizedString(@"Disable Speed Limit", nil)
|
||||
#define NSSTRING_TITLE_ENABLE_SPEED_LIMIT NSLocalizedString(@"Enable Speed Limit", nil)
|
||||
#define NSSTRING_TITLE_DISABLE_AUTO_FRAME_SKIP NSLocalizedString(@"Disable Auto Frame Skip", nil)
|
||||
#define NSSTRING_TITLE_ENABLE_AUTO_FRAME_SKIP NSLocalizedString(@"Enable Auto Frame Skip", nil)
|
||||
#define NSSTRING_TITLE_DISABLE_CHEATS NSLocalizedString(@"Disable Cheats", nil)
|
||||
#define NSSTRING_TITLE_ENABLE_CHEATS NSLocalizedString(@"Enable Cheats", nil)
|
||||
#define NSSTRING_TITLE_DISABLE_HUD NSLocalizedString(@"Disable HUD", nil)
|
||||
#define NSSTRING_TITLE_ENABLE_HUD NSLocalizedString(@"Enable HUD", nil)
|
||||
#define NSSTRING_TITLE_SPEED_1X NSLocalizedString(@"Speed 1x", nil)
|
||||
#define NSSTRING_TITLE_SPEED_2X NSLocalizedString(@"Speed 2x", nil)
|
||||
#define NSSTRING_TITLE_SLOT_NUMBER NSLocalizedString(@"Slot %d", nil)
|
||||
|
||||
#define NSSTRING_ALERT_CRITICAL_FILE_MISSING_PRI NSLocalizedString(@"A critical file is missing. DeSmuME will now quit.", nil)
|
||||
#define NSSTRING_ALERT_CRITICAL_FILE_MISSING_SEC NSLocalizedString(@"The file \"DefaultUserPrefs.plist\" is missing. Please reinstall DeSmuME.", nil)
|
||||
|
||||
#define NSSTRING_STATUS_READY NSLocalizedString(@"Ready.", nil)
|
||||
#define NSSTRING_STATUS_SAVESTATE_LOADING_FAILED NSLocalizedString(@"Save state file loading failed!", nil)
|
||||
#define NSSTRING_STATUS_SAVESTATE_LOADED NSLocalizedString(@"Save state file loaded.", nil)
|
||||
#define NSSTRING_STATUS_SAVESTATE_SAVING_FAILED NSLocalizedString(@"Save state file saving failed!", nil)
|
||||
#define NSSTRING_STATUS_SAVESTATE_SAVED NSLocalizedString(@"Save state file saved.", nil)
|
||||
#define NSSTRING_STATUS_SAVESTATE_REVERTING_FAILED NSLocalizedString(@"Save state file reverting failed!", nil)
|
||||
#define NSSTRING_STATUS_SAVESTATE_REVERTED NSLocalizedString(@"Save state file reverted.", nil)
|
||||
#define NSSTRING_STATUS_BATTERY_IMPORT_FAILED NSLocalizedString(@"Battery file import failed!", nil)
|
||||
#define NSSTRING_STATUS_BATTERY_IMPORTED NSLocalizedString(@"Battery save file imported.", nil)
|
||||
#define NSSTRING_STATUS_BATTERY_EXPORT_FAILED NSLocalizedString(@"Battery file export failed!", nil)
|
||||
#define NSSTRING_STATUS_BATTERY_EXPORTED NSLocalizedString(@"Battery save file exported.", nil)
|
||||
#define NSSTRING_STATUS_ROM_LOADING NSLocalizedString(@"Loading ROM...", nil)
|
||||
#define NSSTRING_STATUS_ROM_LOADING_FAILED NSLocalizedString(@"ROM loading failed!", nil)
|
||||
#define NSSTRING_STATUS_ROM_LOADED NSLocalizedString(@"ROM loaded.", nil)
|
||||
#define NSSTRING_STATUS_ROM_UNLOADING NSLocalizedString(@"Unloading ROM...", nil)
|
||||
#define NSSTRING_STATUS_ROM_UNLOADED NSLocalizedString(@"ROM unloaded.", nil)
|
||||
#define NSSTRING_STATUS_EMULATOR_RESETTING NSLocalizedString(@"Emulator resetting...", nil)
|
||||
#define NSSTRING_STATUS_EMULATOR_RESET NSLocalizedString(@"Emulator reset.", nil)
|
||||
#define NSSTRING_STATUS_CANNOT_GENERATE_SAVE_PATH NSLocalizedString(@"Cannot generate the save file path!", nil)
|
||||
#define NSSTRING_STATUS_CANNOT_CREATE_SAVE_DIRECTORY NSLocalizedString(@"Cannot create the save directory!", nil)
|
||||
|
||||
#define NSSTRING_STATUS_SPEED_LIMIT_DISABLED NSLocalizedString(@"Speed limit disabled.", nil)
|
||||
#define NSSTRING_STATUS_SPEED_LIMIT_ENABLED NSLocalizedString(@"Speed limit enabled.", nil)
|
||||
#define NSSTRING_STATUS_AUTO_FRAME_SKIP_DISABLED NSLocalizedString(@"Auto frame skip disabled.", nil)
|
||||
#define NSSTRING_STATUS_AUTO_FRAME_SKIP_ENABLED NSLocalizedString(@"Auto frame skip enabled.", nil)
|
||||
#define NSSTRING_STATUS_CHEATS_DISABLED NSLocalizedString(@"Cheats disabled.", nil)
|
||||
#define NSSTRING_STATUS_CHEATS_ENABLED NSLocalizedString(@"Cheats enabled.", nil)
|
||||
#define NSSTRING_STATUS_HUD_DISABLED NSLocalizedString(@"HUD disabled.", nil)
|
||||
#define NSSTRING_STATUS_HUD_ENABLED NSLocalizedString(@"HUD enabled.", nil)
|
||||
#define NSSTRING_STATUS_VOLUME NSLocalizedString(@"Volume: %1.1f%%", nil)
|
||||
#define NSSTRING_STATUS_NO_ROM_LOADED NSLocalizedString(@"No ROM loaded.", nil)
|
||||
#define NSSTRING_STATUS_SIZE_BYTES NSLocalizedString(@"%i bytes", nil)
|
||||
|
||||
#define NSSTRING_DISPLAYMODE_MAIN NSLocalizedString(@"Main", nil)
|
||||
#define NSSTRING_DISPLAYMODE_TOUCH NSLocalizedString(@"Touch", nil)
|
||||
#define NSSTRING_DISPLAYMODE_COMBO NSLocalizedString(@"Combo", nil)
|
||||
|
||||
#define PATH_CONFIG_DIRECTORY_0_9_6 "~/.config/desmume"
|
||||
|
||||
#define FILE_EXT_FIRMWARE_CONFIG "dfc"
|
||||
#define FILE_EXT_SAVE_STATE "dst"
|
||||
#define FILE_EXT_ROM_SAVE "dsv"
|
||||
#define FILE_EXT_CHEAT "dct"
|
||||
#define FILE_EXT_ROM_SAVE_NOGBA "sav"
|
||||
#define FILE_EXT_ACTION_REPLAY_SAVE "duc"
|
||||
#define FILE_EXT_ROM_DS "nds"
|
||||
#define FILE_EXT_ROM_GBA "ds.gba"
|
||||
#define FILE_EXT_HW_IMAGE_FILE "bin"
|
||||
#define FILE_EXT_ADVANSCENE_DB "xml"
|
||||
#define FILE_EXT_R4_CHEAT_DB "dat"
|
||||
|
||||
#define MAX_SAVESTATE_SLOTS 10
|
||||
|
||||
#define MAX_VOLUME 100.0f
|
||||
#define MAX_BRIGHTNESS 100.0f
|
||||
|
||||
#define CHEAT_DESCRIPTION_LENGTH 1024
|
||||
|
||||
#define GPU_DISPLAY_WIDTH 256
|
||||
#define GPU_DISPLAY_HEIGHT 192
|
||||
#define GPU_DISPLAY_COLOR_DEPTH sizeof(UInt16)
|
||||
#define GPU_SCREEN_SIZE_BYTES (GPU_DISPLAY_WIDTH * GPU_DISPLAY_HEIGHT * GPU_DISPLAY_COLOR_DEPTH) // The numbers are: 256px width, 192px height, 16bit color depth
|
||||
|
||||
#define WINDOW_STATUS_BAR_HEIGHT 24 // Height of an emulation window status bar in pixels.
|
||||
|
||||
#define SPEED_SCALAR_HALF 0.5 // Speed scalar for half execution speed.
|
||||
#define SPEED_SCALAR_NORMAL 1.0 // Speed scalar for normal execution speed.
|
||||
#define SPEED_SCALAR_DOUBLE 2.0 // Speed scalar for double execution speed.
|
||||
#define SPEED_SCALAR_MIN 0.005 // Lower limit for the speed multiplier.
|
||||
|
||||
#define DS_FRAMES_PER_SECOND 59.73 // Number of DS frames per second.
|
||||
#define DS_SECONDS_PER_FRAME (1.0 / DS_FRAMES_PER_SECOND) // The length of time in seconds that, ideally, a frame should be processed within.
|
||||
|
||||
#define FRAME_SKIP_AGGRESSIVENESS 2.0
|
||||
#define FRAME_SKIP_BIAS 0.5
|
||||
#define MAX_FRAME_SKIP (DS_FRAMES_PER_SECOND * 2.0)
|
||||
|
||||
#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 CLOCKWISE_DEGREES(x) (360.0 - x) // Converts an angle in degrees from normal-direction to clockwise-direction.
|
||||
|
||||
#define VOLUME_THRESHOLD_LOW 35.0f
|
||||
#define VOLUME_THRESHOLD_HIGH 75.0f
|
||||
|
||||
#define ROM_ICON_WIDTH 32
|
||||
#define ROM_ICON_HEIGHT 32
|
||||
|
||||
#define ROMINFO_GAME_TITLE_LENGTH 12
|
||||
#define ROMINFO_GAME_CODE_LENGTH 4
|
||||
#define ROMINFO_GAME_BANNER_LENGTH 128
|
||||
|
||||
#define MIC_NULL_SAMPLE_VALUE 0
|
||||
#define MIC_SAMPLE_RATE 16000
|
||||
#define MIC_MAX_BUFFER_SAMPLES 320
|
||||
#define MIC_BUFFER_SIZE (sizeof(UInt8) * MIC_MAX_BUFFER_SAMPLES)
|
||||
|
||||
#define COCOA_DIALOG_CANCEL 0
|
||||
#define COCOA_DIALOG_DEFAULT 1
|
||||
#define COCOA_DIALOG_OK 1
|
||||
#define COCOA_DIALOG_OPTION 2
|
||||
|
||||
enum
|
||||
{
|
||||
ROMAUTOLOADOPTION_LOAD_LAST = 0,
|
||||
ROMAUTOLOADOPTION_LOAD_SELECTED = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
REASONFORCLOSE_NORMAL = 0,
|
||||
REASONFORCLOSE_OPEN,
|
||||
REASONFORCLOSE_TERMINATE
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EMULATION_ENSATA_BIT = 0,
|
||||
EMULATION_ADVANCED_BUS_LEVEL_TIMING_BIT = 1,
|
||||
EMULATION_USE_EXTERNAL_BIOS_BIT = 2,
|
||||
EMULATION_BIOS_SWI_BIT = 3,
|
||||
EMULATION_PATCH_DELAY_LOOP_BIT = 4,
|
||||
EMULATION_USE_EXTERNAL_FIRMWARE_BIT = 5,
|
||||
EMULATION_BOOT_FROM_FIRMWARE_BIT = 6,
|
||||
EMULATION_SLEEP_BIT = 7,
|
||||
EMULATION_CARD_EJECT_BIT = 8,
|
||||
EMULATION_DEBUG_CONSOLE_BIT = 9
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EMULATION_ENSATA_MASK = 1 << EMULATION_ENSATA_BIT,
|
||||
EMULATION_ADVANCED_BUS_LEVEL_TIMING_MASK = 1 << EMULATION_ADVANCED_BUS_LEVEL_TIMING_BIT,
|
||||
EMULATION_USE_EXTERNAL_BIOS_MASK = 1 << EMULATION_USE_EXTERNAL_BIOS_BIT,
|
||||
EMULATION_BIOS_SWI_MASK = 1 << EMULATION_BIOS_SWI_BIT,
|
||||
EMULATION_PATCH_DELAY_LOOP_MASK = 1 << EMULATION_PATCH_DELAY_LOOP_BIT,
|
||||
EMULATION_USE_EXTERNAL_FIRMWARE_MASK = 1 << EMULATION_USE_EXTERNAL_FIRMWARE_BIT,
|
||||
EMULATION_BOOT_FROM_FIRMWARE_MASK = 1 << EMULATION_BOOT_FROM_FIRMWARE_BIT,
|
||||
EMULATION_SLEEP_MASK = 1 << EMULATION_SLEEP_BIT,
|
||||
EMULATION_CARD_EJECT_MASK = 1 << EMULATION_CARD_EJECT_BIT,
|
||||
EMULATION_DEBUG_CONSOLE_MASK = 1 << EMULATION_DEBUG_CONSOLE_BIT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GPUSTATE_MAIN_GPU_BIT = 0,
|
||||
GPUSTATE_MAIN_BG0_BIT = 1,
|
||||
GPUSTATE_MAIN_BG1_BIT = 2,
|
||||
GPUSTATE_MAIN_BG2_BIT = 3,
|
||||
GPUSTATE_MAIN_BG3_BIT = 4,
|
||||
GPUSTATE_MAIN_OBJ_BIT = 5,
|
||||
GPUSTATE_SUB_GPU_BIT = 6,
|
||||
GPUSTATE_SUB_BG0_BIT = 7,
|
||||
GPUSTATE_SUB_BG1_BIT = 8,
|
||||
GPUSTATE_SUB_BG2_BIT = 9,
|
||||
GPUSTATE_SUB_BG3_BIT = 10,
|
||||
GPUSTATE_SUB_OBJ_BIT = 11
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GPUSTATE_MAIN_GPU_MASK = 1 << GPUSTATE_MAIN_GPU_BIT,
|
||||
GPUSTATE_MAIN_BG0_MASK = 1 << GPUSTATE_MAIN_BG0_BIT,
|
||||
GPUSTATE_MAIN_BG1_MASK = 1 << GPUSTATE_MAIN_BG1_BIT,
|
||||
GPUSTATE_MAIN_BG2_MASK = 1 << GPUSTATE_MAIN_BG2_BIT,
|
||||
GPUSTATE_MAIN_BG3_MASK = 1 << GPUSTATE_MAIN_BG3_BIT,
|
||||
GPUSTATE_MAIN_OBJ_MASK = 1 << GPUSTATE_MAIN_OBJ_BIT,
|
||||
GPUSTATE_SUB_GPU_MASK = 1 << GPUSTATE_SUB_GPU_BIT,
|
||||
GPUSTATE_SUB_BG0_MASK = 1 << GPUSTATE_SUB_BG0_BIT,
|
||||
GPUSTATE_SUB_BG1_MASK = 1 << GPUSTATE_SUB_BG1_BIT,
|
||||
GPUSTATE_SUB_BG2_MASK = 1 << GPUSTATE_SUB_BG2_BIT,
|
||||
GPUSTATE_SUB_BG3_MASK = 1 << GPUSTATE_SUB_BG3_BIT,
|
||||
GPUSTATE_SUB_OBJ_MASK = 1 << GPUSTATE_SUB_OBJ_BIT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SPU_SYNC_MODE_DUAL_SYNC_ASYNC = 0,
|
||||
SPU_SYNC_MODE_SYNCHRONOUS = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SPU_SYNC_METHOD_N = 0,
|
||||
SPU_SYNC_METHOD_Z = 1,
|
||||
SPU_SYNC_METHOD_P = 2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHEAT_TYPE_INTERNAL = 0,
|
||||
CHEAT_TYPE_ACTION_REPLAY = 1,
|
||||
CHEAT_TYPE_CODE_BREAKER = 2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHEATSEARCH_SEARCHSTYLE_EXACT_VALUE = 0,
|
||||
CHEATSEARCH_SEARCHSTYLE_COMPARATIVE = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHEATSEARCH_COMPARETYPE_GREATER_THAN = 0,
|
||||
CHEATSEARCH_COMPARETYPE_LESSER_THAN = 1,
|
||||
CHEATSEARCH_COMPARETYPE_EQUALS_TO = 2,
|
||||
CHEATSEARCH_COMPARETYPE_NOT_EQUALS_TO = 3
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHEATSEARCH_UNSIGNED = 0,
|
||||
CHEATSEARCH_SIGNED = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHEATEXPORT_ERROR_FILE_NOT_FOUND = 1,
|
||||
CHEATEXPORT_ERROR_WRONG_FILE_FORMAT = 2,
|
||||
CHEATEXPORT_ERROR_SERIAL_NOT_FOUND = 3,
|
||||
CHEATEXPORT_ERROR_EXPORT_FAILED = 4
|
||||
};
|
||||
|
||||
/*
|
||||
PORT MESSAGES
|
||||
*/
|
||||
enum
|
||||
{
|
||||
MESSAGE_CHECK_FOR_RESPONSE = 100, // Message to check if a port is responding. Usually sent to make sure that a thread is alive.
|
||||
MESSAGE_CHECK_RESPONSE_ECHO, // Response message when another port sends MESSAGE_CHECK_FOR_RESPONSE. Sent to confirm that a thread is indeed alive.
|
||||
MESSAGE_EXIT_THREAD, // Sent whenever there is a need to stop a thread.
|
||||
|
||||
MESSAGE_EMU_FRAME_PROCESSED = 1000, // Sent whenever an emulation frame is fully processed. This is mostly used to signal outputs to update themselves based on the new emulation frame.
|
||||
MESSAGE_OUTPUT_FINISHED_FRAME, // Sent from an output device whenever it finishes processing the frame data.
|
||||
MESSAGE_SET_EMULATION_FLAGS,
|
||||
|
||||
// Video Messages
|
||||
MESSAGE_RESIZE_VIEW,
|
||||
MESSAGE_REDRAW_VIEW,
|
||||
MESSAGE_SET_GPU_STATE_FLAGS,
|
||||
MESSAGE_CHANGE_DISPLAY_TYPE,
|
||||
MESSAGE_CHANGE_BILINEAR_OUTPUT,
|
||||
MESSAGE_CHANGE_VIDEO_FILTER,
|
||||
MESSAGE_SET_RENDER3D_METHOD,
|
||||
MESSAGE_SET_RENDER3D_HIGH_PRECISION_COLOR_INTERPOLATION,
|
||||
MESSAGE_SET_RENDER3D_EDGE_MARKING,
|
||||
MESSAGE_SET_RENDER3D_FOG,
|
||||
MESSAGE_SET_RENDER3D_TEXTURES,
|
||||
MESSAGE_SET_RENDER3D_DEPTH_COMPARISON_THRESHOLD,
|
||||
MESSAGE_SET_RENDER3D_THREADS,
|
||||
MESSAGE_SET_RENDER3D_LINE_HACK,
|
||||
MESSAGE_SET_VIEW_TO_BLACK,
|
||||
MESSAGE_SET_VIEW_TO_WHITE,
|
||||
|
||||
MESSAGE_SET_AUDIO_PROCESS_METHOD,
|
||||
MESSAGE_SET_SPU_ADVANCED_LOGIC,
|
||||
MESSAGE_SET_SPU_SYNC_MODE,
|
||||
MESSAGE_SET_SPU_SYNC_METHOD,
|
||||
MESSAGE_SET_SPU_INTERPOLATION_MODE,
|
||||
MESSAGE_SET_VOLUME,
|
||||
|
||||
MESSAGE_COPY_TO_PASTEBOARD
|
||||
};
|
||||
|
||||
/*
|
||||
DS DISPLAY TYPES
|
||||
*/
|
||||
enum
|
||||
{
|
||||
DS_DISPLAY_TYPE_MAIN = 0,
|
||||
DS_DISPLAY_TYPE_TOUCH,
|
||||
DS_DISPLAY_TYPE_COMBO
|
||||
};
|
||||
|
||||
/*
|
||||
DS GPU TYPES
|
||||
*/
|
||||
enum
|
||||
{
|
||||
DS_GPU_TYPE_MAIN = 0,
|
||||
DS_GPU_TYPE_SUB,
|
||||
DS_GPU_TYPE_COMBO
|
||||
};
|
||||
|
||||
/*
|
||||
COCOA DS CORE STATES
|
||||
*/
|
||||
enum
|
||||
{
|
||||
CORESTATE_EXECUTE = 0,
|
||||
CORESTATE_PAUSE
|
||||
};
|
||||
|
||||
/*
|
||||
DESMUME 3D RENDERER TYPES
|
||||
*/
|
||||
enum
|
||||
{
|
||||
CORE3DLIST_NULL = 0,
|
||||
CORE3DLIST_SWRASTERIZE,
|
||||
CORE3DLIST_OPENGL
|
||||
};
|
||||
|
||||
/*
|
||||
MICROPHONE MODE
|
||||
*/
|
||||
enum
|
||||
{
|
||||
MICMODE_NONE = 0,
|
||||
MICMODE_INTERNAL_NOISE,
|
||||
MICMODE_SOUND_FILE,
|
||||
MICMODE_WHITE_NOISE,
|
||||
MICMODE_PHYSICAL
|
||||
};
|
||||
|
||||
/*
|
||||
CONTROL TAGS FOR PREFERENCE WINDOW INPUT CONFIG BUTTONS
|
||||
*/
|
||||
enum
|
||||
{
|
||||
PREF_INPUT_BUTTON_UP = 1000,
|
||||
PREF_INPUT_BUTTON_DOWN,
|
||||
PREF_INPUT_BUTTON_LEFT,
|
||||
PREF_INPUT_BUTTON_RIGHT,
|
||||
PREF_INPUT_BUTTON_A,
|
||||
PREF_INPUT_BUTTON_B,
|
||||
PREF_INPUT_BUTTON_X,
|
||||
PREF_INPUT_BUTTON_Y,
|
||||
PREF_INPUT_BUTTON_L,
|
||||
PREF_INPUT_BUTTON_R,
|
||||
PREF_INPUT_BUTTON_START,
|
||||
PREF_INPUT_BUTTON_SELECT,
|
||||
|
||||
PREF_INPUT_BUTTON_SIM_MIC = 2000,
|
||||
|
||||
PREF_INPUT_BUTTON_LID = 3000,
|
||||
PREF_INPUT_BUTTON_DEBUG,
|
||||
PREF_INPUT_BUTTON_SPEED_HALF,
|
||||
PREF_INPUT_BUTTON_SPEED_DOUBLE,
|
||||
PREF_INPUT_BUTTON_TOGGLE_HUD,
|
||||
PREF_INPUT_BUTTON_EXECUTE,
|
||||
PREF_INPUT_BUTTON_PAUSE,
|
||||
PREF_INPUT_BUTTON_RESET,
|
||||
|
||||
PREF_INPUT_BUTTON_TOUCH = 4000
|
||||
};
|
|
@ -27,6 +27,8 @@ Mac related questions can go to osx@desmume.org
|
|||
#import "main_window.h"
|
||||
#import "preferences.h"
|
||||
|
||||
#include "sndOSX.h"
|
||||
|
||||
#ifdef GDB_STUB
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
@ -576,6 +578,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification*)notification
|
||||
{
|
||||
SNDOSXStartup();
|
||||
|
||||
//Set default values for all preferences
|
||||
//(this wont override saved preferences as
|
||||
//they work in different preference domains)
|
||||
|
@ -623,7 +627,10 @@ int main(int argc, char *argv[])
|
|||
|
||||
- (void)applicationWillTerminate:(NSNotification*)notification
|
||||
{
|
||||
[main_window pause];
|
||||
[main_window release];
|
||||
|
||||
SNDOSXShutdown();
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,717 @@
|
|||
/*
|
||||
Copyright (C) 2007 Jeff Bland
|
||||
Copyright (C) 2007-2011 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 "sndOSX.h"
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <pthread.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);
|
||||
const size_t copySize = inNumberFrames * SPU_STEREO_SAMPLE_SIZE;
|
||||
size_t hiBufferAvailable = 0;
|
||||
size_t loBufferAvailable = 0;
|
||||
|
||||
pthread_mutex_lock(mutexAudioUnit);
|
||||
|
||||
UInt8 *__restrict__ outputData = (UInt8 *)ioData->mBuffers[0].mData;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutexAudioUnit);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SoundInterface_struct SNDOSX = {
|
||||
SNDCORE_OSX,
|
||||
"Core Audio Sound Interface",
|
||||
SNDOSXInit,
|
||||
SNDOSXDeInit,
|
||||
SNDOSXUpdateAudio,
|
||||
SNDOSXGetAudioSpace,
|
||||
SNDOSXMuteAudio,
|
||||
SNDOSXUnMuteAudio,
|
||||
SNDOSXSetVolume,
|
||||
SNDOSXClearBuffer
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//Sound recording
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SNDOSXOpenFile(void *fname)
|
||||
{
|
||||
/*
|
||||
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();
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void SNDOSXStartRecording()
|
||||
{
|
||||
pthread_mutex_lock(mutexSoundData);
|
||||
|
||||
if(sound_data == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
}
|
||||
|
||||
void SNDOSXStopRecording()
|
||||
{
|
||||
pthread_mutex_lock(mutexSoundData);
|
||||
|
||||
if(sound_data == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
}
|
||||
|
||||
void SNDOSXCloseFile()
|
||||
{
|
||||
pthread_mutex_lock(mutexSoundData);
|
||||
|
||||
if(sound_data == NULL)
|
||||
{
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
return;
|
||||
}
|
||||
|
||||
if(file_open)
|
||||
{
|
||||
file_open = false;
|
||||
|
||||
//if it's rendering sound, wait until it's not
|
||||
//so we dont close the file while writing to it
|
||||
|
||||
// Do something here, just not implemented yet...
|
||||
|
||||
//ExtAudioFileDispose(outfile);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutexSoundData);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
|
@ -1,483 +0,0 @@
|
|||
/* Copyright 2007 Jeff Bland
|
||||
|
||||
This file is part of DeSmuME
|
||||
|
||||
DeSmuME 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.
|
||||
|
||||
DeSmuME 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 DeSmuME; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
//external includes
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
//desmume includes
|
||||
#include "sndOSX.h"
|
||||
|
||||
//globals
|
||||
AudioUnit output_unit = NULL; //pointer to our audio device
|
||||
UInt16 *sound_data = NULL; //buffer where we hold data between getting it from the emulator and sending it to the device
|
||||
u32 sound_buffer_size; //size in bytes of sound_data
|
||||
volatile u32 sound_offset; //position in the buffer that we have copied to from the emu
|
||||
volatile u32 sound_position; //position in the buffer that we have played to
|
||||
|
||||
volatile bool mix_sound = false; //if false, our sound callback will do nothing
|
||||
volatile bool in_mix = false; //should probably use a real mutex instead but this seems to work
|
||||
|
||||
float current_volume_scalar = 100; //for volume/muting
|
||||
|
||||
//file output
|
||||
volatile bool file_open = false;
|
||||
ExtAudioFileRef outfile;
|
||||
|
||||
//defines
|
||||
#define SAMPLE_SIZE (sizeof(s16) * 2) //16 bit samples, stereo sound
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//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);
|
||||
|
||||
if(!mix_sound)
|
||||
return noErr;
|
||||
|
||||
in_mix = true;
|
||||
|
||||
UInt32 bytes_to_copy = inNumberFrames * 4;
|
||||
UInt8 *data_output = (UInt8*)ioData->mBuffers[0].mData;
|
||||
UInt8 *data_input = (UInt8*)sound_data;
|
||||
|
||||
if(sound_position == sound_offset)
|
||||
{//buffer empty
|
||||
|
||||
memset(data_output, 0, bytes_to_copy);
|
||||
|
||||
} else
|
||||
{ //buffer is not empty
|
||||
|
||||
int x;
|
||||
for(x = 0; x < bytes_to_copy; x++)
|
||||
{
|
||||
sound_position++;
|
||||
|
||||
if(sound_position >= sound_buffer_size)sound_position = 0;
|
||||
|
||||
if(sound_position == sound_offset)
|
||||
{
|
||||
sound_position --;
|
||||
memset(&data_output[x], 0, bytes_to_copy - x);
|
||||
break;
|
||||
}
|
||||
|
||||
data_output[x] = data_input[sound_position];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//copy to other channels
|
||||
UInt32 channel;
|
||||
for (channel = 1; channel < ioData->mNumberBuffers; channel++)
|
||||
memcpy(ioData->mBuffers[channel].mData, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize);
|
||||
|
||||
//record to file
|
||||
if(file_open)
|
||||
;//ExtAudioFileWrite(outfile, inNumberFrames, ioData);
|
||||
|
||||
in_mix = false;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SNDOSXInit(int buffer_size)
|
||||
{
|
||||
OSStatus err = noErr;
|
||||
|
||||
//Setup the sound buffer -------------------------------------------
|
||||
|
||||
//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 emptys
|
||||
buffer_size += 1;
|
||||
|
||||
if((sound_data = (UInt16*)malloc(buffer_size)) == NULL)
|
||||
return -1;
|
||||
|
||||
sound_buffer_size = buffer_size;
|
||||
|
||||
SNDOSXReset();
|
||||
|
||||
//grab the default 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 -1;
|
||||
|
||||
err = OpenAComponent(comp, &output_unit);
|
||||
if (comp == NULL)
|
||||
return -1;
|
||||
|
||||
//then setup the callback where we will send the audio -------
|
||||
|
||||
AURenderCallbackStruct callback;
|
||||
callback.inputProc = soundMixer;
|
||||
callback.inputProcRefCon = NULL;
|
||||
|
||||
err = AudioUnitSetProperty(
|
||||
output_unit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&callback,
|
||||
sizeof(callback)
|
||||
);
|
||||
|
||||
if(err != noErr)
|
||||
return -1;
|
||||
|
||||
//now begin running the audio unit-- ----------------------
|
||||
|
||||
AudioStreamBasicDescription audio_format;
|
||||
audio_format.mSampleRate = 44100;
|
||||
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 = 16;
|
||||
|
||||
err = AudioUnitSetProperty(
|
||||
output_unit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&audio_format,
|
||||
sizeof(audio_format)
|
||||
);
|
||||
|
||||
if(err != noErr){return -1;}
|
||||
|
||||
// Initialize unit
|
||||
err = AudioUnitInitialize(output_unit);
|
||||
if(err != noErr)
|
||||
return -1;
|
||||
|
||||
//Start the rendering
|
||||
//The DefaultOutputUnit will do any format conversions to the format of the default device
|
||||
err = AudioOutputUnitStart(output_unit);
|
||||
if(err != noErr)
|
||||
return -1;
|
||||
|
||||
//
|
||||
current_volume_scalar = 100;
|
||||
|
||||
//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));
|
||||
|
||||
mix_sound = true;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SNDOSXDeInit()
|
||||
{
|
||||
if(output_unit != NULL)
|
||||
{
|
||||
//wait for mix to end
|
||||
mix_sound = false;
|
||||
while(in_mix);
|
||||
|
||||
//closes the audio unit (errors are ignored here)
|
||||
AudioOutputUnitStop(output_unit);
|
||||
AudioUnitUninitialize(output_unit);
|
||||
|
||||
output_unit = NULL;
|
||||
}
|
||||
|
||||
SNDOSXCloseFile(); //end recording to file if needed
|
||||
|
||||
if(sound_data != NULL)
|
||||
{
|
||||
free(sound_data);
|
||||
sound_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SNDOSXReset()
|
||||
{
|
||||
if(sound_data == NULL)return 0;
|
||||
|
||||
memset(sound_data, 0, sound_buffer_size);
|
||||
|
||||
sound_offset = 0;
|
||||
sound_position = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SNDOSXUpdateAudio(s16 *buffer, u32 num_samples)
|
||||
{
|
||||
//printf("NEW SOUND DATA %u ", num_samples * SAMPLE_SIZE);
|
||||
|
||||
if(sound_data == NULL)return;
|
||||
|
||||
//get the avilable bufferspace ------------------------------------------------
|
||||
|
||||
//in these calculatations:
|
||||
//1 is subtracted from sound_buffer_size since if the size is 2, we can only go to index 1
|
||||
//1 is subtracted from sound_position since sound_offset should never catch up to it
|
||||
//since them being equal means that the buffer is empty, rather than full
|
||||
|
||||
u32 bytes_to_copy = num_samples * SAMPLE_SIZE;
|
||||
|
||||
int sound_pos = sound_position; //incase the sound render thread changes it
|
||||
|
||||
u32 copy1size, copy2size;
|
||||
|
||||
if(sound_offset >= sound_pos)
|
||||
{
|
||||
if(sound_pos > 0)
|
||||
{
|
||||
copy1size = sound_buffer_size - sound_offset;
|
||||
copy2size = (sound_pos-1);
|
||||
} else
|
||||
{
|
||||
copy1size = sound_buffer_size - sound_offset - 1;
|
||||
copy2size = 0;
|
||||
}
|
||||
} else if(sound_offset < sound_pos)
|
||||
{
|
||||
copy1size = sound_pos - sound_offset - 1;
|
||||
copy2size = 0;
|
||||
}
|
||||
|
||||
//printf("copy1:%u copy2:%u both:%u\n",copy1size, copy2size, copy2size+copy1size);
|
||||
//truncate the copy sizes to however much we've been been given to fill --------
|
||||
|
||||
if(copy1size + copy2size < bytes_to_copy)
|
||||
//this shouldn't happen as the emulator core generally asks how much
|
||||
//space is available before sending stuff, but just incase
|
||||
printf("NDOSXUpdateAudio() error: not enough space in buffer");
|
||||
else
|
||||
{
|
||||
u32 diff = copy1size + copy2size - bytes_to_copy;
|
||||
|
||||
if(diff <= copy2size)
|
||||
{
|
||||
copy2size -= diff;
|
||||
} else
|
||||
{
|
||||
diff -= copy2size;
|
||||
copy2size = 0;
|
||||
copy1size -= diff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//copy the data -------------------------------------------------------------
|
||||
|
||||
memcpy((((u8 *)sound_data)+sound_offset), buffer, copy1size);
|
||||
|
||||
if(copy2size)
|
||||
memcpy(sound_data, ((u8 *)buffer)+copy1size, copy2size);
|
||||
|
||||
//change our sound_offset
|
||||
sound_offset += copy1size + copy2size;
|
||||
while(sound_offset >= sound_buffer_size)sound_offset -= sound_buffer_size;
|
||||
|
||||
//printf("cop1%u cop2%u off%u size%u \n", copy1size, copy2size, sound_offset, sound_buffer_size);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
u32 SNDOSXGetAudioSpace()
|
||||
{
|
||||
if(sound_data == NULL)return 0;
|
||||
|
||||
int sound_pos = sound_position; //incase the sound render thread changes it
|
||||
|
||||
u32 free_space;
|
||||
|
||||
if(sound_offset > sound_pos)
|
||||
free_space = sound_buffer_size + sound_pos - 1 - sound_offset;
|
||||
else if(sound_offset < sound_pos)
|
||||
free_space = sound_pos - sound_offset - 1;
|
||||
else
|
||||
free_space = sound_buffer_size-1; //sound_offset == sound_data, meaning the buffer is empty
|
||||
|
||||
return (free_space / SAMPLE_SIZE);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SNDOSXMuteAudio()
|
||||
{
|
||||
if(sound_data == NULL)return;
|
||||
|
||||
OSStatus err = AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, 0, 0);
|
||||
|
||||
if(err != noErr)
|
||||
printf("SNDOSXMuteAudio error\n");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SNDOSXUnMuteAudio()
|
||||
{
|
||||
if(sound_data == NULL)return;
|
||||
|
||||
OSStatus err = AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, current_volume_scalar, 0);
|
||||
|
||||
if(err != noErr)
|
||||
printf("SNDOSXUnMuteAudio %f error\n",current_volume_scalar);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SNDOSXSetVolume(int volume)
|
||||
{
|
||||
if(sound_data == NULL)return;
|
||||
|
||||
if(volume > 100)volume = 100;
|
||||
if(volume < 0)volume = 0;
|
||||
|
||||
current_volume_scalar = volume;
|
||||
current_volume_scalar /= 100.0;
|
||||
|
||||
OSStatus err = AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, current_volume_scalar, 0);
|
||||
|
||||
if(err != noErr)
|
||||
printf("SNDOSXSetVolume %f error\n",current_volume_scalar);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SoundInterface_struct SNDOSX = {
|
||||
SNDCORE_OSX,
|
||||
"Core Audio Sound Interface",
|
||||
SNDOSXInit,
|
||||
SNDOSXDeInit,
|
||||
SNDOSXUpdateAudio,
|
||||
SNDOSXGetAudioSpace,
|
||||
SNDOSXMuteAudio,
|
||||
SNDOSXUnMuteAudio,
|
||||
SNDOSXSetVolume
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//Sound recording
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SNDOSXOpenFile(void *fname)
|
||||
{
|
||||
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();
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioStreamBasicDescription audio_format;
|
||||
audio_format.mSampleRate = 44100;
|
||||
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 = 16;
|
||||
/*
|
||||
if(ExtAudioFileCreateNew(&ref, (CFStringRef)[[filename pathComponents] lastObject], kAudioFileWAVEType, &audio_format, NULL, &outfile) != noErr)
|
||||
return false;
|
||||
|
||||
file_open = true;
|
||||
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
void SNDOSXStartRecording()
|
||||
{
|
||||
if(sound_data == NULL)return;
|
||||
}
|
||||
|
||||
void SNDOSXStopRecording()
|
||||
{
|
||||
if(sound_data == NULL)return;
|
||||
}
|
||||
|
||||
void SNDOSXCloseFile()
|
||||
{
|
||||
if(sound_data == NULL)return;
|
||||
|
||||
if(file_open)
|
||||
{
|
||||
file_open = false;
|
||||
|
||||
//if it's rendering sound, wait until it's not
|
||||
//so we dont close the file while writing to it
|
||||
while(in_mix);
|
||||
|
||||
//ExtAudioFileDispose(outfile);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
Loading…
Reference in New Issue