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