2 Skelton for retropc emulator
4 Author : K.Ohta <whatisthis.sowhat _at_ gmail.com>
11 #include "../fileio.h"
14 #include "agar_logger.h"
21 static int nSndDataLen, nSndDataPos, nSndWritePos;
23 static bool bSoundDebug;
24 static SDL_sem *pSndApplySem;
25 static Sint16 *pSoundBuf;
28 static SDL_AudioDeviceID nAudioDevid;
30 static int nAudioDevid;
32 static SDL_AudioSpec SndSpecReq, SndSpecPresented;
35 void AudioCallbackSDL(void *udata, Uint8 *stream, int len)
42 struct timespec req, remain;
48 sdl_snddata_t *pData = (sdl_snddata_t *)udata;
49 // printf("Called SND: %d %08x len = %d\n", SDL_GetTicks(), pData, len);
50 //if(pData == NULL) return;
53 req.tv_nsec = 500 * 1000; // 0.5ms
57 memset(stream, 0x00, len);
59 SDL_SemWait(*pData->pSndApplySem);
60 if(config.general_sound_level < -32768) config.general_sound_level = -32768;
61 if(config.general_sound_level > 32767) config.general_sound_level = 32767;
62 iTotalVolume = (uint8)(((uint32)(config.general_sound_level + 32768)) >> 9);
64 if(uBufSize <= nSndWritePos) { // Wrap
67 len2 = uBufSize - nSndWritePos;
69 SDL_SemPost(*pData->pSndApplySem);
72 if(len2 >= sndlen) len2 = sndlen; // Okay
73 if((spos + len2) >= (len / sizeof(Sint16))) {
74 len2 = (len / sizeof(Sint16)) - spos;
76 if((nSndWritePos + len2) >= uBufSize ) len2 = uBufSize - nSndWritePos;
78 if((len2 > 0) && (sndlen > 0)){
79 writepos = nSndWritePos;
80 p = (Uint8 *)pSoundBuf;
81 SDL_SemPost(*pData->pSndApplySem);
83 s = &stream[spos * 2];
84 SDL_MixAudio(s, (Uint8 *)p, len2 * 2, iTotalVolume);
85 if(bSoundDebug) AGAR_DebugLog(AGAR_LOG_DEBUG, "SND:Time=%d,Callback,nSndWritePos=%d,spos=%d,len=%d,len2=%d", SDL_GetTicks(),
86 writepos, spos, len, len2);
87 SDL_SemWait(*pData->pSndApplySem);
89 if(nSndDataLen <= 0) nSndDataLen = 0;
91 SDL_SemPost(*pData->pSndApplySem);
94 SDL_SemPost(*pData->pSndApplySem);
95 if(spos >= (len / 2)) return;
96 while(nSndDataLen <= 0) {
97 #if defined(Q_OS_WIN32)
100 nanosleep(&req, &remain); // Wait 500uS
109 void OSD::initialize_sound(int rate, int samples)
115 sound_samples = samples;
116 sound_ok = sound_started = now_mute = now_rec_sound = false;
117 rec_sound_buffer_ptr = 0;
118 sound_ok = sound_started = now_mute = now_rec_sound = false;
126 // initialize direct sound
130 snddata.pSoundBuf = &pSoundBuf;
131 snddata.uBufSize = &uBufSize;
132 snddata.nSndWritePos = &nSndWritePos;
133 snddata.nSndDataLen = &nSndDataLen;
134 snddata.pSndApplySem = &pSndApplySem;
135 snddata.iTotalVolume = &iTotalVolume;
136 snddata.bSndExit = &bSndExit;
137 snddata.bSoundDebug = &bSoundDebug;
139 SndSpecReq.format = AUDIO_S16SYS;
140 SndSpecReq.channels = 2;
141 SndSpecReq.freq = sound_rate;
142 SndSpecReq.samples = ((sound_rate * 20) / 1000);
143 SndSpecReq.callback = AudioCallbackSDL;
144 SndSpecReq.userdata = (void *)&snddata;
145 #if defined(USE_SDL2)
146 for(i = 0; i < SDL_GetNumAudioDevices(0); i++) {
147 devname = SDL_GetAudioDeviceName(i, 0);
148 AGAR_DebugLog(AGAR_LOG_INFO, "Audio Device: %s", devname.c_str());
151 SDL_OpenAudio(&SndSpecReq, &SndSpecPresented);
155 uBufSize = (100 * SndSpecPresented.freq * SndSpecPresented.channels * 2) / 1000;
156 //uBufSize = sound_samples * 2;
157 pSoundBuf = (Sint16 *)malloc(uBufSize * sizeof(Sint16));
158 if(pSoundBuf == NULL) {
159 #if defined(USE_SDL2)
160 SDL_CloseAudioDevice(nAudioDevid);
166 pSndApplySem = SDL_CreateSemaphore(1);
167 if(pSndApplySem == NULL) {
172 AGAR_DebugLog(AGAR_LOG_INFO, "Sound OK: BufSize = %d", uBufSize);
173 ZeroMemory(pSoundBuf, uBufSize * sizeof(Sint16));
174 #if defined(USE_SDL2)
175 SDL_PauseAudioDevice(nAudioDevid, 0);
180 sound_ok = sound_first_half = true;
183 void OSD::release_sound()
187 #if defined(USE_SDL2)
188 SDL_CloseAudioDevice(nAudioDevid);
192 if(pSndApplySem != NULL) {
193 SDL_DestroySemaphore(pSndApplySem);
195 if(pSoundBuf != NULL) free(pSoundBuf);
200 void OSD::update_sound(int* extra_frames)
204 // if(now_debugging) {
210 uint32_t play_c, offset, size1, size2;
214 // check current position
215 play_c = nSndWritePos;
216 if(!sound_first_half) {
217 if(play_c < (uBufSize / 2)) {
222 if(play_c >= (uBufSize / 2)) {
225 offset = uBufSize / 2;
228 // sound buffer must be updated
229 Sint16* sound_buffer = (Sint16 *)vm->create_sound(extra_frames);
232 if(sound_samples > rec_sound_buffer_ptr) {
233 int samples = sound_samples - rec_sound_buffer_ptr;
234 int length = samples * sizeof(uint16) * 2; // stereo
235 rec_sound_fio->Fwrite(sound_buffer + rec_sound_buffer_ptr * 2, length, 1);
236 rec_sound_bytes += length;
238 // sync video recording
239 static double frames = 0;
240 static int prev_samples = -1;
241 #ifdef SUPPORT_VARIABLE_TIMING
242 static double prev_fps = -1;
243 double fps = vm->frame_rate();
244 if(prev_samples != samples || prev_fps != fps) {
245 prev_samples = samples;
247 frames = fps * (double)samples / (double)sound_rate;
250 if(prev_samples != samples) {
251 prev_samples = samples;
252 frames = FRAMES_PER_SEC * (double)samples / (double)sound_rate;
255 rec_video_frames -= frames;
256 if(rec_video_frames > 2) {
257 rec_video_run_frames -= (rec_video_frames - 2);
258 } else if(rec_video_frames < -2) {
259 rec_video_run_frames -= (rec_video_frames + 2);
261 // rec_video_run_frames -= rec_video_frames;
264 rec_sound_buffer_ptr = 0;
271 SDL_SemWait(*snddata.pSndApplySem);
272 ssize = sound_samples * SndSpecPresented.channels;
275 ptr1 = &pSoundBuf[pos];
276 if(pos2 >= uBufSize) {
277 size1 = uBufSize - pos;
278 size2 = pos2 - uBufSize;
279 ptr2 = &pSoundBuf[0];
286 memcpy(ptr1, sound_buffer, size1 * sizeof(Sint16));
289 memcpy(ptr2, sound_buffer + size1, size2 * sizeof(Sint16));
291 nSndDataLen = nSndDataLen + ssize;
292 if(nSndDataLen >= uBufSize) nSndDataLen = uBufSize;
293 nSndDataPos = nSndDataPos + ssize;
294 if(nSndDataPos >= uBufSize) nSndDataPos = nSndDataPos - uBufSize;
295 SDL_SemPost(*snddata.pSndApplySem);
297 // SDL_PauseAudioDevice(nAudioDevid, 0);
300 // SDL_PauseAudioDevice(nAudioDevid, 0);
301 sound_first_half = !sound_first_half;
305 void OSD::mute_sound()
307 if(!now_mute && sound_ok) {
308 // check current position
309 uint32_t size1, size2;
316 SDL_SemWait(*snddata.pSndApplySem);
317 ssize = uBufSize / 2;
320 ptr1 = &pSoundBuf[pos];
321 if(pos2 >= uBufSize) {
322 size1 = uBufSize - pos;
323 size2 = pos2 - uBufSize;
324 ptr2 = &pSoundBuf[0];
332 ZeroMemory(ptr1, size1 * sizeof(Sint16));
335 ZeroMemory(ptr2, size2 * sizeof(Sint16));
337 nSndDataPos = (nSndDataPos + ssize) % uBufSize;
338 SDL_SemPost(*snddata.pSndApplySem);
343 void OSD::stop_sound()
345 if(sound_ok && sound_started) {
346 #if defined(USE_SDL2)
347 SDL_PauseAudioDevice(nAudioDevid, 1);
351 sound_started = false;
355 void OSD::start_rec_sound()
361 QDateTime nowTime = QDateTime::currentDateTime();
362 QString tmps = QString::fromUtf8("Screen_Save_emu");
363 tmps = tmps + QString::fromUtf8(CONFIG_NAME);
364 tmps = tmps + QString::fromUtf8("_");
365 tmps = tmps + nowTime.toString(QString::fromUtf8("yyyy-MM-dd_hh-mm-ss.zzz"));
366 tmps = tmps + QString::fromUtf8(".wav");
367 strncpy(sound_file_name, tmps.toUtf8().constData(), sizeof(sound_file_name));
369 rec_sound_fio = new FILEIO();
370 if(rec_sound_fio->Fopen(bios_path(sound_file_name), FILEIO_WRITE_BINARY)) {
371 // write dummy wave header
373 memset(&header, 0, sizeof(wav_header_t));
374 rec_sound_fio->Fwrite(&header, sizeof(wav_header_t), 1);
376 rec_sound_buffer_ptr = vm->sound_buffer_ptr();
377 now_rec_sound = true;
379 // failed to open the wave file
380 delete rec_sound_fio;
386 void OSD::stop_rec_sound()
390 if(rec_sound_bytes == 0) {
391 rec_sound_fio->Fclose();
392 rec_sound_fio->RemoveFile(sound_file_name);
394 // update wave header
395 wav_header_t wav_header;
397 memcpy(wav_header.riff_chunk.id, "RIFF", 4);
398 wav_header.riff_chunk.size = EndianToLittle_DWORD(rec_sound_bytes + sizeof(wav_header_t) - 8);
399 memcpy(wav_header.wave, "WAVE", 4);
400 memcpy(wav_header.fmt_chunk.id, "fmt ", 4);
401 wav_header.fmt_chunk.size = EndianToLittle_DWORD(16);
402 wav_header.format_id = EndianToLittle_WORD(1);
403 wav_header.channels = EndianToLittle_WORD(2);
404 wav_header.sample_bits = EndianToLittle_WORD(16);
405 wav_header.sample_rate = EndianToLittle_DWORD(sound_rate);
406 wav_header.block_size = EndianToLittle_WORD(wav_header.channels * wav_header.sample_bits / 8);
407 wav_header.data_speed = EndianToLittle_DWORD(wav_header.sample_rate * wav_header.block_size);
409 memcpy(wav_header.fmt_chunk.id, "data", 4);
410 wav_header.fmt_chunk.size = EndianToLittle_DWORD(rec_sound_bytes);
412 rec_sound_fio->Fseek(0, FILEIO_SEEK_SET);
413 rec_sound_fio->Fwrite(&wav_header, sizeof(wav_header_t), 1);
414 rec_sound_fio->Fclose();
416 delete rec_sound_fio;
417 now_rec_sound = false;
422 void OSD::restart_rec_sound()
424 bool tmp = now_rec_sound;