[Project64] Add Audio plugin for android
This commit is contained in:
parent
b927aedc7f
commit
06383ff638
|
@ -0,0 +1,32 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64 - A Nintendo 64 emulator. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2016 Project64. All rights reserved. *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#include "AudioSettings.h"
|
||||
#include "trace.h"
|
||||
#include "main.h"
|
||||
|
||||
void SetupAudioSettings (void)
|
||||
{
|
||||
SetModuleName("AndroidAudio");
|
||||
RegisterSetting(Output_SwapChannels, Data_DWORD_General, "SwapChannels", "", 0, NULL);
|
||||
RegisterSetting(Output_DefaultFrequency, Data_DWORD_General, "DefaultFrequency", "", DEFAULT_FREQUENCY, NULL);
|
||||
RegisterSetting(Buffer_PrimarySize, Data_DWORD_General, "BufferPrimarySize", "", PRIMARY_BUFFER_SIZE, NULL);
|
||||
RegisterSetting(Buffer_SecondarySize, Data_DWORD_General, "BufferSecondarySize", "", SECONDARY_BUFFER_SIZE, NULL);
|
||||
RegisterSetting(Buffer_SecondaryNbr, Data_DWORD_General, "BufferSecondaryNbr", "", SECONDARY_BUFFER_NBR, NULL);
|
||||
RegisterSetting(Logging_LogAudioInitShutdown, Data_DWORD_General, "AudioInitShutdown", "Logging", g_ModuleLogLevel[TraceAudioInitShutdown], NULL);
|
||||
RegisterSetting(Logging_LogAudioInterface, Data_DWORD_General, "AudioInterface", "Logging", g_ModuleLogLevel[TraceAudioInterface], NULL);
|
||||
|
||||
g_SwapChannels = GetSetting(Output_SwapChannels);
|
||||
g_GameFreq = GetSetting(Output_DefaultFrequency);
|
||||
|
||||
g_ModuleLogLevel[TraceAudioInitShutdown] = GetSetting(Logging_LogAudioInitShutdown);
|
||||
g_ModuleLogLevel[TraceAudioInterface] = GetSetting(Logging_LogAudioInterface);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64 - A Nintendo 64 emulator. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2016 Project64. All rights reserved. *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
#include <Settings/Settings.h>
|
||||
|
||||
enum AudioSettingID
|
||||
{
|
||||
Output_SwapChannels,
|
||||
Output_DefaultFrequency,
|
||||
Buffer_PrimarySize,
|
||||
Buffer_SecondarySize,
|
||||
Buffer_SecondaryNbr,
|
||||
Logging_LogAudioInitShutdown,
|
||||
Logging_LogAudioInterface,
|
||||
};
|
||||
|
||||
void SetupAudioSettings ( void );
|
|
@ -0,0 +1,194 @@
|
|||
/**********************************************************************************
|
||||
Common Audio plugin spec, version #1.1
|
||||
**********************************************************************************
|
||||
Notes:
|
||||
------
|
||||
|
||||
Setting the approprate bits in the MI_INTR_REG and calling CheckInterrupts which
|
||||
are both passed to the DLL in InitiateAudio will generate an Interrupt from with in
|
||||
the plugin.
|
||||
|
||||
**********************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <Common/stdtypes.h>
|
||||
|
||||
enum { PLUGIN_TYPE_AUDIO = 3 };
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define EXPORT extern "C" __declspec(dllexport)
|
||||
#define CALL __cdecl
|
||||
#else
|
||||
#define EXPORT extern "C" __attribute__((visibility("default")))
|
||||
#define CALL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
SYSTEM_NTSC = 0,
|
||||
SYSTEM_PAL = 1,
|
||||
SYSTEM_MPAL = 2,
|
||||
};
|
||||
|
||||
/***** Structures *****/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t Version; /* Should be set to 0x0101 */
|
||||
uint16_t Type; /* Set to PLUGIN_TYPE_AUDIO */
|
||||
char Name[100]; /* Name of the DLL */
|
||||
int32_t NormalMemory;
|
||||
int32_t MemoryBswaped;
|
||||
} PLUGIN_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void * hwnd;
|
||||
void * hinst;
|
||||
|
||||
int32_t MemoryBswaped; // If this is set to TRUE, then the memory has been pre
|
||||
|
||||
// bswap on a dword (32 bits) boundry
|
||||
// eg. the first 8 bytes are stored like this:
|
||||
// 4 3 2 1 8 7 6 5
|
||||
uint8_t * HEADER; // This is the rom header (first 40h bytes of the rom
|
||||
// This will be in the same memory format as the rest of the memory.
|
||||
uint8_t * RDRAM;
|
||||
uint8_t * DMEM;
|
||||
uint8_t * IMEM;
|
||||
|
||||
uint32_t * MI__INTR_REG;
|
||||
|
||||
uint32_t * AI__DRAM_ADDR_REG;
|
||||
uint32_t * AI__LEN_REG;
|
||||
uint32_t * AI__CONTROL_REG;
|
||||
uint32_t * AI__STATUS_REG;
|
||||
uint32_t * AI__DACRATE_REG;
|
||||
uint32_t * AI__BITRATE_REG;
|
||||
|
||||
void(CALL *CheckInterrupts)(void);
|
||||
} AUDIO_INFO;
|
||||
|
||||
/******************************************************************
|
||||
Function: AiDacrateChanged
|
||||
Purpose: This function is called to notify the dll that the
|
||||
AiDacrate registers value has been changed.
|
||||
input: The System type:
|
||||
SYSTEM_NTSC 0
|
||||
SYSTEM_PAL 1
|
||||
SYSTEM_MPAL 2
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL AiDacrateChanged(int32_t SystemType);
|
||||
|
||||
/******************************************************************
|
||||
Function: AiLenChanged
|
||||
Purpose: This function is called to notify the dll that the
|
||||
AiLen registers value has been changed.
|
||||
input: none
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL AiLenChanged(void);
|
||||
|
||||
/******************************************************************
|
||||
Function: AiReadLength
|
||||
Purpose: This function is called to allow the dll to return the
|
||||
value that AI_LEN_REG should equal
|
||||
input: none
|
||||
output: The amount of bytes still left to play.
|
||||
*******************************************************************/
|
||||
EXPORT uint32_t CALL AiReadLength(void);
|
||||
|
||||
/******************************************************************
|
||||
Function: AiUpdate
|
||||
Purpose: This function is called to allow the dll to update
|
||||
things on a regular basis (check how long to sound to
|
||||
go, copy more stuff to the buffer, anyhting you like).
|
||||
The function is designed to go in to the message loop
|
||||
of the main window ... but can be placed anywhere you
|
||||
like.
|
||||
input: if Wait is set to true, then this function should wait
|
||||
till there is a messgae in the its message queue.
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL AiUpdate(int32_t Wait);
|
||||
|
||||
/******************************************************************
|
||||
Function: CloseDLL
|
||||
Purpose: This function is called when the emulator is closing
|
||||
down allowing the dll to de-initialise.
|
||||
input: none
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL CloseDLL(void);
|
||||
|
||||
/******************************************************************
|
||||
Function: DllAbout
|
||||
Purpose: This function is optional function that is provided
|
||||
to give further information about the DLL.
|
||||
input: a handle to the window that calls this function
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL DllAbout(void * hParent);
|
||||
|
||||
/******************************************************************
|
||||
Function: DllConfig
|
||||
Purpose: This function is optional function that is provided
|
||||
to allow the user to configure the dll
|
||||
input: a handle to the window that calls this function
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL DllConfig(void * hParent);
|
||||
|
||||
/******************************************************************
|
||||
Function: DllTest
|
||||
Purpose: This function is optional function that is provided
|
||||
to allow the user to test the dll
|
||||
input: a handle to the window that calls this function
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL DllTest(void * hParent);
|
||||
|
||||
/******************************************************************
|
||||
Function: GetDllInfo
|
||||
Purpose: This function allows the emulator to gather information
|
||||
about the dll by filling in the PluginInfo structure.
|
||||
input: a pointer to a PLUGIN_INFO stucture that needs to be
|
||||
filled by the function. (see def above)
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL GetDllInfo(PLUGIN_INFO * PluginInfo);
|
||||
|
||||
/******************************************************************
|
||||
Function: InitiateSound
|
||||
Purpose: This function is called when the DLL is started to give
|
||||
information from the emulator that the n64 audio
|
||||
interface needs
|
||||
Input: Audio_Info is passed to this function which is defined
|
||||
above.
|
||||
Output: TRUE on success
|
||||
FALSE on failure to initialise
|
||||
|
||||
** note on interrupts **:
|
||||
To generate an interrupt set the appropriate bit in MI_INTR_REG
|
||||
and then call the function CheckInterrupts to tell the emulator
|
||||
that there is a waiting interrupt.
|
||||
*******************************************************************/
|
||||
EXPORT int32_t CALL InitiateAudio(AUDIO_INFO Audio_Info);
|
||||
|
||||
/******************************************************************
|
||||
Function: ProcessAList
|
||||
Purpose: This function is called when there is a Alist to be
|
||||
processed. The Dll will have to work out all the info
|
||||
about the AList itself.
|
||||
input: none
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL ProcessAList(void);
|
||||
|
||||
/******************************************************************
|
||||
Function: RomClosed
|
||||
Purpose: This function is called when a rom is closed.
|
||||
input: none
|
||||
output: none
|
||||
*******************************************************************/
|
||||
EXPORT void CALL RomClosed(void);
|
|
@ -0,0 +1,799 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64 - A Nintendo 64 emulator. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2016 Project64. All rights reserved. *
|
||||
* Copyright (C) 2015 Gilles Siberlin *
|
||||
* Copyright (C) 2007-2009 Richard Goedeken *
|
||||
* Copyright (C) 2007-2008 Ebenblues *
|
||||
* Copyright (C) 2003 JttL *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#ifdef ANDROID
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
#endif
|
||||
#include "audio_1.1.h"
|
||||
#include "Version.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "AudioSettings.h"
|
||||
#include "trace.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
typedef struct threadLock_
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
volatile unsigned char value;
|
||||
volatile unsigned char limit;
|
||||
} threadLock;
|
||||
#endif
|
||||
|
||||
/* Read header for type definition */
|
||||
AUDIO_INFO g_AudioInfo;
|
||||
|
||||
/* Pointer to the primary audio buffer */
|
||||
uint8_t * g_primaryBuffer = NULL;
|
||||
|
||||
/* Size of the primary buffer */
|
||||
uint32_t g_primaryBufferBytes = 0;
|
||||
|
||||
/* Size of the primary audio buffer in equivalent output samples */
|
||||
unsigned int g_PrimaryBufferSize = PRIMARY_BUFFER_SIZE;
|
||||
|
||||
/* Pointer to secondary buffers */
|
||||
uint8_t ** g_secondaryBuffers = NULL;
|
||||
|
||||
/* Size of a single secondary buffer */
|
||||
uint32_t g_secondaryBufferBytes = 0;
|
||||
|
||||
/* Size of a single secondary audio buffer in output samples */
|
||||
uint32_t g_SecondaryBufferSize = SECONDARY_BUFFER_SIZE;
|
||||
|
||||
/* Position in the primary buffer where next audio chunk should be placed */
|
||||
uint32_t g_primaryBufferPos = 0;
|
||||
|
||||
/* Index of the next secondary buffer available */
|
||||
uint32_t g_secondaryBufferIndex = 0;
|
||||
|
||||
/* Number of secondary buffers */
|
||||
uint32_t g_SecondaryBufferNbr = SECONDARY_BUFFER_NBR;
|
||||
|
||||
/* Audio frequency, this is usually obtained from the game, but for compatibility we set default value */
|
||||
uint32_t g_GameFreq = DEFAULT_FREQUENCY;
|
||||
|
||||
/* SpeedFactor is used to increase/decrease game playback speed */
|
||||
uint32_t g_speed_factor = 100;
|
||||
|
||||
/* If this is true then left and right channels are swapped */
|
||||
bool g_SwapChannels = false;
|
||||
|
||||
/* Output Audio frequency */
|
||||
int g_OutputFreq = 44100;
|
||||
|
||||
/* Indicate that the audio plugin failed to initialize, so the emulator can keep running without sound */
|
||||
bool g_critical_failure = false;
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Thread Lock */
|
||||
threadLock g_lock;
|
||||
|
||||
/* Engine interfaces */
|
||||
SLObjectItf g_engineObject = NULL;
|
||||
SLEngineItf g_engineEngine = NULL;
|
||||
|
||||
/* Output mix interfaces */
|
||||
SLObjectItf g_outputMixObject = NULL;
|
||||
|
||||
/* Player interfaces */
|
||||
SLObjectItf g_playerObject = NULL;
|
||||
SLPlayItf g_playerPlay = NULL;
|
||||
|
||||
/* Buffer queue interfaces */
|
||||
SLAndroidSimpleBufferQueueItf g_bufferQueue = NULL;
|
||||
#endif
|
||||
|
||||
bool g_PluginInit = false;
|
||||
|
||||
void PluginInit ( void )
|
||||
{
|
||||
if (g_PluginInit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetupTrace();
|
||||
SetupAudioSettings();
|
||||
g_PluginInit = true;
|
||||
}
|
||||
|
||||
/* This callback handler is called every time a buffer finishes playing */
|
||||
#ifdef ANDROID
|
||||
void queueCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
|
||||
{
|
||||
threadLock *plock = (threadLock *) context;
|
||||
|
||||
pthread_mutex_lock(&(plock->mutex));
|
||||
|
||||
if(plock->value < plock->limit)
|
||||
plock->value++;
|
||||
|
||||
pthread_cond_signal(&(plock->cond));
|
||||
|
||||
pthread_mutex_unlock(&(plock->mutex));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void CloseAudio(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start");
|
||||
g_primaryBufferPos = 0;
|
||||
g_secondaryBufferIndex = 0;
|
||||
|
||||
/* Delete Primary buffer */
|
||||
if (g_primaryBuffer != NULL)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Delete g_primaryBuffer (%p)",g_primaryBuffer);
|
||||
g_primaryBufferBytes = 0;
|
||||
delete [] g_primaryBuffer;
|
||||
g_primaryBuffer = NULL;
|
||||
}
|
||||
|
||||
/* Delete Secondary buffers */
|
||||
if (g_secondaryBuffers != NULL)
|
||||
{
|
||||
for(uint32_t i = 0; i < g_SecondaryBufferNbr; i++)
|
||||
{
|
||||
if (g_secondaryBuffers[i] != NULL)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Delete g_secondaryBuffers[%d] (%p)",i,g_secondaryBuffers[i]);
|
||||
delete [] g_secondaryBuffers[i];
|
||||
g_secondaryBuffers[i] = NULL;
|
||||
}
|
||||
}
|
||||
g_secondaryBufferBytes = 0;
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Delete g_secondaryBuffers (%p)",g_secondaryBuffers);
|
||||
delete [] g_secondaryBuffers;
|
||||
g_secondaryBuffers = NULL;
|
||||
}
|
||||
#ifdef ANDROID
|
||||
/* Destroy buffer queue audio player object, and invalidate all associated interfaces */
|
||||
if (g_playerObject != NULL)
|
||||
{
|
||||
SLuint32 state = SL_PLAYSTATE_PLAYING;
|
||||
(*g_playerPlay)->SetPlayState(g_playerPlay, SL_PLAYSTATE_STOPPED);
|
||||
|
||||
while(state != SL_PLAYSTATE_STOPPED)
|
||||
{
|
||||
(*g_playerPlay)->GetPlayState(g_playerPlay, &state);
|
||||
}
|
||||
|
||||
(*g_playerObject)->Destroy(g_playerObject);
|
||||
g_playerObject = NULL;
|
||||
g_playerPlay = NULL;
|
||||
g_bufferQueue = NULL;
|
||||
}
|
||||
|
||||
/* Destroy output mix object, and invalidate all associated interfaces */
|
||||
if (g_outputMixObject != NULL)
|
||||
{
|
||||
(*g_outputMixObject)->Destroy(g_outputMixObject);
|
||||
g_outputMixObject = NULL;
|
||||
}
|
||||
|
||||
/* Destroy engine object, and invalidate all associated interfaces */
|
||||
if (g_engineObject != NULL)
|
||||
{
|
||||
(*g_engineObject)->Destroy(g_engineObject);
|
||||
g_engineObject = NULL;
|
||||
g_engineEngine = NULL;
|
||||
}
|
||||
|
||||
/* Destroy thread Locks */
|
||||
pthread_cond_signal(&(g_lock.cond));
|
||||
pthread_mutex_unlock(&(g_lock.mutex));
|
||||
pthread_cond_destroy(&(g_lock.cond));
|
||||
pthread_mutex_destroy(&(g_lock.mutex));
|
||||
#endif
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
|
||||
static bool CreatePrimaryBuffer(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start");
|
||||
unsigned int primaryBytes = (unsigned int) (g_PrimaryBufferSize * N64_SAMPLE_BYTES);
|
||||
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Allocating memory for primary audio buffer: %i bytes.", primaryBytes);
|
||||
|
||||
g_primaryBuffer = new uint8_t[primaryBytes];
|
||||
|
||||
if (g_primaryBuffer == NULL)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_primaryBuffer == NULL");
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: false)");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(g_primaryBuffer, 0, primaryBytes);
|
||||
g_primaryBufferBytes = primaryBytes;
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: True)");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CreateSecondaryBuffers(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start");
|
||||
bool status = true;
|
||||
unsigned int secondaryBytes = (unsigned int) (g_SecondaryBufferSize * SLES_SAMPLE_BYTES);
|
||||
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Allocating memory for %d secondary audio buffers: %i bytes.", g_SecondaryBufferNbr, secondaryBytes);
|
||||
|
||||
/* Allocate number of secondary buffers */
|
||||
g_secondaryBuffers = new uint8_t *[g_SecondaryBufferNbr];
|
||||
|
||||
if (g_secondaryBuffers == NULL)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_secondaryBuffers == NULL");
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: false)");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Allocate size of each secondary buffers */
|
||||
for(uint32_t i = 0; i < g_SecondaryBufferNbr; i++)
|
||||
{
|
||||
g_secondaryBuffers[i] = new uint8_t[secondaryBytes];
|
||||
|
||||
if (g_secondaryBuffers[i] == NULL)
|
||||
{
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(g_secondaryBuffers[i], 0, secondaryBytes);
|
||||
}
|
||||
|
||||
g_secondaryBufferBytes = secondaryBytes;
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: %s)",status?"True":"False");
|
||||
return status;
|
||||
}
|
||||
|
||||
static void InitializeAudio(uint32_t freq)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start (freq: %d)",freq);
|
||||
if (freq < 4000)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceInfo, "Sometimes a bad frequency is requested so ignore it (freq: %d)",freq);
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_GameFreq == freq && g_primaryBuffer != NULL)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceInfo, "we are already using this frequency, so ignore it (freq: %d)",freq);
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_critical_failure)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceInfo, "had a critical failure in setting up plugin, so ignore init");
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is important for the sync */
|
||||
g_GameFreq = freq;
|
||||
|
||||
#ifdef ANDROID
|
||||
SLuint32 sample_rate;
|
||||
if((freq/1000) <= 11)
|
||||
{
|
||||
g_OutputFreq = 11025;
|
||||
sample_rate = SL_SAMPLINGRATE_11_025;
|
||||
}
|
||||
else if((freq/1000) <= 22)
|
||||
{
|
||||
g_OutputFreq = 22050;
|
||||
sample_rate = SL_SAMPLINGRATE_22_05;
|
||||
}
|
||||
else if((freq/1000) <= 32)
|
||||
{
|
||||
g_OutputFreq = 32000;
|
||||
sample_rate = SL_SAMPLINGRATE_32;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_OutputFreq = 44100;
|
||||
sample_rate = SL_SAMPLINGRATE_44_1;
|
||||
}
|
||||
#endif
|
||||
|
||||
WriteTrace(TraceAudioInitShutdown, TraceInfo, "Requesting frequency: %iHz.", g_OutputFreq);
|
||||
|
||||
/* reload these because they gets re-assigned from data below, and InitializeAudio can be called more than once */
|
||||
g_PrimaryBufferSize = GetSetting(Buffer_PrimarySize);
|
||||
g_SecondaryBufferSize = GetSetting(Buffer_SecondarySize);
|
||||
g_SecondaryBufferNbr = GetSetting(Buffer_SecondaryNbr);
|
||||
|
||||
/* Close everything because InitializeAudio can be called more than once */
|
||||
CloseAudio();
|
||||
|
||||
/* Create primary buffer */
|
||||
if(!CreatePrimaryBuffer())
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "CreatePrimaryBuffer failed");
|
||||
CloseAudio();
|
||||
g_critical_failure = true;
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create secondary buffers */
|
||||
if(!CreateSecondaryBuffers())
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "CreateSecondaryBuffers failed");
|
||||
CloseAudio();
|
||||
g_critical_failure = true;
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Create thread Locks to ensure synchronization between callback and processing code */
|
||||
if (pthread_mutex_init(&(g_lock.mutex), (pthread_mutexattr_t*) NULL) != 0)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "pthread_mutex_init failed");
|
||||
CloseAudio();
|
||||
g_critical_failure = true;
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
if (pthread_cond_init(&(g_lock.cond), (pthread_condattr_t*) NULL) != 0)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "pthread_cond_init failed");
|
||||
CloseAudio();
|
||||
g_critical_failure = true;
|
||||
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&(g_lock.mutex));
|
||||
g_lock.value = g_lock.limit = g_SecondaryBufferNbr;
|
||||
pthread_mutex_unlock(&(g_lock.mutex));
|
||||
|
||||
/* Engine object */
|
||||
SLresult result = slCreateEngine(&g_engineObject, 0, NULL, 0, NULL, NULL);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine failed (result: %d)",result);
|
||||
}
|
||||
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_engineObject)->Realize(g_engineObject, SL_BOOLEAN_FALSE);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine->Realize failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_engineObject)->GetInterface(g_engineObject, SL_IID_ENGINE, &g_engineEngine);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine->GetInterface failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
/* Output mix object */
|
||||
result = (*g_engineEngine)->CreateOutputMix(g_engineEngine, &g_outputMixObject, 0, NULL, NULL);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine->CreateOutputMix failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_outputMixObject)->Realize(g_outputMixObject, SL_BOOLEAN_FALSE);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_outputMixObject->Realize failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, g_SecondaryBufferNbr};
|
||||
|
||||
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,2, sample_rate, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
(SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT), SL_BYTEORDER_LITTLEENDIAN};
|
||||
|
||||
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
|
||||
|
||||
/* Configure audio sink */
|
||||
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, g_outputMixObject};
|
||||
SLDataSink audioSnk = {&loc_outmix, NULL};
|
||||
|
||||
/* Create audio player */
|
||||
const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
|
||||
const SLboolean req1[] = {SL_BOOLEAN_TRUE};
|
||||
result = (*g_engineEngine)->CreateAudioPlayer(g_engineEngine, &(g_playerObject), &audioSrc, &audioSnk, 1, ids1, req1);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_engineEngine->CreateAudioPlayer failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
/* Realize the player */
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_playerObject)->Realize(g_playerObject, SL_BOOLEAN_FALSE);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerObject->Realize failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the play interface */
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_playerObject)->GetInterface(g_playerObject, SL_IID_PLAY, &(g_playerPlay));
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerObject->GetInterface(SL_IID_PLAY) failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the buffer queue interface */
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_playerObject)->GetInterface(g_playerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(g_bufferQueue));
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerObject->GetInterface(SL_IID_ANDROIDSIMPLEBUFFERQUEUE) failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
/* register callback on the buffer queue */
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_bufferQueue)->RegisterCallback(g_bufferQueue, queueCallback, &g_lock);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "bufferQueue->RegisterCallback() failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
/* set the player's state to playing */
|
||||
if(result == SL_RESULT_SUCCESS)
|
||||
{
|
||||
result = (*g_playerPlay)->SetPlayState(g_playerPlay, SL_PLAYSTATE_PLAYING);
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerPlay->SetPlayState(SL_PLAYSTATE_PLAYING) failed (result: %d)",result);
|
||||
}
|
||||
}
|
||||
|
||||
if(result != SL_RESULT_SUCCESS)
|
||||
{
|
||||
WriteTrace(TraceAudioInitShutdown, TraceNotice, "Couldn't open OpenSLES audio");
|
||||
CloseAudio();
|
||||
g_critical_failure = true;
|
||||
}
|
||||
#endif
|
||||
WriteTrace(TraceAudioInitShutdown, TraceNotice, "Done");
|
||||
}
|
||||
|
||||
static int resample(unsigned char *input, int /*input_avail*/, int oldsamplerate, unsigned char *output, int output_needed, int newsamplerate)
|
||||
{
|
||||
int *psrc = (int*)input;
|
||||
int *pdest = (int*)output;
|
||||
int i = 0, j = 0;
|
||||
|
||||
#ifdef USE_SPEEX
|
||||
spx_uint32_t in_len, out_len;
|
||||
if(Resample == RESAMPLER_SPEEX)
|
||||
{
|
||||
if(spx_state == NULL)
|
||||
{
|
||||
spx_state = speex_resampler_init(2, oldsamplerate, newsamplerate, ResampleQuality, &error);
|
||||
if(spx_state == NULL)
|
||||
{
|
||||
memset(output, 0, output_needed);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
speex_resampler_set_rate(spx_state, oldsamplerate, newsamplerate);
|
||||
in_len = input_avail / 4;
|
||||
out_len = output_needed / 4;
|
||||
|
||||
if ((error = speex_resampler_process_interleaved_int(spx_state, (const spx_int16_t *)input, &in_len, (spx_int16_t *)output, &out_len)))
|
||||
{
|
||||
memset(output, 0, output_needed);
|
||||
return input_avail; // number of bytes consumed
|
||||
}
|
||||
return in_len * 4;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SRC
|
||||
if(Resample == RESAMPLER_SRC)
|
||||
{
|
||||
// the high quality resampler needs more input than the samplerate ratio would indicate to work properly
|
||||
if (input_avail > output_needed * 3 / 2)
|
||||
input_avail = output_needed * 3 / 2; // just to avoid too much short-float-short conversion time
|
||||
if (_src_len < input_avail*2 && input_avail > 0)
|
||||
{
|
||||
if(_src) free(_src);
|
||||
_src_len = input_avail*2;
|
||||
_src = malloc(_src_len);
|
||||
}
|
||||
if (_dest_len < output_needed*2 && output_needed > 0)
|
||||
{
|
||||
if(_dest) free(_dest);
|
||||
_dest_len = output_needed*2;
|
||||
_dest = malloc(_dest_len);
|
||||
}
|
||||
memset(_src,0,_src_len);
|
||||
memset(_dest,0,_dest_len);
|
||||
if(src_state == NULL)
|
||||
{
|
||||
src_state = src_new (ResampleQuality, 2, &error);
|
||||
if(src_state == NULL)
|
||||
{
|
||||
memset(output, 0, output_needed);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
src_short_to_float_array ((short *) input, _src, input_avail/2);
|
||||
src_data.end_of_input = 0;
|
||||
src_data.data_in = _src;
|
||||
src_data.input_frames = input_avail/4;
|
||||
src_data.src_ratio = (float) newsamplerate / oldsamplerate;
|
||||
src_data.data_out = _dest;
|
||||
src_data.output_frames = output_needed/4;
|
||||
if ((error = src_process (src_state, &src_data)))
|
||||
{
|
||||
memset(output, 0, output_needed);
|
||||
return input_avail; // number of bytes consumed
|
||||
}
|
||||
src_float_to_short_array (_dest, (short *) output, output_needed/2);
|
||||
return src_data.input_frames_used * 4;
|
||||
}
|
||||
#endif
|
||||
// RESAMPLE == TRIVIAL
|
||||
if (newsamplerate >= oldsamplerate)
|
||||
{
|
||||
int sldf = oldsamplerate;
|
||||
int const2 = 2*sldf;
|
||||
int dldf = newsamplerate;
|
||||
int const1 = const2 - 2*dldf;
|
||||
int criteria = const2 - dldf;
|
||||
for (i = 0; i < output_needed/4; i++)
|
||||
{
|
||||
pdest[i] = psrc[j];
|
||||
if(criteria >= 0)
|
||||
{
|
||||
++j;
|
||||
criteria += const1;
|
||||
}
|
||||
else criteria += const2;
|
||||
}
|
||||
return j * 4; //number of bytes consumed
|
||||
}
|
||||
// newsamplerate < oldsamplerate, this only happens when speed_factor > 1
|
||||
for (i = 0; i < output_needed/4; i++)
|
||||
{
|
||||
j = i * oldsamplerate / newsamplerate;
|
||||
pdest[i] = psrc[j];
|
||||
}
|
||||
return j * 4; //number of bytes consumed
|
||||
}
|
||||
|
||||
EXPORT void CALL PluginLoaded(void)
|
||||
{
|
||||
PluginInit();
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
}
|
||||
|
||||
EXPORT void CALL AiDacrateChanged(int SystemType)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Start (SystemType: %d)",SystemType);
|
||||
if (!g_PluginInit)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceNotice, "Plugin has not been initilized");
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
|
||||
return;
|
||||
}
|
||||
|
||||
int f = g_GameFreq != 0 ? g_GameFreq : DEFAULT_FREQUENCY;
|
||||
switch (SystemType)
|
||||
{
|
||||
case SYSTEM_NTSC:
|
||||
f = 48681812 / (*g_AudioInfo.AI__DACRATE_REG + 1);
|
||||
break;
|
||||
case SYSTEM_PAL:
|
||||
f = 49656530 / (*g_AudioInfo.AI__DACRATE_REG + 1);
|
||||
break;
|
||||
case SYSTEM_MPAL:
|
||||
f = 48628316 / (*g_AudioInfo.AI__DACRATE_REG + 1);
|
||||
break;
|
||||
}
|
||||
InitializeAudio(f);
|
||||
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
EXPORT void CALL AiLenChanged(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Start (DRAM_ADDR = 0x%X LenReg = 0x%X)", *g_AudioInfo.AI__LEN_REG, *g_AudioInfo.AI__DRAM_ADDR_REG);
|
||||
|
||||
uint32_t LenReg = *g_AudioInfo.AI__LEN_REG;
|
||||
uint8_t * p = g_AudioInfo.RDRAM + (*g_AudioInfo.AI__DRAM_ADDR_REG & 0xFFFFFF);
|
||||
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "g_primaryBufferPos = 0x%X LenReg = 0x%X g_primaryBufferBytes = %X", g_primaryBufferPos, LenReg, g_primaryBufferBytes);
|
||||
if (g_primaryBufferPos + LenReg < g_primaryBufferBytes)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for ( i = 0 ; i < LenReg ; i += 4 )
|
||||
{
|
||||
if(g_SwapChannels == 0)
|
||||
{
|
||||
/* Left channel */
|
||||
g_primaryBuffer[ g_primaryBufferPos + i ] = p[ i + 2 ];
|
||||
g_primaryBuffer[ g_primaryBufferPos + i + 1 ] = p[ i + 3 ];
|
||||
|
||||
/* Right channel */
|
||||
g_primaryBuffer[ g_primaryBufferPos + i + 2 ] = p[ i ];
|
||||
g_primaryBuffer[ g_primaryBufferPos + i + 3 ] = p[ i + 1 ];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Left channel */
|
||||
g_primaryBuffer[ g_primaryBufferPos + i ] = p[ i ];
|
||||
g_primaryBuffer[ g_primaryBufferPos + i + 1 ] = p[ i + 1 ];
|
||||
|
||||
/* Right channel */
|
||||
g_primaryBuffer[ g_primaryBufferPos + i + 2 ] = p[ i + 2];
|
||||
g_primaryBuffer[ g_primaryBufferPos + i + 3 ] = p[ i + 3 ];
|
||||
}
|
||||
}
|
||||
g_primaryBufferPos += i;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Audio primary buffer overflow. (g_primaryBufferPos: %d LenReg: %d g_primaryBufferBytes: %d)", g_primaryBufferPos, LenReg, g_primaryBufferBytes);
|
||||
}
|
||||
|
||||
uint32_t newsamplerate = g_OutputFreq * 100 / g_speed_factor;
|
||||
uint32_t oldsamplerate = g_GameFreq != 0 ? g_GameFreq : DEFAULT_FREQUENCY;
|
||||
|
||||
while (g_primaryBufferPos >= ((g_secondaryBufferBytes * oldsamplerate) / newsamplerate))
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "g_secondaryBufferBytes = %d", g_secondaryBufferBytes);
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "oldsamplerate = %d", oldsamplerate);
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "newsamplerate = %d", newsamplerate);
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "((g_secondaryBufferBytes * oldsamplerate) / newsamplerate) = %d", ((g_secondaryBufferBytes * oldsamplerate) / newsamplerate));
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "g_primaryBufferPos= %d", g_primaryBufferPos);
|
||||
#ifdef ANDROID
|
||||
pthread_mutex_lock(&(g_lock.mutex));
|
||||
|
||||
/* Wait for the next callback if no more output buffers available */
|
||||
while (g_lock.value == 0)
|
||||
{
|
||||
pthread_cond_wait(&(g_lock.cond), &(g_lock.mutex));
|
||||
}
|
||||
|
||||
g_lock.value--;
|
||||
|
||||
pthread_mutex_unlock(&(g_lock.mutex));
|
||||
#endif
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Finished with lock");
|
||||
|
||||
// TODO: don't resample if speed_factor = 100 and newsamplerate ~= oldsamplerate
|
||||
int input_used = resample(g_primaryBuffer, g_primaryBufferPos, oldsamplerate, g_secondaryBuffers[g_secondaryBufferIndex], g_secondaryBufferBytes, newsamplerate);
|
||||
|
||||
#ifdef ANDROID
|
||||
(*g_bufferQueue)->Enqueue(g_bufferQueue, g_secondaryBuffers[g_secondaryBufferIndex], g_secondaryBufferBytes);
|
||||
#endif
|
||||
memmove(g_primaryBuffer, &g_primaryBuffer[input_used], g_primaryBufferPos - input_used);
|
||||
g_primaryBufferPos -= input_used;
|
||||
|
||||
g_secondaryBufferIndex++;
|
||||
|
||||
if(g_secondaryBufferIndex > (g_SecondaryBufferNbr-1))
|
||||
{
|
||||
g_secondaryBufferIndex = 0;
|
||||
}
|
||||
}
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
EXPORT uint32_t CALL AiReadLength(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT void CALL AiUpdate(int32_t /*Wait*/)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
}
|
||||
|
||||
EXPORT void CALL CloseDLL(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
}
|
||||
|
||||
EXPORT void CALL DllAbout(void * /*hParent*/)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
}
|
||||
|
||||
EXPORT void CALL DllConfig(void * /*hParent*/)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
}
|
||||
|
||||
EXPORT void CALL DllTest(void * /*hParent*/)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
}
|
||||
|
||||
EXPORT void CALL GetDllInfo(PLUGIN_INFO * PluginInfo)
|
||||
{
|
||||
PluginInfo->Version = 0x0101;
|
||||
PluginInfo->Type = PLUGIN_TYPE_AUDIO;
|
||||
#ifdef _DEBUG
|
||||
sprintf(PluginInfo->Name, "Android Audio Debug Plugin %s", VER_FILE_VERSION_STR);
|
||||
#else
|
||||
sprintf(PluginInfo->Name, "Android Audio Plugin %s", VER_FILE_VERSION_STR);
|
||||
#endif
|
||||
PluginInfo->MemoryBswaped = true;
|
||||
PluginInfo->NormalMemory = false;
|
||||
}
|
||||
|
||||
EXPORT int32_t CALL InitiateAudio(AUDIO_INFO Audio_Info)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Start");
|
||||
g_AudioInfo = Audio_Info;
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Done (res: true)");
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT void CALL RomOpen()
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Start");
|
||||
InitializeAudio(DEFAULT_FREQUENCY);
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
EXPORT void CALL RomClosed(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Start");
|
||||
CloseAudio();
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
EXPORT void CALL ProcessAList(void)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
}
|
||||
|
||||
extern "C" void UseUnregisteredSetting(int /*SettingID*/)
|
||||
{
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
|
||||
#ifdef _WIN32
|
||||
DebugBreak();
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D233025A-231F-4A43-92B6-E87193C60ACC}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>PluginAudio</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(SolutionDir)PropertySheets\Platform.$(Configuration).props" />
|
||||
</ImportGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<PropertyGroup>
|
||||
<TargetName>AndroidAudio</TargetName>
|
||||
<TargetName Condition="'$(Configuration)'=='Debug'">AndroidAudio_d</TargetName>
|
||||
<OutDir>$(SolutionDir)Plugin\Audio\</OutDir>
|
||||
<OutDir Condition="'$(Platform)'=='x64'">$(SolutionDir)Plugin64\AndroidAudio\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AudioSettings.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Audio_1.1.h" />
|
||||
<ClInclude Include="AudioSettings.h" />
|
||||
<ClInclude Include="main.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="Version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Common\Common.vcxproj">
|
||||
<Project>{b4a4b994-9111-42b1-93c2-6f1ca8bc4421}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Settings\Settings.vcxproj">
|
||||
<Project>{8b9961b1-88d9-4ea3-a752-507a00dd9f3d}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AudioSettings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Audio_1.1.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Version.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AudioSettings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="main.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,42 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64 - A Nintendo 64 emulator. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2016 Project64. All rights reserved. *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#define STRINGIZE2(s) #s
|
||||
#define STRINGIZE(s) STRINGIZE2(s)
|
||||
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 0
|
||||
#define VERSION_BUILD 9999
|
||||
|
||||
#define VER_FILE_DESCRIPTION_STR "Android Audio Plugin"
|
||||
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
|
||||
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
|
||||
"." STRINGIZE(VERSION_MINOR) \
|
||||
"." STRINGIZE(VERSION_REVISION) \
|
||||
"." STRINGIZE(VERSION_BUILD) \
|
||||
|
||||
#define VER_PRODUCTNAME_STR "Android-Audio"
|
||||
#define VER_PRODUCT_VERSION VER_FILE_VERSION
|
||||
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
|
||||
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll"
|
||||
#define VER_INTERNAL_NAME_STR VER_PRODUCTNAME_STR
|
||||
#define VER_COPYRIGHT_STR "Copyright (C) 2016"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define VER_VER_DEBUG VS_FF_DEBUG
|
||||
#else
|
||||
#define VER_VER_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define VER_FILEOS VOS_NT_WINDOWS32
|
||||
#define VER_FILEFLAGS VER_VER_DEBUG
|
||||
#define VER_FILETYPE VFT_DLL
|
|
@ -0,0 +1,40 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64 - A Nintendo 64 emulator. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2016 Project64. All rights reserved. *
|
||||
* Copyright (C) 2008-2012 Tillin9, Richard42 *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
/* Default start-time size of primary buffer (in equivalent output samples).
|
||||
This is the buffer where audio is loaded after it's extracted from n64's memory. */
|
||||
enum { PRIMARY_BUFFER_SIZE = 16384 };
|
||||
|
||||
/* Size of a single secondary buffer, in output samples. This is the requested size of OpenSLES's
|
||||
hardware buffer, this should be a power of two. */
|
||||
enum { SECONDARY_BUFFER_SIZE = 1024 };
|
||||
|
||||
/* This is the requested number of OpenSLES's hardware buffers */
|
||||
enum { SECONDARY_BUFFER_NBR = 2 };
|
||||
|
||||
/* This sets default frequency what is used if rom doesn't want to change it.
|
||||
Probably only game that needs this is Zelda: Ocarina Of Time Master Quest
|
||||
*NOTICE* We should try to find out why Demos' frequencies are always wrong
|
||||
They tend to rely on a default frequency, apparently, never the same one ;) */
|
||||
enum { DEFAULT_FREQUENCY = 33600 };
|
||||
|
||||
/* number of bytes per sample */
|
||||
enum
|
||||
{
|
||||
N64_SAMPLE_BYTES = 4,
|
||||
SLES_SAMPLE_BYTES = 4,
|
||||
};
|
||||
|
||||
extern bool g_SwapChannels;
|
||||
extern uint32_t g_GameFreq;
|
|
@ -0,0 +1,83 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64 - A Nintendo 64 emulator. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2016 Project64. All rights reserved. *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#include "trace.h"
|
||||
#include <Common/path.h>
|
||||
#include <Common/LogClass.h>
|
||||
#include <Settings/Settings.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
|
||||
class AndroidLogger : public CTraceModule
|
||||
{
|
||||
void Write(uint32_t module, uint8_t severity, const char * file, int line, const char * function, const char * Message)
|
||||
{
|
||||
switch (severity)
|
||||
{
|
||||
case TraceError: __android_log_print(ANDROID_LOG_ERROR, TraceModule(module), "%s: %s", function, Message); break;
|
||||
case TraceWarning: __android_log_print(ANDROID_LOG_WARN, TraceModule(module), "%s: %s", function, Message); break;
|
||||
case TraceNotice: __android_log_print(ANDROID_LOG_INFO, TraceModule(module), "%s: %s", function, Message); break;
|
||||
case TraceInfo: __android_log_print(ANDROID_LOG_INFO, TraceModule(module), "%s: %s", function, Message); break;
|
||||
case TraceDebug: __android_log_print(ANDROID_LOG_DEBUG, TraceModule(module), "%s: %s", function, Message); break;
|
||||
case TraceVerbose: __android_log_print(ANDROID_LOG_VERBOSE, TraceModule(module), "%s: %s", function, Message); break;
|
||||
default: __android_log_print(ANDROID_LOG_UNKNOWN, TraceModule(module), "%s: %s", function, Message); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
static AndroidLogger * g_AndroidLogger = NULL;
|
||||
#endif
|
||||
static CTraceFileLog * g_LogFile = NULL;
|
||||
|
||||
void SetupTrace(void)
|
||||
{
|
||||
if (g_LogFile != NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
if (g_AndroidLogger == NULL)
|
||||
{
|
||||
g_AndroidLogger = new AndroidLogger();
|
||||
}
|
||||
TraceAddModule(g_AndroidLogger);
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
TraceSetMaxModule(MaxTraceModulePluginAudio, TraceInfo);
|
||||
#else
|
||||
TraceSetMaxModule(MaxTraceModulePluginAudio, TraceError);
|
||||
#endif
|
||||
TraceSetModuleName(TraceAudioInitShutdown, "AudioInitShutdown");
|
||||
TraceSetModuleName(TraceAudioInterface, "AudioInterface");
|
||||
|
||||
char log_dir[260];
|
||||
memset(log_dir, 0, sizeof(log_dir));
|
||||
short logDirSetting = FindSystemSettingId("Dir:Log");
|
||||
short logFlushSetting = FindSystemSettingId("Log Auto Flush");
|
||||
if (logDirSetting != 0)
|
||||
{
|
||||
GetSystemSettingSz(logDirSetting, log_dir, sizeof(log_dir));
|
||||
}
|
||||
|
||||
if (strlen(log_dir) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CPath LogFilePath(log_dir,"PluginAudio.log");
|
||||
if (!LogFilePath.DirectoryExists())
|
||||
{
|
||||
LogFilePath.DirectoryCreate();
|
||||
}
|
||||
g_LogFile = new CTraceFileLog(LogFilePath, GetSystemSetting(logFlushSetting) != 0, CLog::Log_New, 500);
|
||||
TraceAddModule(g_LogFile);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64 - A Nintendo 64 emulator. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2016 Project64. All rights reserved. *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
#include <Common/TraceModulesCommon.h>
|
||||
#include <Common/Trace.h>
|
||||
|
||||
enum TraceModuleAndroidAudio
|
||||
{
|
||||
TraceSettings = MaxTraceModuleCommon,
|
||||
TraceAudioInitShutdown,
|
||||
TraceAudioInterface,
|
||||
MaxTraceModulePluginAudio,
|
||||
};
|
||||
|
||||
void SetupTrace(void);
|
Loading…
Reference in New Issue