/[qemu]/qemu/audio/wavaudio.c
ViewVC logotype

Diff of /qemu/audio/wavaudio.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.3 by bellard, Thu Nov 11 16:55:09 2004 UTC revision 1.4 by bellard, Sun Oct 30 18:58:22 2005 UTC
# Line 1  Line 1 
1  /*  /*
2   * QEMU WAV audio output driver   * QEMU WAV audio driver
3   *   *
4   * Copyright (c) 2004 Vassili Karpov (malc)   * Copyright (c) 2004-2005 Vassili Karpov (malc)
5   *   *
6   * Permission is hereby granted, free of charge, to any person obtaining a copy   * 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   * of this software and associated documentation files (the "Software"), to deal
8   * in the Software without restriction, including without limitation the rights   * in the Software without restriction, including without limitation the rights
# Line 23  Line 23 
23   */   */
24  #include "vl.h"  #include "vl.h"
25    
26  #include "audio/audio_int.h"  #define AUDIO_CAP "wav"
27    #include "audio_int.h"
28    
29  typedef struct WAVVoice {  typedef struct WAVVoiceOut {
30      HWVoice hw;      HWVoiceOut hw;
31      QEMUFile *f;      QEMUFile *f;
32      int64_t old_ticks;      int64_t old_ticks;
33      void *pcm_buf;      void *pcm_buf;
34      int total_samples;      int total_samples;
35  } WAVVoice;  } WAVVoiceOut;
   
 #define dolog(...) AUD_log ("wav", __VA_ARGS__)  
 #ifdef DEBUG  
 #define ldebug(...) dolog (__VA_ARGS__)  
 #else  
 #define ldebug(...)  
 #endif  
36    
37  static struct {  static struct {
38      const char *wav_path;      const char *wav_path;
# Line 46  static struct { Line 40  static struct {
40      .wav_path = "qemu.wav"      .wav_path = "qemu.wav"
41  };  };
42    
43  static void wav_hw_run (HWVoice *hw)  static int wav_run_out (HWVoiceOut *hw)
44  {  {
45      WAVVoice *wav = (WAVVoice *) hw;      WAVVoiceOut *wav = (WAVVoiceOut *) hw;
46      int rpos, live, decr, samples;      int rpos, live, decr, samples;
47      uint8_t *dst;      uint8_t *dst;
48      st_sample_t *src;      st_sample_t *src;
49      int64_t now = qemu_get_clock (vm_clock);      int64_t now = qemu_get_clock (vm_clock);
50      int64_t ticks = now - wav->old_ticks;      int64_t ticks = now - wav->old_ticks;
51      int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;      int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
52    
53      if (bytes > INT_MAX)      if (bytes > INT_MAX) {
54          samples = INT_MAX >> hw->shift;          samples = INT_MAX >> hw->info.shift;
55      else      }
56          samples = bytes >> hw->shift;      else {
57            samples = bytes >> hw->info.shift;
58        }
59    
60      live = pcm_hw_get_live (hw);      live = audio_pcm_hw_get_live_out (hw);
61      if (live <= 0)      if (!live) {
62          return;          return 0;
63        }
64    
65      wav->old_ticks = now;      wav->old_ticks = now;
66      decr = audio_MIN (live, samples);      decr = audio_MIN (live, samples);
# Line 73  static void wav_hw_run (HWVoice *hw) Line 70  static void wav_hw_run (HWVoice *hw)
70          int left_till_end_samples = hw->samples - rpos;          int left_till_end_samples = hw->samples - rpos;
71          int convert_samples = audio_MIN (samples, left_till_end_samples);          int convert_samples = audio_MIN (samples, left_till_end_samples);
72    
73          src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));          src = hw->mix_buf + rpos;
74          dst = advance (wav->pcm_buf, rpos << hw->shift);          dst = advance (wav->pcm_buf, rpos << hw->info.shift);
75    
76          hw->clip (dst, src, convert_samples);          hw->clip (dst, src, convert_samples);
77          qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);          qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
78          memset (src, 0, convert_samples * sizeof (st_sample_t));          mixeng_clear (src, convert_samples);
79    
80          rpos = (rpos + convert_samples) % hw->samples;          rpos = (rpos + convert_samples) % hw->samples;
81          samples -= convert_samples;          samples -= convert_samples;
82          wav->total_samples += convert_samples;          wav->total_samples += convert_samples;
83      }      }
84    
     pcm_hw_dec_live (hw, decr);  
