|
|
1.1 root 1: /* 1.1.1.2 ! root 2: * QEMU WAV audio driver ! 3: * ! 4: * Copyright (c) 2004-2005 Vassili Karpov (malc) ! 5: * 1.1 root 6: * Permission is hereby granted, free of charge, to any person obtaining a copy 7: * of this software and associated documentation files (the "Software"), to deal 8: * in the Software without restriction, including without limitation the rights 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10: * copies of the Software, and to permit persons to whom the Software is 11: * furnished to do so, subject to the following conditions: 12: * 13: * The above copyright notice and this permission notice shall be included in 14: * all copies or substantial portions of the Software. 15: * 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22: * THE SOFTWARE. 23: */ 24: #include "vl.h" 25: 1.1.1.2 ! root 26: #define AUDIO_CAP "wav" ! 27: #include "audio_int.h" 1.1 root 28: 1.1.1.2 ! root 29: typedef struct WAVVoiceOut { ! 30: HWVoiceOut hw; 1.1 root 31: QEMUFile *f; 32: int64_t old_ticks; 33: void *pcm_buf; 34: int total_samples; 1.1.1.2 ! root 35: } WAVVoiceOut; 1.1 root 36: 37: static struct { 1.1.1.2 ! root 38: audsettings_t settings; 1.1 root 39: const char *wav_path; 40: } conf = { 1.1.1.2 ! root 41: { ! 42: 44100, ! 43: 2, ! 44: AUD_FMT_S16 ! 45: }, ! 46: "qemu.wav" 1.1 root 47: }; 48: 1.1.1.2 ! root 49: static int wav_run_out (HWVoiceOut *hw) 1.1 root 50: { 1.1.1.2 ! root 51: WAVVoiceOut *wav = (WAVVoiceOut *) hw; 1.1 root 52: int rpos, live, decr, samples; 53: uint8_t *dst; 54: st_sample_t *src; 55: int64_t now = qemu_get_clock (vm_clock); 56: int64_t ticks = now - wav->old_ticks; 1.1.1.2 ! root 57: int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; 1.1 root 58: 1.1.1.2 ! root 59: if (bytes > INT_MAX) { ! 60: samples = INT_MAX >> hw->info.shift; ! 61: } ! 62: else { ! 63: samples = bytes >> hw->info.shift; ! 64: } 1.1 root 65: 1.1.1.2 ! root 66: live = audio_pcm_hw_get_live_out (hw); ! 67: if (!live) { ! 68: return 0; ! 69: } 1.1 root 70: 71: wav->old_ticks = now; 72: decr = audio_MIN (live, samples); 73: samples = decr; 74: rpos = hw->rpos; 75: while (samples) { 76: int left_till_end_samples = hw->samples - rpos; 77: int convert_samples = audio_MIN (samples, left_till_end_samples); 78: 1.1.1.2 ! root 79: src = hw->mix_buf + rpos; ! 80: dst = advance (wav->pcm_buf, rpos << hw->info.shift); 1.1 root 81: 82: hw->clip (dst, src, convert_samples); 1.1.1.2 ! root 83: qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift); ! 84: mixeng_clear (src, convert_samples); 1.1 root 85: 86: rpos = (rpos + convert_samples) % hw->samples; 87: samples -= convert_samples; 88: wav->total_samples += convert_samples; 89: } 90: 91: hw->rpos = rpos; 1.1.1.2 ! root 92: return decr; 1.1 root 93: } 94: 1.1.1.2 ! root 95: static int wav_write_out (SWVoiceOut *sw, void *buf, int len) 1.1 root 96: { 1.1.1.2 ! root 97: return audio_pcm_sw_write (sw, buf, len); 1.1 root 98: } 99: 100: /* VICE code: Store number as little endian. */ 101: static void le_store (uint8_t *buf, uint32_t val, int len) 102: { 103: int i; 104: for (i = 0; i < len; i++) { 105: buf[i] = (uint8_t) (val & 0xff); 106: val >>= 8; 107: } 108: } 109: 1.1.1.2 ! root 110: static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) 1.1 root 111: { 1.1.1.2 ! root 112: WAVVoiceOut *wav = (WAVVoiceOut *) hw; ! 113: int bits16 = 0, stereo = 0; 1.1 root 114: uint8_t hdr[] = { 115: 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 116: 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 117: 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 118: 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 119: }; 1.1.1.2 ! root 120: audsettings_t wav_as = conf.settings; ! 121: ! 122: (void) as; 1.1 root 123: 1.1.1.2 ! root 124: stereo = wav_as.nchannels == 2; ! 125: switch (wav_as.fmt) { 1.1 root 126: case AUD_FMT_S8: 127: case AUD_FMT_U8: 1.1.1.2 ! root 128: bits16 = 0; 1.1 root 129: break; 130: 131: case AUD_FMT_S16: 132: case AUD_FMT_U16: 133: bits16 = 1; 134: break; 135: } 136: 137: hdr[34] = bits16 ? 0x10 : 0x08; 1.1.1.2 ! root 138: ! 139: audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0)); ! 140: ! 141: hw->samples = 1024; ! 142: wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); ! 143: if (!wav->pcm_buf) { ! 144: dolog ("Could not allocate buffer (%d bytes)\n", ! 145: hw->samples << hw->info.shift); 1.1 root 146: return -1; 1.1.1.2 ! root 147: } 1.1 root 148: 1.1.1.2 ! root 149: le_store (hdr + 22, hw->info.nchannels, 2); ! 150: le_store (hdr + 24, hw->info.freq, 4); ! 151: le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); 1.1 root 152: le_store (hdr + 32, 1 << (bits16 + stereo), 2); 153: 154: wav->f = fopen (conf.wav_path, "wb"); 155: if (!wav->f) { 1.1.1.2 ! root 156: dolog ("Failed to open wave file `%s'\nReason: %s\n", 1.1 root 157: conf.wav_path, strerror (errno)); 158: qemu_free (wav->pcm_buf); 159: wav->pcm_buf = NULL; 160: return -1; 161: } 162: 163: qemu_put_buffer (wav->f, hdr, sizeof (hdr)); 164: return 0; 165: } 166: 1.1.1.2 ! root 167: static void wav_fini_out (HWVoiceOut *hw) 1.1 root 168: { 1.1.1.2 ! root 169: WAVVoiceOut *wav = (WAVVoiceOut *) hw; 1.1 root 170: uint8_t rlen[4]; 171: uint8_t dlen[4]; 1.1.1.2 ! root 172: uint32_t datalen = wav->total_samples << hw->info.shift; ! 173: uint32_t rifflen = datalen + 36; 1.1 root 174: 1.1.1.2 ! root 175: if (!wav->f) { 1.1 root 176: return; 1.1.1.2 ! root 177: } 1.1 root 178: 179: le_store (rlen, rifflen, 4); 180: le_store (dlen, datalen, 4); 181: 182: qemu_fseek (wav->f, 4, SEEK_SET); 183: qemu_put_buffer (wav->f, rlen, 4); 184: 185: qemu_fseek (wav->f, 32, SEEK_CUR); 186: qemu_put_buffer (wav->f, dlen, 4); 187: 188: fclose (wav->f); 189: wav->f = NULL; 190: 191: qemu_free (wav->pcm_buf); 192: wav->pcm_buf = NULL; 193: } 194: 1.1.1.2 ! root 195: static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...) 1.1 root 196: { 197: (void) hw; 198: (void) cmd; 199: return 0; 200: } 201: 202: static void *wav_audio_init (void) 203: { 204: return &conf; 205: } 206: 207: static void wav_audio_fini (void *opaque) 208: { 1.1.1.2 ! root 209: (void) opaque; 1.1 root 210: ldebug ("wav_fini"); 211: } 212: 1.1.1.2 ! root 213: struct audio_option wav_options[] = { ! 214: {"FREQUENCY", AUD_OPT_INT, &conf.settings.freq, ! 215: "Frequency", NULL, 0}, ! 216: ! 217: {"FORMAT", AUD_OPT_FMT, &conf.settings.fmt, ! 218: "Format", NULL, 0}, ! 219: ! 220: {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, ! 221: "Number of channels (1 - mono, 2 - stereo)", NULL, 0}, ! 222: ! 223: {"PATH", AUD_OPT_STR, &conf.wav_path, ! 224: "Path to wave file", NULL, 0}, ! 225: {NULL, 0, NULL, NULL, NULL, 0} ! 226: }; ! 227: ! 228: struct audio_pcm_ops wav_pcm_ops = { ! 229: wav_init_out, ! 230: wav_fini_out, ! 231: wav_run_out, ! 232: wav_write_out, ! 233: wav_ctl_out, ! 234: ! 235: NULL, ! 236: NULL, ! 237: NULL, ! 238: NULL, ! 239: NULL 1.1 root 240: }; 241: 1.1.1.2 ! root 242: struct audio_driver wav_audio_driver = { ! 243: INIT_FIELD (name = ) "wav", ! 244: INIT_FIELD (descr = ) ! 245: "WAV renderer http://wikipedia.org/wiki/WAV", ! 246: INIT_FIELD (options = ) wav_options, ! 247: INIT_FIELD (init = ) wav_audio_init, ! 248: INIT_FIELD (fini = ) wav_audio_fini, ! 249: INIT_FIELD (pcm_ops = ) &wav_pcm_ops, ! 250: INIT_FIELD (can_be_default = ) 0, ! 251: INIT_FIELD (max_voices_out = ) 1, ! 252: INIT_FIELD (max_voices_in = ) 0, ! 253: INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut), ! 254: INIT_FIELD (voice_size_in = ) 0 1.1 root 255: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.