diff options
Diffstat (limited to 'src/jogl/native/audio/Mixer.cpp')
-rw-r--r-- | src/jogl/native/audio/Mixer.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/jogl/native/audio/Mixer.cpp b/src/jogl/native/audio/Mixer.cpp new file mode 100644 index 000000000..9fa5b61bc --- /dev/null +++ b/src/jogl/native/audio/Mixer.cpp @@ -0,0 +1,199 @@ +#include <windows.h> +#include <stdlib.h> +#include <mmsystem.h> +#include <mmreg.h> +#include "com_jogamp_audio_windows_waveout_Mixer.h" + +static HANDLE event = NULL; +static HWAVEOUT output = NULL; +// We use only two buffers to keep latency down +#define NUM_BUFFERS 2 +//#define NUM_BUFFERS 4 +// This is about 20 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (20 ms / 1000 ms) * (2 bytes / sample) * (2 channels) +//#define BUFFER_SIZE 3528 + +// This is about 50 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (50 ms / 1000 ms) * (2 bytes / sample) * (1 channel) +//#define BUFFER_SIZE 4410 + +// This is about 200 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (1 channel) +//#define BUFFER_SIZE 17640 + +// This is about 200 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (2 channel) +//#define BUFFER_SIZE 35280 + +// This is about 1000 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (1000 ms / 1000 ms) * (2 bytes / sample) * (1 channel) +//#define BUFFER_SIZE 88200 + +// This is about 50 ms of data for WAVE_FORMAT_PCM: +// (44100 samples / sec) * (50 ms / 1000 ms) * (2 bytes / sample) * (2 channels) +//#define BUFFER_SIZE 8820 + +// This is about 50 ms of data for WAVE_FORMAT_IEEE_FLOAT: +// (44100 samples / sec) * (50 ms / 1000 ms) * (4 bytes / sample) * (2 channels) +//#define BUFFER_SIZE 17640 + +// This is about 200 ms of data for WAVE_FORMAT_PCM: +// (11025 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (2 channel) +#define BUFFER_SIZE 8820 + +//#define BUFFER_SIZE 8192 +static WAVEHDR** buffers = NULL; + +void CALLBACK playbackCallback(HWAVEOUT output, + UINT msg, + DWORD_PTR userData, + DWORD_PTR param1, + DWORD_PTR param2) +{ + if (msg == WOM_DONE) { + WAVEHDR* hdr = (WAVEHDR*) param1; + hdr->dwFlags |= WHDR_DONE; + SetEvent(event); + } +} + +JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_initializeWaveOut + (JNIEnv *env, jclass unused, jlong eventObject) +{ + event = (HANDLE) eventObject; + + // Note the hard requirements on the RawSoundConverter's output format + WAVEFORMATEX format; + format.wFormatTag = WAVE_FORMAT_PCM; + // format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + format.nChannels = 2; + // format.nChannels = 1; + // format.nSamplesPerSec = 44100; + format.nSamplesPerSec = 11025; + format.wBitsPerSample = 16; + // format.wBitsPerSample = 32; + format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; + format.nAvgBytesPerSec = format.nBlockAlign * format.nSamplesPerSec; + format.cbSize = 0; + MMRESULT res = waveOutOpen(&output, + WAVE_MAPPER, + &format, + /* NULL, */ (DWORD_PTR) &playbackCallback, + NULL, // No user data right now + /* CALLBACK_NULL */ CALLBACK_FUNCTION); + if (res != MMSYSERR_NOERROR) { + return JNI_FALSE; + } + + buffers = (WAVEHDR**) calloc(NUM_BUFFERS, sizeof(WAVEHDR)); + for (int i = 0; i < NUM_BUFFERS; i++) { + char* data = (char*) calloc(BUFFER_SIZE, 1); + WAVEHDR* hdr = (WAVEHDR*) calloc(1, sizeof(WAVEHDR)); + hdr->lpData = data; + hdr->dwBufferLength = BUFFER_SIZE; + hdr->dwFlags |= WHDR_DONE; + buffers[i] = hdr; + } + + return JNI_TRUE; +} + +JNIEXPORT void JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_shutdownWaveOut + (JNIEnv *env, jclass unused) +{ + // writeString("Pausing\n"); + waveOutPause(output); + // writeString("Resetting\n"); + waveOutReset(output); + // writeString("Closing output\n"); + waveOutClose(output); +} + +JNIEXPORT jlong JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getNextMixerBuffer + (JNIEnv *env, jclass unused) +{ + WAVEHDR* hdr = NULL; + for (int i = 0; i < NUM_BUFFERS; i++) { + if (buffers[i] != NULL && ((buffers[i]->dwFlags & WHDR_DONE) != 0)) { + hdr = buffers[i]; + hdr->dwFlags &= ~WHDR_DONE; + break; + } + } + return (jlong) hdr; +} + +JNIEXPORT jobject JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getMixerBufferData + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + WAVEHDR* hdr = (WAVEHDR*) mixerBuffer; + return env->NewDirectByteBuffer(hdr->lpData, hdr->dwBufferLength); +} + +JNIEXPORT jlong JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getMixerBufferDataAddress + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + WAVEHDR* hdr = (WAVEHDR*) mixerBuffer; + return (jlong) hdr->lpData; +} + +JNIEXPORT jint JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getMixerBufferDataCapacity + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + WAVEHDR* hdr = (WAVEHDR*) mixerBuffer; + return (jint) hdr->dwBufferLength; +} + +JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_prepareMixerBuffer + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + MMRESULT res = waveOutPrepareHeader(output, + (WAVEHDR*) mixerBuffer, + sizeof(WAVEHDR)); + if (res == MMSYSERR_NOERROR) { + return JNI_TRUE; + } + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_writeMixerBuffer + (JNIEnv *env, jclass unused, jlong mixerBuffer) +{ + MMRESULT res = waveOutWrite(output, + (WAVEHDR*) mixerBuffer, + sizeof(WAVEHDR)); + if (res == MMSYSERR_NOERROR) { + waveOutRestart(output); + + return JNI_TRUE; + } + return JNI_FALSE; +} + +JNIEXPORT jlong JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_CreateEvent + (JNIEnv *env, jclass unused) +{ + return (jlong) CreateEvent(NULL, FALSE, TRUE, NULL); +} + +JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_WaitForSingleObject + (JNIEnv *env, jclass unused, jlong eventObject) +{ + DWORD res = WaitForSingleObject((HANDLE) eventObject, INFINITE); + if (res == WAIT_OBJECT_0) { + return JNI_TRUE; + } + return JNI_FALSE; +} + +JNIEXPORT void JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_SetEvent + (JNIEnv *env, jclass unused, jlong eventObject) +{ + SetEvent((HANDLE) eventObject); +} + +JNIEXPORT void JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_CloseHandle + (JNIEnv *env, jclass unused, jlong eventObject) +{ + CloseHandle((HANDLE) eventObject); +} |