Jogamp
moved com.jogamp.javafx.* to com.jogamp.*.
[jogl.git] / src / jogl / native / audio / Mixer.cpp
1 #include <windows.h>
2 #include <stdlib.h>
3 #include <mmsystem.h>
4 #include <mmreg.h>
5 #include "com_jogamp_audio_windows_waveout_Mixer.h"
6
7 static HANDLE event = NULL;
8 static HWAVEOUT output = NULL;
9 // We use only two buffers to keep latency down
10 #define NUM_BUFFERS 2
11 //#define NUM_BUFFERS 4
12 // This is about 20 ms of data for WAVE_FORMAT_PCM:
13 // (44100 samples / sec) * (20 ms / 1000 ms) * (2 bytes / sample) * (2 channels)
14 //#define BUFFER_SIZE 3528
15
16 // This is about 50 ms of data for WAVE_FORMAT_PCM:
17 // (44100 samples / sec) * (50 ms / 1000 ms) * (2 bytes / sample) * (1 channel)
18 //#define BUFFER_SIZE 4410
19
20 // This is about 200 ms of data for WAVE_FORMAT_PCM:
21 // (44100 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (1 channel)
22 //#define BUFFER_SIZE 17640
23
24 // This is about 200 ms of data for WAVE_FORMAT_PCM:
25 // (44100 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (2 channel)
26 //#define BUFFER_SIZE 35280
27
28 // This is about 1000 ms of data for WAVE_FORMAT_PCM:
29 // (44100 samples / sec) * (1000 ms / 1000 ms) * (2 bytes / sample) * (1 channel)
30 //#define BUFFER_SIZE 88200
31
32 // This is about 50 ms of data for WAVE_FORMAT_PCM:
33 // (44100 samples / sec) * (50 ms / 1000 ms) * (2 bytes / sample) * (2 channels)
34 //#define BUFFER_SIZE 8820
35
36 // This is about 50 ms of data for WAVE_FORMAT_IEEE_FLOAT:
37 // (44100 samples / sec) * (50 ms / 1000 ms) * (4 bytes / sample) * (2 channels)
38 //#define BUFFER_SIZE 17640
39
40 // This is about 200 ms of data for WAVE_FORMAT_PCM:
41 // (11025 samples / sec) * (200 ms / 1000 ms) * (2 bytes / sample) * (2 channel)
42 #define BUFFER_SIZE 8820
43
44 //#define BUFFER_SIZE 8192
45 static WAVEHDR** buffers = NULL;
46
47 void CALLBACK playbackCallback(HWAVEOUT output,
48                                UINT msg,
49                                DWORD_PTR userData,
50                                DWORD_PTR param1,
51                                DWORD_PTR param2)
52 {
53     if (msg == WOM_DONE) {
54         WAVEHDR* hdr = (WAVEHDR*) param1;
55         hdr->dwFlags |= WHDR_DONE;
56         SetEvent(event);
57     }
58 }
59
60 JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_initializeWaveOut
61   (JNIEnv *env, jclass unused, jlong eventObject)
62 {
63     event = (HANDLE) eventObject;
64
65     // Note the hard requirements on the RawSoundConverter's output format
66     WAVEFORMATEX format;
67     format.wFormatTag = WAVE_FORMAT_PCM;
68     //    format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
69     format.nChannels = 2;
70     //    format.nChannels = 1;
71     //    format.nSamplesPerSec = 44100;
72     format.nSamplesPerSec = 11025;
73     format.wBitsPerSample = 16;
74     //    format.wBitsPerSample = 32;
75     format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
76     format.nAvgBytesPerSec = format.nBlockAlign * format.nSamplesPerSec;
77     format.cbSize = 0;
78     MMRESULT res = waveOutOpen(&output,
79                                WAVE_MAPPER,
80                                &format,
81                                /* NULL, */ (DWORD_PTR) &playbackCallback,
82                                NULL, // No user data right now
83                                /* CALLBACK_NULL */ CALLBACK_FUNCTION);
84     if (res != MMSYSERR_NOERROR) {
85         return JNI_FALSE;
86     }
87
88     buffers = (WAVEHDR**) calloc(NUM_BUFFERS, sizeof(WAVEHDR));
89     for (int i = 0; i < NUM_BUFFERS; i++) {
90         char* data = (char*) calloc(BUFFER_SIZE, 1);
91         WAVEHDR* hdr = (WAVEHDR*) calloc(1, sizeof(WAVEHDR));
92         hdr->lpData = data;
93         hdr->dwBufferLength = BUFFER_SIZE;
94         hdr->dwFlags |= WHDR_DONE;
95         buffers[i] = hdr;
96     }
97
98     return JNI_TRUE;
99 }
100
101 JNIEXPORT void JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_shutdownWaveOut
102   (JNIEnv *env, jclass unused)
103 {
104     //    writeString("Pausing\n");
105     waveOutPause(output);
106     //    writeString("Resetting\n");
107     waveOutReset(output);
108     //    writeString("Closing output\n");
109     waveOutClose(output);
110 }
111
112 JNIEXPORT jlong JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getNextMixerBuffer
113   (JNIEnv *env, jclass unused)
114 {
115     WAVEHDR* hdr = NULL;
116     for (int i = 0; i < NUM_BUFFERS; i++) {
117         if (buffers[i] != NULL && ((buffers[i]->dwFlags & WHDR_DONE) != 0)) {
118             hdr = buffers[i];
119             hdr->dwFlags &= ~WHDR_DONE;
120             break;
121         }
122     }
123     return (jlong) hdr;
124 }
125
126 JNIEXPORT jobject JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getMixerBufferData
127   (JNIEnv *env, jclass unused, jlong mixerBuffer)
128 {
129     WAVEHDR* hdr = (WAVEHDR*) mixerBuffer;
130     return env->NewDirectByteBuffer(hdr->lpData, hdr->dwBufferLength);
131 }
132
133 JNIEXPORT jlong JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getMixerBufferDataAddress
134   (JNIEnv *env, jclass unused, jlong mixerBuffer)
135 {
136     WAVEHDR* hdr = (WAVEHDR*) mixerBuffer;
137     return (jlong) hdr->lpData;
138 }
139
140 JNIEXPORT jint JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_getMixerBufferDataCapacity
141   (JNIEnv *env, jclass unused, jlong mixerBuffer)
142 {
143     WAVEHDR* hdr = (WAVEHDR*) mixerBuffer;
144     return (jint) hdr->dwBufferLength;
145 }
146
147 JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_prepareMixerBuffer
148   (JNIEnv *env, jclass unused, jlong mixerBuffer)
149 {
150     MMRESULT res = waveOutPrepareHeader(output,
151                                         (WAVEHDR*) mixerBuffer,
152                                         sizeof(WAVEHDR));
153     if (res == MMSYSERR_NOERROR) {
154         return JNI_TRUE;
155     }
156     return JNI_FALSE;
157 }
158
159 JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_writeMixerBuffer
160   (JNIEnv *env, jclass unused, jlong mixerBuffer)
161 {
162     MMRESULT res = waveOutWrite(output,
163                                 (WAVEHDR*) mixerBuffer,
164                                 sizeof(WAVEHDR));
165     if (res == MMSYSERR_NOERROR) {
166         waveOutRestart(output);
167
168         return JNI_TRUE;
169     }
170     return JNI_FALSE;
171 }
172
173 JNIEXPORT jlong JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_CreateEvent
174   (JNIEnv *env, jclass unused)
175 {
176     return (jlong) CreateEvent(NULL, FALSE, TRUE, NULL);
177 }
178
179 JNIEXPORT jboolean JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_WaitForSingleObject
180   (JNIEnv *env, jclass unused, jlong eventObject)
181 {
182     DWORD res = WaitForSingleObject((HANDLE) eventObject, INFINITE);
183     if (res == WAIT_OBJECT_0) {
184         return JNI_TRUE;
185     }
186     return JNI_FALSE;
187 }
188
189 JNIEXPORT void JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_SetEvent
190   (JNIEnv *env, jclass unused, jlong eventObject)
191 {
192     SetEvent((HANDLE) eventObject);
193 }
194
195 JNIEXPORT void JNICALL Java_com_jogamp_audio_windows_waveout_Mixer_CloseHandle
196   (JNIEnv *env, jclass unused, jlong eventObject)
197 {
198     CloseHandle((HANDLE) eventObject);
199 }
http://JogAmp.org git info: FAQ, tutorial and man pages.