Home | History | Annotate | Download | only in audio
      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