|
|
1.1 ! root 1: /* ! 2: * QEMU WAV audio output driver ! 3: * ! 4: * Copyright (c) 2004 Vassili Karpov (malc) ! 5: * ! 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: ! 26: #include "audio/audio_int.h" ! 27: ! 28: typedef struct WAVVoice { ! 29: HWVoice hw; ! 30: QEMUFile *f; ! 31: int64_t old_ticks; ! 32: void *pcm_buf; ! 33: int total_samples; ! 34: } WAVVoice; ! 35: ! 36: #define dolog(...) AUD_log ("wav", __VA_ARGS__) ! 37: #ifdef DEBUG ! 38: #define ldebug(...) dolog (__VA_ARGS__) ! 39: #else ! 40: #define ldebug(...) ! 41: #endif ! 42: ! 43: static struct { ! 44: const char *wav_path; ! 45: } conf = { ! 46: .wav_path = "qemu.wav" ! 47: }; ! 48: ! 49: static void wav_hw_run (HWVoice *hw) ! 50: { ! 51: WAVVoice *wav = (WAVVoice *) hw; ! 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; ! 57: int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; ! 58: ! 59: if (bytes > INT_MAX) ! 60: samples = INT_MAX >> hw->shift; ! 61: else ! 62: samples = bytes >> hw->shift; ! 63: ! 64: live = pcm_hw_get_live (hw); ! 65: if (live <= 0) ! 66: return; ! 67: ! 68: wav->old_ticks = now; ! 69: decr = audio_MIN (live, samples); ! 70: samples = decr; ! 71: rpos = hw->rpos; ! 72: while (samples) { ! 73: int left_till_end_samples = hw->samples - rpos; ! 74: int convert_samples = audio_MIN (samples, left_till_end_samples); ! 75: ! 76: src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); ! 77: dst = advance (wav->pcm_buf, rpos << hw->shift); ! 78: ! 79: hw->clip (dst, src, convert_samples); ! 80: qemu_put_buffer (wav->f, dst, convert_samples << hw->shift); ! 81: memset (src, 0, convert_samples * sizeof (st_sample_t)); ! 82: ! 83: rpos = (rpos + convert_samples) % hw->samples; ! 84: samples -= convert_samples; ! 85: wav->total_samples += convert_samples; ! 86: } ! 87: ! 88: pcm_hw_dec_live (hw, decr); ! 89: hw->rpos = rpos; ! 90: } ! 91: ! 92: static int wav_hw_write (SWVoice *sw, void *buf, int len) ! 93: { ! 94: return pcm_hw_write (sw, buf, len); ! 95: } ! 96: ! 97: /* VICE code: Store number as little endian. */ ! 98: static void le_store (uint8_t *buf, uint32_t val, int len) ! 99: { ! 100: int i; ! 101: for (i = 0; i < len; i++) { ! 102: buf[i] = (uint8_t) (val & 0xff); ! 103: val >>= 8; ! 104: } ! 105: } ! 106: ! 107: static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) ! 108: { ! 109: WAVVoice *wav = (WAVVoice *) hw; ! 110: int bits16 = 0, stereo = audio_state.fixed_channels == 2; ! 111: uint8_t hdr[] = { ! 112: 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, ! 113: 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, ! 114: 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, ! 115: 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 ! 116: }; ! 117: ! 118: switch (audio_state.fixed_fmt) { ! 119: case AUD_FMT_S8: ! 120: case AUD_FMT_U8: ! 121: break; ! 122: ! 123: case AUD_FMT_S16: ! 124: case AUD_FMT_U16: ! 125: bits16 = 1; ! 126: break; ! 127: } ! 128: ! 129: hdr[34] = bits16 ? 0x10 : 0x08; ! 130: hw->freq = 44100; ! 131: hw->nchannels = stereo ? 2 : 1; ! 132: hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; ! 133: hw->bufsize = 4096; ! 134: wav->pcm_buf = qemu_mallocz (hw->bufsize); ! 135: if (!wav->pcm_buf) ! 136: return -1; ! 137: ! 138: le_store (hdr + 22, hw->nchannels, 2); ! 139: le_store (hdr + 24, hw->freq, 4); ! 140: le_store (hdr + 28, hw->freq << (bits16 + stereo), 4); ! 141: le_store (hdr + 32, 1 << (bits16 + stereo), 2); ! 142: ! 143: wav->f = fopen (conf.wav_path, "wb"); ! 144: if (!wav->f) { ! 145: dolog ("failed to open wave file `%s'\nReason: %s\n", ! 146: conf.wav_path, strerror (errno)); ! 147: qemu_free (wav->pcm_buf); ! 148: wav->pcm_buf = NULL; ! 149: return -1; ! 150: } ! 151: ! 152: qemu_put_buffer (wav->f, hdr, sizeof (hdr)); ! 153: return 0; ! 154: } ! 155: ! 156: static void wav_hw_fini (HWVoice *hw) ! 157: { ! 158: WAVVoice *wav = (WAVVoice *) hw; ! 159: int stereo = hw->nchannels == 2; ! 160: uint8_t rlen[4]; ! 161: uint8_t dlen[4]; ! 162: uint32_t rifflen = (wav->total_samples << stereo) + 36; ! 163: uint32_t datalen = wav->total_samples << stereo; ! 164: ! 165: if (!wav->f || !hw->active) ! 166: return; ! 167: ! 168: le_store (rlen, rifflen, 4); ! 169: le_store (dlen, datalen, 4); ! 170: ! 171: qemu_fseek (wav->f, 4, SEEK_SET); ! 172: qemu_put_buffer (wav->f, rlen, 4); ! 173: ! 174: qemu_fseek (wav->f, 32, SEEK_CUR); ! 175: qemu_put_buffer (wav->f, dlen, 4); ! 176: ! 177: fclose (wav->f); ! 178: wav->f = NULL; ! 179: ! 180: qemu_free (wav->pcm_buf); ! 181: wav->pcm_buf = NULL; ! 182: } ! 183: ! 184: static int wav_hw_ctl (HWVoice *hw, int cmd, ...) ! 185: { ! 186: (void) hw; ! 187: (void) cmd; ! 188: return 0; ! 189: } ! 190: ! 191: static void *wav_audio_init (void) ! 192: { ! 193: return &conf; ! 194: } ! 195: ! 196: static void wav_audio_fini (void *opaque) ! 197: { ! 198: ldebug ("wav_fini"); ! 199: } ! 200: ! 201: struct pcm_ops wav_pcm_ops = { ! 202: wav_hw_init, ! 203: wav_hw_fini, ! 204: wav_hw_run, ! 205: wav_hw_write, ! 206: wav_hw_ctl ! 207: }; ! 208: ! 209: struct audio_output_driver wav_output_driver = { ! 210: "wav", ! 211: wav_audio_init, ! 212: wav_audio_fini, ! 213: &wav_pcm_ops, ! 214: 1, ! 215: 1, ! 216: sizeof (WAVVoice) ! 217: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.