2 Skelton for retropc emulator
4 Author : K.Ohta <whatisthis.sowhat _at_ gmail.com>
11 #include "../fileio.h"
14 #include "agar_logger.h"
20 void OSD::audio_callback(void *udata, Uint8 *stream, int len)
32 sdl_snddata_t *pData = (sdl_snddata_t *)udata;
33 if(pData == NULL) return;
37 memset(stream, 0x00, len);
39 SDL_SemWait(*pData->snd_apply_sem);
40 if(config.general_sound_level < -32768) config.general_sound_level = -32768;
41 if(config.general_sound_level > 32767) config.general_sound_level = 32767;
42 *pData->snd_total_volume = (uint8_t)(((uint32_t)(config.general_sound_level + 32768)) >> 9);
43 sndlen = *pData->sound_data_len;
44 if(*(pData->sound_buffer_size) <= *(pData->sound_write_pos)) { // Wrap
45 *(pData->sound_write_pos) = 0;
47 len2 = *(pData->sound_buffer_size) - *(pData->sound_write_pos);
48 if(*pData->sound_exit) {
49 SDL_SemPost(*pData->snd_apply_sem);
52 if(len2 >= sndlen) len2 = sndlen; // Okay
53 if((spos + len2) >= (len / sizeof(Sint16))) {
54 len2 = (len / sizeof(Sint16)) - spos;
56 if((*(pData->sound_write_pos) + len2) >= *(pData->sound_buffer_size) ) len2 = *(pData->sound_buffer_size) - *(pData->sound_write_pos);
58 if(*(pData->sound_debug)) AGAR_DebugLog(AGAR_LOG_DEBUG, "SND:Callback,sound_write_pos=%d,spos=%d,len=%d,len2=%d",
59 *(pData->sound_write_pos), spos, len, len2);
60 if((len2 > 0) && (sndlen > 0)){
61 writepos = *pData->sound_write_pos;
62 p = (Uint8 *)(*pData->sound_buf_ptr);
63 SDL_SemPost(*pData->snd_apply_sem);
65 s = &stream[spos * 2];
66 SDL_MixAudio(s, (Uint8 *)p, len2 * 2, *(pData->snd_total_volume));
67 SDL_SemWait(*pData->snd_apply_sem);
68 *(pData->sound_data_len) -= len2;
69 if(*(pData->sound_data_len) <= 0) *(pData->sound_data_len) = 0;
70 *pData->sound_write_pos += len2;
71 SDL_SemPost(*pData->snd_apply_sem);
74 SDL_SemPost(*pData->snd_apply_sem);
75 if(spos >= (len / 2)) return;
76 while(*(pData->sound_data_len) <= 0) {
78 if(*pData->sound_exit) return;
85 void OSD::initialize_sound(int rate, int samples)
91 sound_samples = samples;
92 sound_ok = sound_started = now_mute = now_record_sound = false;
93 rec_sound_buffer_ptr = 0;
94 sound_ok = sound_started = now_mute = now_record_sound = false;
97 sound_buffer_size = 0;
101 //sound_debug = true;
102 sound_buf_ptr = NULL;
103 snd_apply_sem = NULL;
104 // initialize direct sound
106 snd_total_volume = 127;
108 snddata.sound_buf_ptr = &sound_buf_ptr;
109 snddata.sound_buffer_size = &sound_buffer_size;
110 snddata.sound_write_pos = &sound_write_pos;
111 snddata.sound_data_len = &sound_data_len;
112 snddata.snd_apply_sem = &snd_apply_sem;
113 snddata.snd_total_volume = &snd_total_volume;
114 snddata.sound_exit = &sound_exit;
115 snddata.sound_debug = &sound_debug;
117 snd_spec_req.format = AUDIO_S16SYS;
118 snd_spec_req.channels = 2;
119 snd_spec_req.freq = sound_rate;
120 //snd_spec_req.samples = ((sound_rate * 100) / 1000);
121 snd_spec_req.samples = samples;
122 snd_spec_req.callback = &(this->audio_callback);
123 snd_spec_req.userdata = (void *)&snddata;
124 #if defined(USE_SDL2)
125 for(i = 0; i < SDL_GetNumAudioDevices(0); i++) {
126 devname = SDL_GetAudioDeviceName(i, 0);
127 AGAR_DebugLog(AGAR_LOG_INFO, "Audio Device: %s", devname.c_str());
130 SDL_OpenAudio(&snd_spec_req, &snd_spec_presented);
134 sound_buffer_size = sound_samples * snd_spec_presented.channels * 2;
135 sound_buf_ptr = (Sint16 *)malloc(sound_buffer_size * sizeof(Sint16));
136 if(sound_buf_ptr == NULL) {
137 #if defined(USE_SDL2)
138 SDL_CloseAudioDevice(audio_dev_id);
144 snd_apply_sem = SDL_CreateSemaphore(1);
145 if(snd_apply_sem == NULL) {
147 sound_buf_ptr = NULL;
150 AGAR_DebugLog(AGAR_LOG_INFO, "Sound OK: BufSize = %d", sound_buffer_size);
151 memset(sound_buf_ptr, 0x00, sound_buffer_size * sizeof(Sint16));
152 #if defined(USE_SDL2)
153 SDL_PauseAudioDevice(audio_dev_id, 0);
158 sound_ok = sound_first_half = true;
161 void OSD::release_sound()
165 #if defined(USE_SDL2)
166 SDL_CloseAudioDevice(audio_dev_id);
170 if(snd_apply_sem != NULL) {
171 SDL_DestroySemaphore(snd_apply_sem);
173 if(sound_buf_ptr != NULL) free(sound_buf_ptr);
178 void OSD::update_sound(int* extra_frames)
182 // if(now_debugging) {
188 uint32_t play_c, offset, size1, size2;
192 // check current position
193 play_c = sound_write_pos;
194 if(sound_debug) AGAR_DebugLog(AGAR_LOG_DEBUG, "SND: Called time=%d sound_write_pos=%d\n", osd_timer.elapsed(), play_c);
195 if(!sound_first_half) {
196 if(play_c < (sound_buffer_size / 2)) {
201 if(play_c >= (sound_buffer_size / 2)) {
204 offset = sound_buffer_size / 2;
207 // sound buffer must be updated
208 Sint16* sound_buffer = (Sint16 *)vm->create_sound(extra_frames);
209 if(now_record_sound) {
211 if(sound_samples > rec_sound_buffer_ptr) {
212 int samples = sound_samples - rec_sound_buffer_ptr;
213 int length = samples * sizeof(int16_t) * 2; // stereo
214 rec_sound_fio->Fwrite(sound_buffer + rec_sound_buffer_ptr * 2, length, 1);
215 rec_sound_bytes += length;
216 if(now_record_video) {
217 // sync video recording
218 static double frames = 0;
219 static int prev_samples = -1;
220 #ifdef SUPPORT_VARIABLE_TIMING
221 static double prev_fps = -1;
222 double fps = vm->get_frame_rate();
223 if(prev_samples != samples || prev_fps != fps) {
224 prev_samples = samples;
226 frames = fps * (double)samples / (double)sound_rate;
229 if(prev_samples != samples) {
230 prev_samples = samples;
231 frames = FRAMES_PER_SEC * (double)samples / (double)sound_rate;
234 rec_video_frames -= frames;
235 if(rec_video_frames > 2) {
236 rec_video_run_frames -= (rec_video_frames - 2);
237 } else if(rec_video_frames < -2) {
238 rec_video_run_frames -= (rec_video_frames + 2);
240 // rec_video_run_frames -= rec_video_frames;
242 // printf("Wrote %d samples\n", samples);
243 rec_sound_buffer_ptr += samples;
244 if(rec_sound_buffer_ptr >= sound_samples) rec_sound_buffer_ptr = 0;
253 if(sound_debug) AGAR_DebugLog(AGAR_LOG_DEBUG, "SND:Pushed time=%d samples=%d\n",
254 osd_timer.elapsed(), sound_samples);
255 //SDL_PauseAudioDevice(audio_dev_id, 1);
257 SDL_SemWait(*snddata.snd_apply_sem);
258 ssize = sound_samples * snd_spec_presented.channels;
259 //ssize = sound_buffer_size / 2;
260 pos = sound_data_pos;
262 ptr1 = &sound_buf_ptr[pos];
263 if(pos2 >= sound_buffer_size) {
264 size1 = sound_buffer_size - pos;
265 size2 = pos2 - sound_buffer_size;
266 ptr2 = &sound_buf_ptr[0];
273 memcpy(ptr1, sound_buffer, size1 * sizeof(Sint16));
276 memcpy(ptr2, &sound_buffer[size1], size2 * sizeof(Sint16));
278 sound_data_len = sound_data_len + ssize;
279 if(sound_data_len >= sound_buffer_size) sound_data_len = sound_buffer_size;
280 sound_data_pos = sound_data_pos + ssize;
281 if(sound_data_pos >= sound_buffer_size) sound_data_pos = sound_data_pos - sound_buffer_size;
282 SDL_SemPost(*snddata.snd_apply_sem);
284 //SDL_PauseAudioDevice(audio_dev_id, 0);
288 // SDL_PauseAudioDevice(audio_dev_id, 0);
289 sound_first_half = !sound_first_half;
293 void OSD::mute_sound()
295 if(!now_mute && sound_ok) {
296 // check current position
297 uint32_t size1, size2;
304 SDL_SemWait(*snddata.snd_apply_sem);
305 ssize = sound_buffer_size / 2;
306 pos = sound_data_pos;
308 ptr1 = &sound_buf_ptr[pos];
309 if(pos2 >= sound_buffer_size) {
310 size1 = sound_buffer_size - pos;
311 size2 = pos2 - sound_buffer_size;
312 ptr2 = &sound_buf_ptr[0];
320 memset(ptr1, 0x00, size1 * sizeof(Sint16));
323 memset(ptr2, 0x00, size2 * sizeof(Sint16));
325 sound_data_pos = (sound_data_pos + ssize) % sound_buffer_size;
326 SDL_SemPost(*snddata.snd_apply_sem);
331 void OSD::stop_sound()
333 if(sound_ok && sound_started) {
334 #if defined(USE_SDL2)
335 SDL_PauseAudioDevice(audio_dev_id, 1);
339 sound_started = false;
343 void OSD::start_record_sound()
346 if(!now_record_sound) {
348 QDateTime nowTime = QDateTime::currentDateTime();
349 QString tmps = QString::fromUtf8("Sound_Save_emu");
350 tmps = tmps + QString::fromUtf8(CONFIG_NAME);
351 tmps = tmps + QString::fromUtf8("_");
352 tmps = tmps + nowTime.toString(QString::fromUtf8("yyyy-MM-dd_hh-mm-ss.zzz"));
353 tmps = tmps + QString::fromUtf8(".wav");
354 strncpy(sound_file_name, tmps.toUtf8().constData(), sizeof(sound_file_name));
356 rec_sound_fio = new FILEIO();
357 if(rec_sound_fio->Fopen(bios_path(sound_file_name), FILEIO_WRITE_BINARY)) {
358 // write dummy wave header
359 wav_header_t wav_header;
360 wav_chunk_t wav_chunk;
361 memset(&wav_header, 0, sizeof(wav_header));
362 memset(&wav_chunk, 0, sizeof(wav_chunk));
363 rec_sound_fio->Fwrite(&wav_header, sizeof(wav_header), 1);
364 rec_sound_fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
367 rec_sound_buffer_ptr = 0;
368 now_record_sound = true;
370 // failed to open the wave file
371 delete rec_sound_fio;
377 void OSD::stop_record_sound()
379 if(now_record_sound) {
381 if(rec_sound_bytes == 0) {
382 rec_sound_fio->Fclose();
383 rec_sound_fio->RemoveFile(sound_file_name);
385 // update wave header
386 wav_header_t wav_header;
387 wav_chunk_t wav_chunk;
389 memcpy(wav_header.riff_chunk.id, "RIFF", 4);
390 wav_header.riff_chunk.size = EndianToLittle_DWORD(rec_sound_bytes + sizeof(wav_header_t) - 8);
391 memcpy(wav_header.wave, "WAVE", 4);
392 memcpy(wav_header.fmt_chunk.id, "fmt ", 4);
393 wav_header.fmt_chunk.size = EndianToLittle_DWORD(16);
394 wav_header.format_id = EndianToLittle_WORD(1);
395 wav_header.channels = EndianToLittle_WORD(2);
396 wav_header.sample_bits = EndianToLittle_WORD(16);
397 wav_header.sample_rate = EndianToLittle_DWORD(sound_rate);
398 wav_header.block_size = EndianToLittle_WORD(wav_header.channels * wav_header.sample_bits / 8);
399 wav_header.data_speed = EndianToLittle_DWORD(wav_header.sample_rate * wav_header.block_size);
401 memcpy(wav_chunk.id, "data", 4);
402 wav_chunk.size = EndianToLittle_DWORD(rec_sound_bytes);
404 rec_sound_fio->Fseek(0, FILEIO_SEEK_SET);
405 rec_sound_fio->Fwrite(&wav_header, sizeof(wav_header_t), 1);
406 rec_sound_fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
407 rec_sound_fio->Fclose();
409 delete rec_sound_fio;
410 now_record_sound = false;
415 void OSD::restart_record_sound()
417 bool tmp = now_record_sound;
420 start_record_sound();