1 /* 2 * QEMU WAV audio driver 3 * 4 * Copyright (c) 2007 The Android Open Source Project 5 * Copyright (c) 2004-2005 Vassili Karpov (malc) 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 #include "hw/hw.h" 26 #include "qemu/timer.h" 27 #include "audio.h" 28 29 #define AUDIO_CAP "wav" 30 #include "audio_int.h" 31 32 #define WAV_AUDIO_IN 1 33 34 /** VOICE OUT (Saving to a .WAV file) 35 **/ 36 typedef struct WAVVoiceOut { 37 HWVoiceOut hw; 38 FILE *f; 39 int64_t old_ticks; 40 void *pcm_buf; 41 int total_samples; 42 } WAVVoiceOut; 43 44 static struct { 45 struct audsettings settings; 46 const char *wav_path; 47 } conf_out = { 48 { 49 44100, 50 2, 51 AUD_FMT_S16, 52 0 53 }, 54 "qemu.wav" 55 }; 56 57 static int wav_out_run (HWVoiceOut *hw, int live) 58 { 59 WAVVoiceOut *wav = (WAVVoiceOut *) hw; 60 int rpos, decr, samples; 61 uint8_t *dst; 62 struct st_sample *src; 63 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 64 int64_t ticks = now - wav->old_ticks; 65 int64_t bytes = 66 muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ()); 67 68 if (bytes > INT_MAX) { 69 samples = INT_MAX >> hw->info.shift; 70 } 71 else { 72 samples = bytes >> hw->info.shift; 73 } 74 75 wav->old_ticks = now; 76 decr = audio_MIN (live, samples); 77 samples = decr; 78 rpos = hw->rpos; 79 while (samples) { 80 int left_till_end_samples = hw->samples - rpos; 81 int convert_samples = audio_MIN (samples, left_till_end_samples); 82 83 src = hw->mix_buf + rpos; 84 dst = advance (wav->pcm_buf, rpos << hw->info.shift); 85 86 hw->clip (dst, src, convert_samples); 87 if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) { 88 dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n", 89 convert_samples << hw->info.shift, strerror (errno)); 90 } 91 92 rpos = (rpos + convert_samples) % hw->samples; 93 samples -= convert_samples; 94 wav->total_samples += convert_samples; 95 } 96 97 hw->rpos = rpos; 98 return decr; 99 } 100 101 static int wav_out_write (SWVoiceOut *sw, void *buf, int len) 102 { 103 return audio_pcm_sw_write (sw, buf, len); 104 } 105 106 /* VICE code: Store number as little endian. */ 107 static void le_store (uint8_t *buf, uint32_t val, int len) 108 { 109 int i; 110 for (i = 0; i < len; i++) { 111 buf[i] = (uint8_t) (val & 0xff); 112 val >>= 8; 113 } 114 } 115 116 static int wav_out_init (HWVoiceOut *hw, struct audsettings *as) 117 { 118 WAVVoiceOut *wav = (WAVVoiceOut *) hw; 119 int bits16 = 0, stereo = 0; 120 uint8_t hdr[] = { 121 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 122 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 123 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 124 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 125 }; 126 struct audsettings wav_as = conf_out.settings; 127 128 (void) as; 129 130 stereo = wav_as.nchannels == 2; 131 switch (wav_as.fmt) { 132 case AUD_FMT_S8: 133 case AUD_FMT_U8: 134 bits16 = 0; 135 break; 136 137 case AUD_FMT_S16: 138 case AUD_FMT_U16: 139 bits16 = 1; 140 break; 141 142 case AUD_FMT_S32: 143 case AUD_FMT_U32: 144 dolog ("WAVE files can not handle 32bit formats\n"); 145 return -1; 146 } 147 148 hdr[34] = bits16 ? 0x10 : 0x08; 149 150 wav_as.endianness = 0; 151 audio_pcm_init_info (&hw->info, &wav_as); 152 153 hw->samples = 1024; 154 wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 155 if (!wav->pcm_buf) { 156 dolog ("Could not allocate buffer (%d bytes)\n", 157 hw->samples << hw->info.shift); 158 return -1; 159 } 160 161 le_store (hdr + 22, hw->info.nchannels, 2); 162 le_store (hdr + 24, hw->info.freq, 4); 163 le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); 164 le_store (hdr + 32, 1 << (bits16 + stereo), 2); 165 166 wav->f = fopen (conf_out.wav_path, "wb"); 167 if (!wav->f) { 168 dolog ("Failed to open wave file `%s'\nReason: %s\n", 169 conf_out.wav_path, strerror (errno)); 170 g_free (wav->pcm_buf); 171 wav->pcm_buf = NULL; 172 return -1; 173 } 174 175 if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) { 176 dolog ("wav_init_out: failed to write header\nReason: %s\n", 177 strerror(errno)); 178 return -1; 179 } 180 return 0; 181 } 182 183 static void wav_out_fini (HWVoiceOut *hw) 184 { 185 WAVVoiceOut *wav = (WAVVoiceOut *) hw; 186 uint8_t rlen[4]; 187 uint8_t dlen[4]; 188 uint32_t datalen = wav->total_samples << hw->info.shift; 189 uint32_t rifflen = datalen + 36; 190 191 if (!wav->f) { 192 return; 193 } 194 195 le_store (rlen, rifflen, 4); 196 le_store (dlen, datalen, 4); 197 198 fseek (wav->f, 4, SEEK_SET); 199 fwrite(rlen, 4, 1, wav->f); 200 201 fseek (wav->f, 32, SEEK_CUR); 202 fwrite(dlen, 4, 1, wav->f); 203 204 fclose (wav->f); 205 wav->f = NULL; 206 207 g_free (wav->pcm_buf); 208 wav->pcm_buf = NULL; 209 } 210 211 static int wav_out_ctl (HWVoiceOut *hw, int cmd, ...) 212 { 213 (void) hw; 214 (void) cmd; 215 return 0; 216 } 217 218 219 #if WAV_AUDIO_IN 220 221 /** WAV IN (Reading from a .WAV file) 222 **/ 223 224 static struct { 225 const char *wav_path; 226 } conf_in = { 227 "qemu.wav" 228 }; 229 230 typedef struct WAVVoiceIn { 231 HWVoiceIn hw; 232 FILE* f; 233 int64_t old_ticks; 234 void* pcm_buf; 235 int total_samples; 236 int total_size; 237 } WAVVoiceIn; 238 239 240 static int 241 le_read( const uint8_t* p, int size ) { 242 int shift = 0; 243 int result = 0; 244 for ( ; size > 0; size-- ) { 245 result = result | (p[0] << shift); 246 p += 1; 247 shift += 8; 248 } 249 return result; 250 } 251 252 static int 253 wav_in_init (HWVoiceIn *hw, struct audsettings *as) 254 { 255 WAVVoiceIn* wav = (WAVVoiceIn *) hw; 256 const char* path = conf_in.wav_path; 257 uint8_t hdr[44]; 258 struct audsettings wav_as = *as; 259 int nchannels, freq, format, bits; 260 261 wav->f = fopen (path, "rb"); 262 if (wav->f == NULL) { 263 dolog("Failed to open wave file '%s'\nReason: %s\n", path, 264 strerror(errno)); 265 return -1; 266 } 267 268 if (fread(hdr, sizeof(hdr), 1, wav->f) != 1) { 269 dolog("File '%s' doesn't seem to be a .wav file\n", path); 270 goto Fail; 271 } 272 273 /* check that this is a wave file */ 274 if ( hdr[0] != 'R' || hdr[1] != 'I' || hdr[2] != 'F' || hdr[3] != 'F' || 275 hdr[8] != 'W' || hdr[9] != 'A' || hdr[10]!= 'V' || hdr[11]!= 'E' || 276 hdr[12]!= 'f' || hdr[13]!= 'm' || hdr[14]!= 't' || hdr[15]!= ' ' || 277 hdr[40]!= 'd' || hdr[41]!= 'a' || hdr[42]!= 't' || hdr[43]!= 'a') { 278 dolog("File '%s' is not a valid .wav file\n", path); 279 goto Fail; 280 } 281 282 nchannels = le_read( hdr+22, 2 ); 283 freq = le_read( hdr+24, 4 ); 284 format = le_read( hdr+32, 2 ); 285 bits = le_read( hdr+34, 2 ); 286 287 wav->total_size = le_read( hdr+40, 4 ); 288 289 /* perform some sainty checks */ 290 switch (nchannels) { 291 case 1: 292 case 2: break; 293 default: 294 dolog("unsupported number of channels (%d) in '%s'\n", 295 nchannels, path); 296 goto Fail; 297 } 298 299 switch (format) { 300 case 1: 301 case 2: 302 case 4: break; 303 default: 304 dolog("unsupported bytes per sample (%d) in '%s'\n", 305 format, path); 306 goto Fail; 307 } 308 309 if (format*8/nchannels != bits) { 310 dolog("invalid bits per sample (%d, expected %d) in '%s'\n", 311 bits, format*8/nchannels, path); 312 goto Fail; 313 } 314 315 wav_as.nchannels = nchannels; 316 wav_as.fmt = (bits == 8) ? AUD_FMT_U8 : AUD_FMT_S16; 317 wav_as.freq = freq; 318 wav_as.endianness = 0; /* always little endian */ 319 320 audio_pcm_init_info (&hw->info, &wav_as); 321 322 hw->samples = 1024; 323 wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 324 if (!wav->pcm_buf) { 325 goto Fail; 326 } 327 return 0; 328 329 Fail: 330 fclose (wav->f); 331 wav->f = NULL; 332 return -1; 333 } 334 335 336 static void wav_in_fini (HWVoiceIn *hw) 337 { 338 WAVVoiceIn *wav = (WAVVoiceIn *) hw; 339 340 if (!wav->f) { 341 return; 342 } 343 344 fclose (wav->f); 345 wav->f = NULL; 346 347 g_free (wav->pcm_buf); 348 wav->pcm_buf = NULL; 349 } 350 351 static int wav_in_run (HWVoiceIn *hw) 352 { 353 WAVVoiceIn* wav = (WAVVoiceIn *) hw; 354 int wpos, live, decr, samples; 355 uint8_t* src; 356 struct st_sample* dst; 357 358 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 359 int64_t ticks = now - wav->old_ticks; 360 int64_t bytes = muldiv64(ticks, hw->info.bytes_per_second, get_ticks_per_sec()); 361 362 if (bytes > INT_MAX) { 363 samples = INT_MAX >> hw->info.shift; 364 } 365 else { 366 samples = bytes >> hw->info.shift; 367 } 368 369 live = audio_pcm_hw_get_live_in (hw); 370 if (!live) { 371 return 0; 372 } 373 374 wav->old_ticks = now; 375 376 decr = audio_MIN (live, samples); 377 samples = decr; 378 wpos = hw->wpos; 379 while (samples) { 380 int left_till_end_samples = hw->samples - wpos; 381 int convert_samples = audio_MIN (samples, left_till_end_samples); 382 383 dst = hw->conv_buf + wpos; 384 src = advance (wav->pcm_buf, wpos << hw->info.shift); 385 386 clearerr(wav->f); 387 size_t read_bytes = fread(src, 1, convert_samples << hw->info.shift, wav->f); 388 if (read_bytes == 0 && ferror(wav->f) != EINTR) 389 return 0; 390 391 size_t read_samples = read_bytes >> hw->info.shift; 392 memcpy (dst, src, read_bytes); 393 394 wpos = (wpos + read_samples) % hw->samples; 395 samples -= read_samples; 396 wav->total_samples += read_samples; 397 } 398 399 hw->wpos = wpos; 400 return decr; 401 } 402 403 static int wav_in_read (SWVoiceIn *sw, void *buf, int len) 404 { 405 return audio_pcm_sw_read (sw, buf, len); 406 } 407 408 static int wav_in_ctl (HWVoiceIn *hw, int cmd, ...) 409 { 410 (void) hw; 411 (void) cmd; 412 return 0; 413 } 414 415 #endif /* WAV_AUDIO_IN */ 416 417 /** COMMON CODE 418 **/ 419 static void *wav_audio_init (void) 420 { 421 return &conf_out; 422 } 423 424 static void wav_audio_fini (void *opaque) 425 { 426 (void) opaque; 427 ldebug ("wav_fini"); 428 } 429 430 static struct audio_option wav_options[] = { 431 {"FREQUENCY", AUD_OPT_INT, &conf_out.settings.freq, 432 "Frequency", NULL, 0}, 433 434 {"FORMAT", AUD_OPT_FMT, &conf_out.settings.fmt, 435 "Format", NULL, 0}, 436 437 {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf_out.settings.nchannels, 438 "Number of channels (1 - mono, 2 - stereo)", NULL, 0}, 439 440 {"PATH", AUD_OPT_STR, &conf_out.wav_path, 441 "Path to output .wav file", NULL, 0}, 442 443 #if WAV_AUDIO_IN 444 {"IN_PATH", AUD_OPT_STR, &conf_in.wav_path, 445 "Path to input .wav file", NULL, 0}, 446 #endif 447 {NULL, 0, NULL, NULL, NULL, 0} 448 }; 449 450 struct audio_pcm_ops wav_pcm_ops = { 451 wav_out_init, 452 wav_out_fini, 453 wav_out_run, 454 wav_out_write, 455 wav_out_ctl, 456 457 #if WAV_AUDIO_IN 458 wav_in_init, 459 wav_in_fini, 460 wav_in_run, 461 wav_in_read, 462 wav_in_ctl 463 #else 464 NULL, 465 NULL, 466 NULL, 467 NULL, 468 NULL 469 #endif 470 }; 471 472 struct audio_driver wav_audio_driver = { 473 INIT_FIELD (name = ) "wav", 474 INIT_FIELD (descr = ) 475 "WAV file read/write (www.wikipedia.org/wiki/WAV)", 476 INIT_FIELD (options = ) wav_options, 477 INIT_FIELD (init = ) wav_audio_init, 478 INIT_FIELD (fini = ) wav_audio_fini, 479 INIT_FIELD (pcm_ops = ) &wav_pcm_ops, 480 INIT_FIELD (can_be_default = ) 0, 481 #if WAV_AUDIO_IN 482 INIT_FIELD (max_voices_in = ) 1, 483 INIT_FIELD (max_voices_out = ) 1, 484 INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut), 485 INIT_FIELD (voice_size_in = ) sizeof (WAVVoiceIn) 486 #else 487 INIT_FIELD (max_voices_out = ) 1, 488 INIT_FIELD (max_voices_in = ) 0, 489 INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut), 490 INIT_FIELD (voice_size_in = ) 0 491 #endif 492 }; 493