mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-23 06:10:03 -06:00
hook up microphone shit.
I did my best.
This commit is contained in:
@ -101,6 +101,17 @@ int AudioOut_GetNumSamples(int outlen);
|
|||||||
// note: this assumes the output buffer is interleaved stereo
|
// note: this assumes the output buffer is interleaved stereo
|
||||||
void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen);
|
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
|
#endif // FRONTENDUTIL_H
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@ -26,7 +27,6 @@
|
|||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "GBACart.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Frontend
|
namespace Frontend
|
||||||
@ -35,13 +35,22 @@ namespace Frontend
|
|||||||
int AudioOut_Freq;
|
int AudioOut_Freq;
|
||||||
float AudioOut_SampleFrac;
|
float AudioOut_SampleFrac;
|
||||||
|
|
||||||
|
s16* MicBuffer;
|
||||||
|
u32 MicBufferLength;
|
||||||
|
u32 MicBufferReadPos;
|
||||||
|
|
||||||
|
|
||||||
void Init_Audio(int outputfreq)
|
void Init_Audio(int outputfreq)
|
||||||
{
|
{
|
||||||
AudioOut_Freq = outputfreq;
|
AudioOut_Freq = outputfreq;
|
||||||
AudioOut_SampleFrac = 0;
|
AudioOut_SampleFrac = 0;
|
||||||
|
|
||||||
|
MicBuffer = nullptr;
|
||||||
|
MicBufferLength = 0;
|
||||||
|
MicBufferReadPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int AudioOut_GetNumSamples(int outlen)
|
int AudioOut_GetNumSamples(int outlen)
|
||||||
{
|
{
|
||||||
float f_len_in = (outlen * 32823.6328125) / (float)AudioOut_Freq;
|
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_cond* audioSync;
|
||||||
SDL_mutex* audioSyncLock;
|
SDL_mutex* audioSyncLock;
|
||||||
|
|
||||||
|
SDL_AudioDeviceID micDevice;
|
||||||
|
s16 micExtBuffer[2048];
|
||||||
|
u32 micExtBufferWritePos;
|
||||||
|
|
||||||
|
u32 micWavLength;
|
||||||
|
s16* micWavBuffer;
|
||||||
|
|
||||||
|
|
||||||
void audioCallback(void* data, Uint8* stream, int len)
|
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)
|
EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||||
{
|
{
|
||||||
EmuStatus = 0;
|
EmuStatus = 0;
|
||||||
@ -189,9 +323,9 @@ void EmuThread::run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// microphone input
|
// microphone input
|
||||||
/*FeedMicInput();
|
micProcess();
|
||||||
|
|
||||||
if (Screen_UseGL)
|
/*if (Screen_UseGL)
|
||||||
{
|
{
|
||||||
uiGLBegin(GLContext);
|
uiGLBegin(GLContext);
|
||||||
uiGLMakeContextCurrent(GLContext);
|
uiGLMakeContextCurrent(GLContext);
|
||||||
@ -365,6 +499,7 @@ void EmuThread::emuRun()
|
|||||||
// checkme
|
// checkme
|
||||||
emit windowEmuStart();
|
emit windowEmuStart();
|
||||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0);
|
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0);
|
||||||
|
if (micDevice) SDL_PauseAudioDevice(micDevice, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::emuPause()
|
void EmuThread::emuPause()
|
||||||
@ -374,6 +509,7 @@ void EmuThread::emuPause()
|
|||||||
while (EmuStatus != 2);
|
while (EmuStatus != 2);
|
||||||
|
|
||||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1);
|
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1);
|
||||||
|
if (micDevice) SDL_PauseAudioDevice(micDevice, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::emuUnpause()
|
void EmuThread::emuUnpause()
|
||||||
@ -381,6 +517,7 @@ void EmuThread::emuUnpause()
|
|||||||
EmuRunning = PrevEmuStatus;
|
EmuRunning = PrevEmuStatus;
|
||||||
|
|
||||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0);
|
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0);
|
||||||
|
if (micDevice) SDL_PauseAudioDevice(micDevice, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::emuStop()
|
void EmuThread::emuStop()
|
||||||
@ -388,6 +525,7 @@ void EmuThread::emuStop()
|
|||||||
EmuRunning = 0;
|
EmuRunning = 0;
|
||||||
|
|
||||||
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1);
|
if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1);
|
||||||
|
if (micDevice) SDL_PauseAudioDevice(micDevice, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuThread::emuIsRunning()
|
bool EmuThread::emuIsRunning()
|
||||||
@ -1300,9 +1438,40 @@ int main(int argc, char** argv)
|
|||||||
SDL_PauseAudioDevice(audioDevice, 1);
|
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_ROM();
|
||||||
Frontend::Init_Audio(audioFreq);
|
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::JoystickID = Config::JoystickID;
|
||||||
Input::OpenJoystick();
|
Input::OpenJoystick();
|
||||||
|
|
||||||
@ -1349,12 +1518,12 @@ int main(int argc, char** argv)
|
|||||||
Input::CloseJoystick();
|
Input::CloseJoystick();
|
||||||
|
|
||||||
if (audioDevice) SDL_CloseAudioDevice(audioDevice);
|
if (audioDevice) SDL_CloseAudioDevice(audioDevice);
|
||||||
//if (MicDevice) SDL_CloseAudioDevice(MicDevice);
|
if (micDevice) SDL_CloseAudioDevice(micDevice);
|
||||||
|
|
||||||
SDL_DestroyCond(audioSync);
|
SDL_DestroyCond(audioSync);
|
||||||
SDL_DestroyMutex(audioSyncLock);
|
SDL_DestroyMutex(audioSyncLock);
|
||||||
|
|
||||||
//if (MicWavBuffer) delete[] MicWavBuffer;
|
if (micWavBuffer) delete[] micWavBuffer;
|
||||||
|
|
||||||
Config::Save();
|
Config::Save();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user