85      hw->rpos = rpos;      hw->rpos = rpos;
86        return decr;
87  }  }
88    
89  static int wav_hw_write (SWVoice *sw, void *buf, int len)  static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
90  {  {
91      return pcm_hw_write (sw, buf, len);      return audio_pcm_sw_write (sw, buf, len);
92  }  }
93    
94  /* VICE code: Store number as little endian. */  /* VICE code: Store number as little endian. */
# Line 104  static void le_store (uint8_t *buf, uint Line 101  static void le_store (uint8_t *buf, uint
101      }      }
102  }  }
103    
104  static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)  static int wav_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt)
105  {  {
106      WAVVoice *wav = (WAVVoice *) hw;      WAVVoiceOut *wav = (WAVVoiceOut *) hw;
107      int bits16 = 0, stereo = audio_state.fixed_channels == 2;      int bits16;
108      uint8_t hdr[] = {      uint8_t hdr[] = {
109          0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,          0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
110          0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,          0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
# Line 115  static int wav_hw_init (HWVoice *hw, int Line 112  static int wav_hw_init (HWVoice *hw, int
112          0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00          0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
113      };      };
114    
115      switch (audio_state.fixed_fmt) {      freq = audio_state.fixed_freq_out;
116        fmt = audio_state.fixed_fmt_out;
117        nchannels = audio_state.fixed_channels_out;
118    
119        switch (fmt) {
120      case AUD_FMT_S8:      case AUD_FMT_S8:
121      case AUD_FMT_U8:      case AUD_FMT_U8:
122            bits16 = 0;
123          break;          break;
124    
125      case AUD_FMT_S16:      case AUD_FMT_S16:
126      case AUD_FMT_U16:      case AUD_FMT_U16:
127          bits16 = 1;          bits16 = 1;
128          break;          break;
129    
130        default:
131            dolog ("Internal logic error bad format %d\n", fmt);
132            return -1;
133      }      }
134    
135      hdr[34] = bits16 ? 0x10 : 0x08;      hdr[34] = bits16 ? 0x10 : 0x08;
136      hw->freq = 44100;      audio_pcm_init_info (
137      hw->nchannels = stereo ? 2 : 1;          &hw->info,
138      hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;          freq,
139            nchannels,
140            bits16 ? AUD_FMT_S16 : AUD_FMT_U8,
141            audio_need_to_swap_endian (0)
142            );
143      hw->bufsize = 4096;      hw->bufsize = 4096;
144      wav->pcm_buf = qemu_mallocz (hw->bufsize);      wav->pcm_buf = qemu_mallocz (hw->bufsize);
145      if (!wav->pcm_buf)      if (!wav->pcm_buf) {
146            dolog ("Can not initialize WAV buffer of %d bytes\n",
147                   hw->bufsize);
148          return -1;          return -1;
149        }
150    
151      le_store (hdr + 22, hw->nchannels, 2);      le_store (hdr + 22, hw->info.nchannels, 2);
152      le_store (hdr + 24, hw->freq, 4);      le_store (hdr + 24, hw->info.freq, 4);
153      le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);      le_store (hdr + 28, hw->info.freq << (bits16 + (nchannels == 2)), 4);
154      le_store (hdr + 32, 1 << (bits16 + stereo), 2);      le_store (hdr + 32, 1 << (bits16 + (nchannels == 2)), 2);
155    
156      wav->f = fopen (conf.wav_path, "wb");      wav->f = fopen (conf.wav_path, "wb");
157      if (!wav->f) {      if (!wav->f) {
158          dolog ("failed to open wave file `%s'\nReason: %s\n",          dolog ("Failed to open wave file `%s'\nReason: %s\n",
159                 conf.wav_path, strerror (errno));                 conf.wav_path, strerror (errno));
160          qemu_free (wav->pcm_buf);          qemu_free (wav->pcm_buf);
161          wav->pcm_buf = NULL;          wav->pcm_buf = NULL;
# Line 153  static int wav_hw_init (HWVoice *hw, int Line 166  static int wav_hw_init (HWVoice *hw, int
166      return 0;      return 0;
167  }  }
168    
169  static void wav_hw_fini (HWVoice *hw)  static void wav_fini_out (HWVoiceOut *hw)
170  {  {
171      WAVVoice *wav = (WAVVoice *) hw;      WAVVoiceOut *wav = (WAVVoiceOut *) hw;
172      int stereo = hw->nchannels == 2;      int stereo = hw->info.nchannels == 2;
173      uint8_t rlen[4];      uint8_t rlen[4];
174      uint8_t dlen[4];      uint8_t dlen[4];
175      uint32_t rifflen = (wav->total_samples << stereo) + 36;      uint32_t rifflen = (wav->total_samples << stereo) + 36;
176      uint32_t datalen = wav->total_samples << stereo;      uint32_t datalen = wav->total_samples << stereo;
177    
178      if (!wav->f || !hw->active)      if (!wav->f || !hw->active) {
179          return;          return;
180        }
181    
182      le_store (rlen, rifflen, 4);      le_store (rlen, rifflen, 4);
183      le_store (dlen, datalen, 4);      le_store (dlen, datalen, 4);
# Line 181  static void wav_hw_fini (HWVoice *hw) Line 195  static void wav_hw_fini (HWVoice *hw)
195      wav->pcm_buf = NULL;      wav->pcm_buf = NULL;
196  }  }
197    
198  static int wav_hw_ctl (HWVoice *hw, int cmd, ...)  static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
199  {  {
200      (void) hw;      (void) hw;
201      (void) cmd;      (void) cmd;
# Line 195  static void *wav_audio_init (void) Line 209  static void *wav_audio_init (void)
209    
210  static void wav_audio_fini (void *opaque)  static void wav_audio_fini (void *opaque)
211  {  {
212        (void) opaque;
213      ldebug ("wav_fini");      ldebug ("wav_fini");
214  }  }
215    
216  struct pcm_ops wav_pcm_ops = {  struct audio_option wav_options[] = {
217      wav_hw_init,      {"PATH", AUD_OPT_STR, &conf.wav_path,
218      wav_hw_fini,       "Path to wave file", NULL, 0},
219      wav_hw_run,      {NULL, 0, NULL, NULL, NULL, 0}
220      wav_hw_write,  };
221      wav_hw_ctl  
222    struct audio_pcm_ops wav_pcm_ops = {
223        wav_init_out,
224        wav_fini_out,
225        wav_run_out,
226        wav_write_out,
227        wav_ctl_out,
228    
229        NULL,
230        NULL,
231        NULL,
232        NULL,
233        NULL
234  };  };
235    
236  struct audio_output_driver wav_output_driver = {  struct audio_driver wav_audio_driver = {
237      "wav",      INIT_FIELD (name           = ) "wav",
238      wav_audio_init,      INIT_FIELD (descr          = )
239      wav_audio_fini,      "WAV renderer http://wikipedia.org/wiki/WAV",
240      &wav_pcm_ops,      INIT_FIELD (options        = ) wav_options,
241      1,      INIT_FIELD (init           = ) wav_audio_init,
242      1,      INIT_FIELD (fini           = ) wav_audio_fini,
243      sizeof (WAVVoice)      INIT_FIELD (pcm_ops        = ) &wav_pcm_ops,
244        INIT_FIELD (can_be_default = ) 0,
245        INIT_FIELD (max_voices_out = ) 1,
246        INIT_FIELD (max_voices_in  = ) 0,
247        INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut),
248        INIT_FIELD (voice_size_in  = ) 0
249  };  };

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.4

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26