parent
a9b275bc25
commit
9e43c85b4d
|
@ -101,6 +101,17 @@ int AudioOut_GetNumSamples(int outlen);
|
|||
// note: this assumes the output buffer is interleaved stereo
|
||||
void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen);
|
||||
|
||||
// feed silence to the microphone input
|
||||
void Mic_FeedSilence();
|
||||
|
||||
// feed random noise to the microphone input
|
||||
void Mic_FeedNoise();
|
||||
|
||||
// feed an external buffer to the microphone input
|
||||
// buffer should be mono
|
||||
void Mic_FeedExternalBuffer();
|
||||
void Mic_SetExternalBuffer(s16* buffer, u32 len);
|
||||
|
||||
}
|
||||
|
||||
#endif // FRONTENDUTIL_H
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -26,7 +27,6 @@
|
|||
#include "Platform.h"
|
||||
|
||||
#include "NDS.h"
|
||||
#include "GBACart.h"
|
||||
|
||||
|
||||
namespace Frontend
|
||||
|
@ -35,13 +35,22 @@ namespace Frontend
|
|||
int AudioOut_Freq;
|
||||
float AudioOut_SampleFrac;
|
||||
|
||||
s16* MicBuffer;
|
||||
u32 MicBufferLength;
|
||||
u32 MicBufferReadPos;
|
||||
|
||||
|
||||
void Init_Audio(int outputfreq)
|
||||
{
|
||||
AudioOut_Freq = outputfreq;
|
||||
AudioOut_SampleFrac = 0;
|
||||
|
||||
MicBuffer = nullptr;
|
||||
MicBufferLength = 0;
|
||||
MicBufferReadPos = 0;
|
||||
}
|
||||
|
||||
|
||||
int AudioOut_GetNumSamples(int outlen)
|
||||
{
|
||||
float f_len_in = (outlen * 32823.6328125) / (float)AudioOut_Freq;
|
||||
|
@ -74,4 +83,57 @@ void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Mic_FeedSilence()
|
||||
{
|
||||
MicBufferReadPos = 0;
|
||||
NDS::MicInputFrame(NULL, 0);
|
||||
}
|
||||
|
||||
void Mic_FeedNoise()
|
||||
{
|
||||
// note: DS games seem to expect very saturated 'blowing into mic' noise
|
||||
|
||||
s16 tmp[735];
|
||||
|
||||
for (int i = 0; i < 735; i++)
|
||||
{
|
||||
int val = rand() >> 8;
|
||||
if (val < -0x8000) val = -0x8000;
|
||||
else if (val > 0x7FFF) val = 0x7FFF;
|
||||
|
||||
tmp[i] = val;
|
||||
}
|
||||
|
||||
NDS::MicInputFrame(tmp, 735);
|
||||
}
|
||||
|
||||
void Mic_FeedExternalBuffer()
|
||||
{
|
||||
if (!MicBuffer) return Mic_FeedSilence();
|
||||
|
||||
if ((MicBufferReadPos + 735) > MicBufferLength)
|
||||
{
|
||||
s16 tmp[735];
|
||||
u32 len1 = MicBufferLength - MicBufferReadPos;
|
||||
memcpy(&tmp[0], &MicBuffer[MicBufferReadPos], len1*sizeof(s16));
|
||||
memcpy(&tmp[len1], &MicBuffer[0], (735 - len1)*sizeof(s16));
|
||||
|
||||
NDS::MicInputFrame(tmp, 735);
|
||||
MicBufferReadPos = 735 - len1;
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS::MicInputFrame(&MicBuffer[MicBufferReadPos], 735);
|
||||
MicBufferReadPos += 735;
|
||||
}
|
||||
}
|
||||
|
||||
void Mic_SetExternalBuffer(s16* buffer, u32 len)
|
||||
{
|
||||
MicBuffer = buffer;
|
||||
MicBufferLength = len;
|
||||
MicBufferReadPos = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,6 +66,13 @@ int audioFreq;
|
|||
SDL_cond* audioSync;
|
||||
SDL_mutex* audioSyncLock;
|
||||
|
||||
SDL_AudioDeviceID micDevice;
|
||||
s16 micExtBuffer[2048];
|
||||
u32 micExtBufferWritePos;
|
||||
|
||||
u32 micWavLength;
|
||||
s16* micWavBuffer;
|
||||
|
||||
|
||||
void audioCallback(void* data, Uint8* stream, int len)
|
||||
{
|
||||
|
@ -104,6 +111,133 @@ void audioCallback(void* data, Uint8* stream, int len)
|
|||
}
|
||||
|
||||
|
||||
void micLoadWav(const char* name)
|
||||
{
|
||||
SDL_AudioSpec format;
|
||||
memset(&format, 0, sizeof(SDL_AudioSpec));
|
||||
|
||||
if (micWavBuffer) delete[] micWavBuffer;
|
||||
micWavBuffer = nullptr;
|
||||
micWavLength = 0;
|
||||
|
||||
u8* buf;
|
||||
u32 len;
|
||||
if (!SDL_LoadWAV(name, &format, &buf, &len))
|
||||
return;
|
||||
|
||||
const u64 dstfreq = 44100;
|
||||
|
||||
if (format.format == AUDIO_S16 || format.format == AUDIO_U16)
|
||||
{
|
||||
int srcinc = format.channels;
|
||||
len /= (2 * srcinc);
|
||||
|
||||
micWavLength = (len * dstfreq) / format.freq;
|
||||
if (micWavLength < 735) micWavLength = 735;
|
||||
micWavBuffer = new s16[micWavLength];
|
||||
|
||||
float res_incr = len / (float)micWavLength;
|
||||
float res_timer = 0;
|
||||
int res_pos = 0;
|
||||
|
||||
for (int i = 0; i < micWavLength; i++)
|
||||
{
|
||||
u16 val = ((u16*)buf)[res_pos];
|
||||
if (SDL_AUDIO_ISUNSIGNED(format.format)) val ^= 0x8000;
|
||||
|
||||
micWavBuffer[i] = val;
|
||||
|
||||
res_timer += res_incr;
|
||||
while (res_timer >= 1.0)
|
||||
{
|
||||
res_timer -= 1.0;
|
||||
res_pos += srcinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (format.format == AUDIO_S8 || format.format == AUDIO_U8)
|
||||
{
|
||||
int srcinc = format.channels;
|
||||
len /= srcinc;
|
||||
|
||||
micWavLength = (len * dstfreq) / format.freq;
|
||||
if (micWavLength < 735) micWavLength = 735;
|
||||
micWavBuffer = new s16[micWavLength];
|
||||
|
||||
float res_incr = len / (float)micWavLength;
|
||||
float res_timer = 0;
|
||||
int res_pos = 0;
|
||||
|
||||
for (int i = 0; i < micWavLength; i++)
|
||||
{
|
||||
u16 val = buf[res_pos] << 8;
|
||||
if (SDL_AUDIO_ISUNSIGNED(format.format)) val ^= 0x8000;
|
||||
|
||||
micWavBuffer[i] = val;
|
||||
|
||||
res_timer += res_incr;
|
||||
while (res_timer >= 1.0)
|
||||
{
|
||||
res_timer -= 1.0;
|
||||
res_pos += srcinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("bad WAV format %08X\n", format.format);
|
||||
|
||||
SDL_FreeWAV(buf);
|
||||
}
|
||||
|
||||
void micCallback(void* data, Uint8* stream, int len)
|
||||
{
|
||||
s16* input = (s16*)stream;
|
||||
len /= sizeof(s16);
|
||||
|
||||
int maxlen = sizeof(micExtBuffer) / sizeof(s16);
|
||||
|
||||
if ((micExtBufferWritePos + len) > maxlen)
|
||||
{
|
||||
u32 len1 = maxlen - micExtBufferWritePos;
|
||||
memcpy(&micExtBuffer[micExtBufferWritePos], &input[0], len1*sizeof(s16));
|
||||
memcpy(&micExtBuffer[0], &input[len1], (len - len1)*sizeof(s16));
|
||||
micExtBufferWritePos = len - len1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&micExtBuffer[micExtBufferWritePos], input, len*sizeof(s16));
|
||||
micExtBufferWritePos += len;
|
||||
}
|
||||
}
|
||||
|
||||
void micProcess()
|
||||
{
|
||||
int type = Config::MicInputType;
|
||||
bool cmd = Input::HotkeyDown(HK_Mic);
|
||||
|
||||
if (type != 1 && !cmd)
|
||||
{
|
||||
type = 0;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0: // no mic
|
||||
Frontend::Mic_FeedSilence();
|
||||
break;
|
||||
|
||||
case 1: // host mic
|
||||
case 3: // WAV
|
||||
Frontend::Mic_FeedExternalBuffer();
|
||||
break;
|
||||
|
||||
case 2: // white noise
|
||||
Frontend::Mic_FeedNoise();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||
{
|
||||
EmuStatus = 0;
|
||||
|
@ -189,9 +323,9 @@ void EmuThread::run()
|
|||
}
|
||||
|
||||
// microphone input
|
||||
/*FeedMicInput();
|
||||
micProcess();
|
||||
|
||||
if (Screen_UseGL)
|
||||
/*if (Screen_UseGL)
|
||||
{
|
||||
uiGLBegin(GLContext);
|
||||
uiGLMakeContextCurrent(GLContext);
|
||||
|
@ -365,6 +499,7 @@ void EmuThread::emuRun()
|
|||
// checkme
|
||||
emit windowEmuStart();
|
||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0);
|
||||
if (micDevice) SDL_PauseAudioDevice(micDevice, 0);
|
||||
}
|
||||
|
||||
void EmuThread::emuPause()
|
||||
|
@ -374,6 +509,7 @@ void EmuThread::emuPause()
|
|||
while (EmuStatus != 2);
|
||||
|
||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1);
|
||||
if (micDevice) SDL_PauseAudioDevice(micDevice, 1);
|
||||
}
|
||||
|
||||
void EmuThread::emuUnpause()
|
||||
|
@ -381,6 +517,7 @@ void EmuThread::emuUnpause()
|
|||
EmuRunning = PrevEmuStatus;
|
||||
|
||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0);
|
||||
if (micDevice) SDL_PauseAudioDevice(micDevice, 0);
|
||||
}
|
||||
|
||||
void EmuThread::emuStop()
|
||||
|
@ -388,6 +525,7 @@ void EmuThread::emuStop()
|
|||
EmuRunning = 0;
|
||||
|
||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1);
|
||||
if (micDevice) SDL_PauseAudioDevice(micDevice, 1);
|
||||
}
|
||||
|
||||
bool EmuThread::emuIsRunning()
|
||||
|
@ -1300,9 +1438,40 @@ int main(int argc, char** argv)
|
|||
SDL_PauseAudioDevice(audioDevice, 1);
|
||||
}
|
||||
|
||||
memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
|
||||
whatIwant.freq = 44100;
|
||||
whatIwant.format = AUDIO_S16LSB;
|
||||
whatIwant.channels = 1;
|
||||
whatIwant.samples = 1024;
|
||||
whatIwant.callback = micCallback;
|
||||
micDevice = SDL_OpenAudioDevice(NULL, 1, &whatIwant, &whatIget, 0);
|
||||
if (!micDevice)
|
||||
{
|
||||
printf("Mic init failed: %s\n", SDL_GetError());
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_PauseAudioDevice(micDevice, 1);
|
||||
}
|
||||
|
||||
|
||||
memset(micExtBuffer, 0, sizeof(micExtBuffer));
|
||||
micExtBufferWritePos = 0;
|
||||
micWavBuffer = nullptr;
|
||||
|
||||
Frontend::Init_ROM();
|
||||
Frontend::Init_Audio(audioFreq);
|
||||
|
||||
if (Config::MicInputType == 1)
|
||||
{
|
||||
Frontend::Mic_SetExternalBuffer(micExtBuffer, sizeof(micExtBuffer)/sizeof(s16));
|
||||
}
|
||||
else if (Config::MicInputType == 3)
|
||||
{
|
||||
micLoadWav(Config::MicWavPath);
|
||||
Frontend::Mic_SetExternalBuffer(micWavBuffer, micWavLength);
|
||||
}
|
||||
|
||||
Input::JoystickID = Config::JoystickID;
|
||||
Input::OpenJoystick();
|
||||
|
||||
|
@ -1349,12 +1518,12 @@ int main(int argc, char** argv)
|
|||
Input::CloseJoystick();
|
||||
|
||||
if (audioDevice) SDL_CloseAudioDevice(audioDevice);
|
||||
//if (MicDevice) SDL_CloseAudioDevice(MicDevice);
|
||||
if (micDevice) SDL_CloseAudioDevice(micDevice);
|
||||
|
||||
SDL_DestroyCond(audioSync);
|
||||
SDL_DestroyMutex(audioSyncLock);
|
||||
|
||||
//if (MicWavBuffer) delete[] MicWavBuffer;
|
||||
if (micWavBuffer) delete[] micWavBuffer;
|
||||
|
||||
Config::Save();
|
||||
|
||||
|
|
Loading…
Reference in New Issue