3 * (C) 2014-12-30 K.Ohta <whatisthis.sowhat@gmail.com>
20 DWORD dwSamplesPerSec;
21 DWORD dwAvgBytesPerSec;
30 int nSndDataLen, nSndDataPos, nSndWritePos;
33 SDL_sem *pSndApplySem;
39 void AudioCallbackSDL(void *udata, Uint8 *stream, int len)
46 struct timespec req, remain;
50 sdl_snddata_t *pData = (sdl_snddata_t *)udata;
51 //printf("Called SND: %d %08x len = %d\n", AG_GetTicks(), pData, len);
52 //if(pData == NULL) return;
55 req.tv_nsec = 4000 * 1000; // 0.1ms
59 memset(stream, 0x00, len);
63 if(uBufSize <= nSndWritePos) { // Wrap
66 len2 = uBufSize - nSndWritePos;
70 if(len2 >= nSndDataLen) len2 = nSndDataLen; // Okay
71 if((spos + len2) >= (len / sizeof(Sint16))) {
72 len2 = (len / sizeof(Sint16)) - spos;
74 if((nSndWritePos + len2) >= uBufSize ) len2 = uBufSize - nSndWritePos;
75 //printf("len2 = %d, len = %d, spos = %d\n", len2, len, spos);
76 //SDL_SemWait(*pData->pSndApplySem);
77 if((len2 > 0) && (nSndDataLen > 0)){
78 p = (Uint8 *)pSoundBuf;
79 p = &p[nSndWritePos * 2];
80 s = &stream[spos * 2];
81 SDL_MixAudio(s, (Uint8 *)p, len2 * 2, iTotalVolume);
82 if(bSoundDebug) printf("SND:Time=%d,Callback,nSndWritePos=%d,spos=%d,len=%d,len2=%d\n", SDL_GetTicks(),
83 nSndWritePos, spos, len, len2);
85 if(nSndDataLen <= 0) nSndDataLen = 0;
87 // SDL_SemPost(pSndApplySem);
90 //SDL_SemPost(pSndApplySem);
91 if(spos >= (len / 2)) return;
92 // while(nSndDataLen <= 0) {
93 nanosleep(&req, &remain); // Wait 500uS
104 void EMU::initialize_sound()
106 sound_ok = sound_started = now_mute = now_rec_sound = false;
115 // initialize direct sound
119 snddata.pSoundBuf = &pSoundBuf;
120 snddata.uBufSize = &uBufSize;
121 snddata.nSndWritePos = &nSndWritePos;
122 snddata.nSndDataLen = &nSndDataLen;
123 snddata.pSndApplySem = &pSndApplySem;
124 snddata.iTotalVolume = &iTotalVolume;
125 snddata.bSndExit = &bSndExit;
126 snddata.bSoundDebug = &bSoundDebug;
128 SndSpecReq.format = AUDIO_S16SYS;
129 SndSpecReq.channels = 2;
130 SndSpecReq.freq = sound_rate;
131 SndSpecReq.samples = ((sound_rate * 20) / 1000);
132 SndSpecReq.callback = AudioCallbackSDL;
133 SndSpecReq.userdata = (void *)&snddata;
134 SDL_OpenAudio(&SndSpecReq, &SndSpecPresented);
137 uBufSize = (100 * SndSpecPresented.freq * SndSpecPresented.channels * 2) / 1000;
138 //uBufSize = sound_samples * 2;
139 pSoundBuf = (Sint16 *)malloc(uBufSize * sizeof(Sint16));
140 if(pSoundBuf == NULL) {
144 pSndApplySem = SDL_CreateSemaphore(1);
145 if(pSndApplySem == NULL) {
150 printf("Sound OK: BufSize = %d\n", uBufSize);
151 ZeroMemory(pSoundBuf, uBufSize * sizeof(Sint16));
152 sound_ok = first_half = true;
156 void EMU::release_sound()
158 // release direct sound
161 if(pSndApplySem != NULL) {
162 //SDL_SemWait(pSndApplySem);
163 //SDL_SemPost(pSndApplySem);
164 SDL_DestroySemaphore(pSndApplySem);
166 if(pSoundBuf != NULL) free(pSoundBuf);
171 void EMU::update_sound(int* extra_frames)
175 // if(now_debugging) {
182 DWORD play_c, offset, size1, size2;
186 //if(!sound_started) {
187 // SDL_PauseAudio(0);
188 // sound_started = true;
193 // check current position
194 play_c = nSndWritePos;
195 //printf("play_c = %d\n", play_c);
198 if(play_c < (uBufSize / 2)) {
204 if(play_c >= (uBufSize / 2)) {
208 offset = uBufSize / 2;
213 if(play_c < sound_samples) {
219 if(play_c >= sound_samples) {
223 offset = uBufSize / 2;
228 // sound buffer must be updated
229 Sint16* sound_buffer = (Sint16 *)vm->create_sound(extra_frames);
230 // printf("Snd: made buffer = %08x\n", sound_buffer);
233 if(sound_samples > rec_buffer_ptr) {
234 int samples = sound_samples - rec_buffer_ptr;
235 int length = samples * sizeof(uint16) * 2; // stereo
236 rec->Fwrite(sound_buffer + rec_buffer_ptr * 2, length, 1);
239 // sync video recording
240 static double frames = 0;
241 static int prev_samples = -1;
242 #ifdef SUPPORT_VARIABLE_TIMING
243 static double prev_fps = -1;
244 double fps = vm->frame_rate();
245 if(prev_samples != samples || prev_fps != fps) {
246 prev_samples = samples;
248 frames = fps * (double)samples / (double)sound_rate;
251 if(prev_samples != samples) {
252 prev_samples = samples;
253 frames = FRAMES_PER_SEC * (double)samples / (double)sound_rate;
256 rec_video_frames -= frames;
257 if(rec_video_frames > 2) {
258 rec_video_run_frames -= (rec_video_frames - 2);
259 } else if(rec_video_frames < -2) {
260 rec_video_run_frames -= (rec_video_frames + 2);
262 // rec_video_run_frames -= rec_video_frames;
271 double fps = vm->frame_rate();
274 //SDL_SemWait(pSndApplySem);
275 ssize = sound_samples * SndSpecPresented.channels;
276 //ssize = uBufSize / 2;
280 ptr1 = &pSoundBuf[pos];
281 //if(nSndDataLen < uBufSize) {
282 if(pos2 >= uBufSize) {
283 size1 = uBufSize - pos;
284 size2 = pos2 - uBufSize;
285 ptr2 = &pSoundBuf[0];
292 memcpy(ptr1, sound_buffer, size1 * sizeof(Sint16));
295 memcpy(ptr2, sound_buffer + size1, size2 * sizeof(Sint16));
297 nSndDataLen = nSndDataLen + ssize;
298 if(nSndDataLen >= uBufSize) nSndDataLen = uBufSize;
300 //printf("samples = %d\n", sound_samples);
301 nSndDataPos = nSndDataPos + ssize;
302 if(nSndDataPos >= uBufSize) nSndDataPos = nSndDataPos - uBufSize;
305 //SDL_SemPost(pSndApplySem);
310 first_half = !first_half;
314 void EMU::mute_sound()
316 if(!now_mute && sound_ok) {
317 // check current position
326 //SDL_SemWait(pSndApplySem);
328 // ssize = sound_samples * SndSpecPresented.channels;
329 ssize = uBufSize / 2;
332 ptr1 = &pSoundBuf[pos];
333 if(pos2 >= uBufSize) {
334 size1 = uBufSize - pos;
335 size2 = pos2 - uBufSize;
336 ptr2 = &pSoundBuf[0];
344 ZeroMemory(ptr1, size1 * sizeof(Sint16));
347 ZeroMemory(ptr2, size2 * sizeof(Sint16));
349 nSndDataPos = (nSndDataPos + ssize) % uBufSize;
351 //SDL_SemPost(pSndApplySem);
358 void EMU::start_rec_sound()
365 //GetLocalTime(&sTime);
368 tnow = std::time(NULL);
369 tm = std::localtime(&tnow);
371 //_stprintf(sound_file_name, _T("%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.wav"), sTime.wYear, sTime.wMonth, sTime.wDay, sTime.wHour, sTime.wMinute, sTime.wSecond);
372 sprintf(sound_file_name, _T("%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.wav"), tm->tm_year + 1900, tm->tm_mon + 1,
373 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
377 if(rec->Fopen(bios_path(sound_file_name), FILEIO_WRITE_BINARY)) {
378 // write dummy wave header
380 memset(&header, 0, sizeof(wavheader_t));
381 rec->Fwrite(&header, sizeof(wavheader_t), 1);
383 rec_buffer_ptr = vm->sound_buffer_ptr();
384 now_rec_sound = true;
386 // failed to open the wave file
393 void EMU::stop_rec_sound()
399 rec->Remove(sound_file_name);
401 // update wave header
404 header.dwRIFF = EndianToLittle_DWORD(0x46464952);
405 header.dwFileSize = EndianToLittle_DWORD(rec_bytes + sizeof(wavheader_t) - 8);
406 header.dwWAVE = EndianToLittle_DWORD(0x45564157);
407 header.dwfmt_ = EndianToLittle_DWORD(0x20746d66);
408 header.dwFormatSize = EndianToLittle_DWORD(16);
409 header.wFormatTag = EndianToLittle_WORD(1);
410 header.wChannels = EndianToLittle_WORD(2);
411 header.wBitsPerSample = EndianToLittle_WORD(16);
412 header.dwSamplesPerSec = EndianToLittle_DWORD(sound_rate);
413 header.wBlockAlign = EndianToLittle_WORD(header.wChannels * header.wBitsPerSample / 8);
414 header.dwAvgBytesPerSec = EndianToLittle_DWORD(header.dwSamplesPerSec * header.wBlockAlign);
415 header.dwdata = EndianToLittle_DWORD(0x61746164);
416 header.dwDataLength = EndianToLittle_DWORD(rec_bytes);
417 rec->Fseek(0, FILEIO_SEEK_SET);
418 rec->Fwrite(&header, sizeof(wavheader_t), 1);
422 now_rec_sound = false;
427 void EMU::restart_rec_sound()
429 bool tmp = now_rec_sound;
431 if(tmp) start_rec_sound();