OSDN Git Service

[General][I18N] Update Japanese translations.
[csp-qt/common_source_project-fm7.git] / source / src / qt / osd_sound.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : K.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2015.11.30-
6
7         [Qt/SDL sound ]
8 */
9
10 #include "../emu.h"
11 #include "../fileio.h"
12
13 #include <SDL.h>
14
15 #include "qt_main.h"
16 //#include "csp_logger.h"
17 #include "gui/menu_flags.h"
18
19 #include <QString>
20 #include <QDateTime>
21 #include <QThread>
22
23 void OSD_BASE::audio_callback(void *udata, Uint8 *stream, int len)
24 {
25         int len2 = len;
26         int spos;
27         Uint8 *p;
28         Uint8 *s;
29         int writepos;
30         int sndlen;
31         
32         sdl_snddata_t *pData = (sdl_snddata_t *)udata;
33         if(pData == NULL) return;
34         
35         if(len <= 0) return;
36         spos = 0;
37         memset(stream, 0x00, len);
38         do {
39                 if(pData->p_config->general_sound_level < -32768) pData->p_config->general_sound_level = -32768;
40                 if(pData->p_config->general_sound_level > 32767)  pData->p_config->general_sound_level = 32767;
41                 *pData->snd_total_volume = (uint8_t)(((uint32_t)(pData->p_config->general_sound_level + 32768)) >> 9);
42                 sndlen = *pData->sound_data_len;
43                 if(*(pData->sound_buffer_size)  <= *(pData->sound_write_pos)) { // Wrap
44                         *(pData->sound_write_pos) = 0;
45                 }
46                 len2 = *(pData->sound_buffer_size) - *(pData->sound_write_pos);
47                 if(*pData->sound_exit) {
48                         return;
49                 }
50                 if(len2 >= sndlen) len2 = sndlen;  // Okay
51                 if((spos + len2) >= (int)(len / sizeof(Sint16))) {
52                         len2 = (len / sizeof(Sint16)) - spos;
53                 }
54                 if((*(pData->sound_write_pos) + len2) >= *(pData->sound_buffer_size) ) len2 = *(pData->sound_buffer_size) - *(pData->sound_write_pos);
55                 
56                 //if(*(pData->sound_debug)) debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_SOUND,
57                 //                                                                                              "Callback,sound_write_pos=%d,spos=%d,len=%d,len2=%d",
58                 //                                                                                              *(pData->sound_write_pos), spos, len, len2);
59                 if((len2 > 0) && (sndlen > 0)){
60                         writepos = *pData->sound_write_pos;
61                         p = (Uint8 *)(*pData->sound_buf_ptr);
62                         p = &p[writepos * 2];
63                         s = &stream[spos * 2];
64                         SDL_MixAudio(s, (Uint8 *)p, len2 * 2, *(pData->snd_total_volume));
65                         *(pData->sound_data_len) -= len2;
66                         if(*(pData->sound_data_len) <= 0) *(pData->sound_data_len) = 0;
67                         *pData->sound_write_pos += len2;
68                 } else {
69                         len2 = 0;
70                         if(spos >= (len / 2)) return;
71                         if(*(pData->sound_data_len) <= 0) return;
72                         //while(*(pData->sound_data_len) <= 0) {
73                         //      QThread::usleep(500);
74                         //      if(*pData->sound_exit) return;
75                         //}
76                 }
77                 spos += len2;
78                 if(*pData->sound_exit) return;
79         } while(spos < len); 
80 }
81
82 void OSD_BASE::initialize_sound(int rate, int samples)
83 {
84         std::string devname;
85         int i;
86
87         sound_rate = rate;
88         sound_samples = samples;
89         rec_sound_buffer_ptr = 0;
90         sound_ok = sound_started = now_mute = now_record_sound = false;
91         sound_write_pos = 0;
92         sound_data_len = 0;
93         sound_buffer_size = 0;
94         sound_data_pos = 0;
95         sound_exit = false;
96         sound_debug = false;
97         //sound_debug = true;
98         sound_buf_ptr = NULL;
99         sound_initialized = false;
100         // initialize direct sound
101
102         snd_total_volume = 127;
103    
104         snddata.sound_buf_ptr = &sound_buf_ptr;
105         snddata.sound_buffer_size = &sound_buffer_size;
106         snddata.sound_write_pos = &sound_write_pos;
107         snddata.sound_data_len = &sound_data_len;
108         snddata.snd_total_volume = &snd_total_volume;
109         snddata.sound_exit = &sound_exit;
110         snddata.sound_debug = &sound_debug;
111         snddata.p_config = p_config;
112         
113         snd_spec_req.format = AUDIO_S16SYS;
114         snd_spec_req.channels = 2;
115         snd_spec_req.freq = sound_rate;
116         //snd_spec_req.samples = ((sound_rate * 100) / 1000);
117         snd_spec_req.samples = samples;
118         snd_spec_req.callback = &(this->audio_callback);
119         snd_spec_req.userdata = (void *)&snddata;
120 #if defined(USE_SDL2)      
121         for(i = 0; i < SDL_GetNumAudioDevices(0); i++) {
122                 //devname = SDL_GetAudioDeviceName(i, 0);
123                 QString tmps = QString::fromUtf8(SDL_GetAudioDeviceName(i, 0));
124                 debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND,
125                                                           "Audio Device: %s", tmps.toLocal8Bit().constData());
126         }
127 #endif   
128         SDL_OpenAudio(&snd_spec_req, &snd_spec_presented);
129         audio_dev_id = 1;
130    
131         // secondary buffer
132         sound_buffer_size = sound_samples * snd_spec_presented.channels * 2;
133         sound_buf_ptr = (Sint16 *)malloc(sound_buffer_size * sizeof(Sint16)); 
134         if(sound_buf_ptr == NULL) {
135 #if defined(USE_SDL2)              
136                 SDL_CloseAudioDevice(audio_dev_id);
137 #else      
138                 SDL_CloseAudio();
139 #endif     
140                 return;
141         }
142
143         debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND,
144                                                   "Sound OK: BufSize = %d", sound_buffer_size);
145         memset(sound_buf_ptr, 0x00, sound_buffer_size * sizeof(Sint16));
146 //#if defined(USE_SDL2)   
147 //      SDL_PauseAudioDevice(audio_dev_id, 0);
148 //#else   
149 //      SDL_PauseAudio(0);
150 //#endif   
151         sound_initialized = true;
152         sound_ok = sound_first_half = true;
153 }
154
155 void OSD_BASE::release_sound()
156 {
157         // release SDL sound
158         sound_exit = true;
159         sound_initialized = false;
160
161 #if defined(USE_SDL2)   
162         //SDL_PauseAudioDevice(audio_dev_id, 1);
163         SDL_CloseAudioDevice(audio_dev_id);
164 #else   
165         //SDL_PauseAudio(1);
166         SDL_CloseAudio();
167 #endif   
168         if(sound_buf_ptr != NULL) free(sound_buf_ptr);
169         sound_buf_ptr = NULL;
170         // stop recording
171         stop_record_sound();
172 }
173
174 void OSD_BASE::update_sound(int* extra_frames)
175 {
176         *extra_frames = 0;
177         
178         now_mute = false;
179         if(sound_ok) {
180                 uint32_t play_c, size1, size2;
181                 //uint32_t offset;
182                 Sint16 *ptr1, *ptr2;
183                 
184                 // start play
185                 // check current position
186                 play_c = sound_write_pos;
187                 if(sound_debug) debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_SOUND,
188                                                                                           "Called time=%d sound_write_pos=%d\n", osd_timer.elapsed(), play_c);
189                 if(!sound_first_half) {
190                         if((int)play_c < (sound_buffer_size / 2)) {
191                                 return;
192                         }
193                         //offset = 0;
194                 } else {
195                         if((int)play_c >= (sound_buffer_size / 2)) {
196                                 return;
197                         }
198                         //offset = sound_buffer_size / 2;
199                 }
200                 //SDL_UnlockAudio();
201                 // sound buffer must be updated
202                 Sint16* sound_buffer = (Sint16 *)this->create_sound(extra_frames);
203                 if(now_record_sound || now_record_video) {
204                         if(sound_samples > rec_sound_buffer_ptr) {
205                                 int samples = sound_samples - rec_sound_buffer_ptr;
206                                 int length = samples * sizeof(int16_t) * 2; // stereo
207                                 rec_sound_bytes += length;
208                                 if(now_record_video) {
209                                         //AGAR_DebugLog(AGAR_LOG_DEBUG, "Push Sound %d bytes\n", length);
210                                         emit sig_enqueue_audio((int16_t *)(&(sound_buffer[rec_sound_buffer_ptr * 2])), length);
211                                 }
212                                 // record sound
213                                 if(now_record_sound) {
214                                         rec_sound_fio->Fwrite(sound_buffer + rec_sound_buffer_ptr * 2, length, 1);
215                                 }
216                                 //if(now_record_video) {
217                                 //      // sync video recording
218                                 //      static double frames = 0;
219                                 //      static int prev_samples = -1;
220                                 //      static double prev_fps = -1;
221                                 //      double fps = this->vm_frame_rate();
222                                 //      frames = fps * (double)samples / (double)sound_rate;
223                                 //}
224                                 //printf("Wrote %d samples ptr=%d\n", samples, rec_sound_buffer_ptr);
225                                 rec_sound_buffer_ptr += samples;
226                                 if(rec_sound_buffer_ptr >= sound_samples) rec_sound_buffer_ptr = 0;
227                         }
228                 }
229                 if(sound_buffer) {
230                         int ssize;
231                         int pos;
232                         int pos2;
233                         if(sound_initialized) {
234                                         ssize = sound_samples * snd_spec_presented.channels;
235
236                                 pos = sound_data_pos;
237                                 pos2 = pos + ssize;
238                                 ptr1 = &sound_buf_ptr[pos];
239                                 if(pos2 >= sound_buffer_size) {
240                                                 size1 = sound_buffer_size  - pos;
241                                                 size2 = pos2 - sound_buffer_size;
242                                                 ptr2 = &sound_buf_ptr[0];
243                                         } else {
244                                                 size1 = ssize;
245                                                 size2 = 0;
246                                                 ptr2 = NULL;
247                                         }
248 #if defined(USE_SDL2)   
249                                         SDL_LockAudioDevice(audio_dev_id);
250 #else
251                                         SDL_LockAudio();
252 #endif
253                                         if(ptr1) {
254                                                 my_memcpy(ptr1, sound_buffer, size1 * sizeof(Sint16));
255                                         }
256                                         if(ptr2) {
257                                                 my_memcpy(ptr2, &sound_buffer[size1], size2 * sizeof(Sint16));
258                                         }
259                                         sound_data_len = sound_data_len + ssize;
260                                         if(sound_data_len >= sound_buffer_size) sound_data_len = sound_buffer_size;
261                                         sound_data_pos = sound_data_pos + ssize;
262                                         if(sound_data_pos >= sound_buffer_size) sound_data_pos = sound_data_pos - sound_buffer_size;
263                                         if(!sound_started) sound_started = true;
264 #if defined(USE_SDL2)   
265                                         SDL_UnlockAudioDevice(audio_dev_id);
266 #else
267                                         SDL_UnlockAudio();
268 #endif
269                                         //SDL_UnlockAudio();
270                                         SDL_PauseAudioDevice(audio_dev_id, 0);
271                         }
272                 }
273            
274 //              SDL_PauseAudioDevice(audio_dev_id, 0);
275                 sound_first_half = !sound_first_half;
276         }
277 }
278
279 void OSD_BASE::mute_sound()
280 {
281         if(!now_mute && sound_ok) {
282                 // check current position
283                 uint32_t size1, size2;
284             
285                 Sint16 *ptr1, *ptr2;
286                 // WIP
287                 int ssize;
288                 int pos;
289                 int pos2;
290 #if defined(USE_SDL2)   
291                 SDL_LockAudioDevice(audio_dev_id);
292 #else
293                 SDL_LockAudio();
294 #endif
295                 ssize = sound_buffer_size / 2;
296                 pos = sound_data_pos;
297                 pos2 = pos + ssize;
298                 ptr1 = &sound_buf_ptr[pos];
299                 if(pos2 >= sound_buffer_size) {
300                         size1 = sound_buffer_size - pos;
301                         size2 = pos2 - sound_buffer_size;
302                         ptr2 = &sound_buf_ptr[0];
303                 } else {
304                         size1 = ssize;
305                         size2 = 0;
306                         ptr2 = NULL;
307                 }
308                 
309                 if(ptr1) {
310                         memset(ptr1, 0x00, size1 * sizeof(Sint16));
311                 }
312                 if(ptr2) {
313                         memset(ptr2, 0x00, size2 * sizeof(Sint16));
314                 }
315                 sound_data_pos = (sound_data_pos + ssize) % sound_buffer_size;
316 #if defined(USE_SDL2)   
317                 SDL_UnlockAudioDevice(audio_dev_id);
318 #else
319                 SDL_UnlockAudio();
320 #endif
321         }
322         now_mute = true;
323 }
324
325 void OSD_BASE::stop_sound()
326 {
327         if(sound_ok && sound_started) {
328                 //sound_exit = true;
329 #if defined(USE_SDL2)   
330                 SDL_PauseAudioDevice(audio_dev_id, 1);
331 #else   
332                 SDL_PauseAudio(1);
333 #endif   
334                 sound_started = false;
335                 //sound_exit = false;
336         }
337 }
338
339 void OSD_BASE::start_record_sound()
340 {
341    
342         if(!now_record_sound) {
343                 //LockVM();
344                 QDateTime nowTime = QDateTime::currentDateTime();
345                 QString tmps = QString::fromUtf8("Sound_Save_emu");
346                 tmps = tmps + get_vm_config_name();
347                 tmps = tmps + QString::fromUtf8("_");
348                 tmps = tmps + nowTime.toString(QString::fromUtf8("yyyy-MM-dd_hh-mm-ss.zzz"));
349                 tmps = tmps + QString::fromUtf8(".wav");
350                 strncpy((char *)sound_file_name, tmps.toLocal8Bit().constData(), sizeof(sound_file_name) - 1);
351                 // create wave file
352                 rec_sound_fio = new FILEIO();
353                 if(rec_sound_fio->Fopen(bios_path(sound_file_name), FILEIO_WRITE_BINARY)) {
354                         // write dummy wave header
355                         write_dummy_wav_header((void *)rec_sound_fio);
356                         
357                         rec_sound_bytes = 0;
358                         rec_sound_buffer_ptr = 0;
359                         now_record_sound = true;
360                 } else {
361                         // failed to open the wave file
362                         delete rec_sound_fio;
363                 }
364                 //UnlockVM();
365         }
366 }
367
368 void OSD_BASE::stop_record_sound()
369 {
370                 if(now_record_sound) {
371                         //LockVM();
372                 if(rec_sound_bytes == 0) {
373                         rec_sound_fio->Fclose();
374                         rec_sound_fio->RemoveFile(sound_file_name);
375                 } else {
376                         // update wave header
377                         wav_header_t wav_header;
378                         wav_chunk_t wav_chunk;
379 #if 0
380                         pair16_t tmpval16;
381                         pair_t tmpval32;
382                         
383                         memcpy(wav_header.riff_chunk.id, "RIFF", 4);
384                         
385                         tmpval32.d = rec_sound_bytes + sizeof(wav_header_t) - 8;
386                         wav_header.riff_chunk.size = tmpval32.get_4bytes_le_to();
387                         
388                         memcpy(wav_header.wave, "WAVE", 4);
389                         memcpy(wav_header.fmt_chunk.id, "fmt ", 4);
390                         
391                         tmpval32.d = 16;
392                         wav_header.fmt_chunk.size = tmpval32.get_4bytes_le_to();
393
394                         tmpval16.w = 1;
395                         wav_header.format_id = tmpval16.get_2bytes_le_to();
396                         
397                         tmpval16.w = 2;
398                         wav_header.channels =  tmpval16.get_2bytes_le_to();
399                         
400                         tmpval16.w = 16;
401                         wav_header.sample_bits = tmpval16.get_2bytes_le_to();
402
403                         tmpval32.d = snd_spec_presented.freq;
404                         wav_header.sample_rate = tmpval32.get_4bytes_le_to();
405
406                         tmpval16.w = wav_header.channels * wav_header.sample_bits / 8;
407                         wav_header.block_size = tmpval16.get_2bytes_le_to();
408
409                         tmpval32.d = wav_header.sample_rate * wav_header.block_size;
410                         wav_header.data_speed = tmpval32.get_4bytes_le_to();
411                         
412                         memcpy(wav_chunk.id, "data", 4);
413
414                         tmpval32.d = rec_sound_bytes;
415                         wav_chunk.size = tmpval32.get_4bytes_le_to();
416 #else
417                         if(!set_wav_header(&wav_header, &wav_chunk, 2, snd_spec_presented.freq, 16,
418                                                          (size_t)(rec_sound_bytes + sizeof(wav_header) + sizeof(wav_chunk)))) {
419                                 delete rec_sound_fio;
420                                 now_record_sound = false;
421                                 return;
422                         }
423 #endif
424                         rec_sound_fio->Fseek(0, FILEIO_SEEK_SET);
425                         rec_sound_fio->Fwrite(&wav_header, sizeof(wav_header_t), 1);
426                         rec_sound_fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
427                         rec_sound_fio->Fclose();
428                 }
429                 delete rec_sound_fio;
430                 now_record_sound = false;
431                 //UnlockVM();
432         }
433 }
434
435 void OSD_BASE::restart_record_sound()
436 {
437         bool tmp = now_record_sound;
438         stop_record_sound();
439         if(tmp) {
440                 start_record_sound();
441         }
442 }
443
444 int OSD_BASE::get_sound_rate()
445 {
446         return snd_spec_presented.freq;
447 }
448
449 void OSD_BASE::load_sound_file(int id, const _TCHAR *name, int16_t **data, int *dst_size)
450 {
451         if(data != NULL) *data = NULL;
452         if(dst_size != NULL) *dst_size = 0;
453 }
454
455 void OSD_BASE::free_sound_file(int id, int16_t **data)
456 {
457 }
458
459 void OSD_BASE::init_sound_files()
460 {
461 }
462
463 void OSD_BASE::release_sound_files()
464 {
465 }