00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <unistd.h>
00004 #include <fcntl.h>
00005 #include <errno.h>
00006 #include <string.h>
00007 #include <sys/ioctl.h>
00008 #include <sys/time.h>
00009
00010 #include <alsa/asoundlib.h>
00011
00012 int xrun_count;
00013
00014 int dsp_fd;
00015
00016 static int buffer_size;
00017 static int period_size;
00018
00019 static void
00020 set_hwparams(snd_pcm_t *handle)
00021 {
00022 snd_pcm_uframes_t size;
00023 int dir;
00024 snd_pcm_hw_params_t *hwparams;
00025 unsigned int uval;
00026
00027 snd_pcm_hw_params_malloc(&hwparams);
00028
00029 snd_pcm_hw_params_any(handle, hwparams);
00030
00031 snd_pcm_hw_params_set_rate_resample(handle, hwparams, 1);
00032
00033 snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
00034 snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_U8);
00035 snd_pcm_hw_params_set_channels(handle, hwparams, 1);
00036
00037 uval = 11025;
00038 snd_pcm_hw_params_set_rate_near(handle, hwparams, &uval, 0);
00039
00040 uval = 500 * 1000;
00041 snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &uval, &dir);
00042 snd_pcm_hw_params_get_buffer_size(hwparams, &size);
00043 buffer_size = size;
00044
00045 uval = 100 * 1000;
00046 snd_pcm_hw_params_set_period_time_near(handle, hwparams, &uval, &dir);
00047 snd_pcm_hw_params_get_period_size(hwparams, &size, &dir);
00048 period_size = size;
00049
00050 snd_pcm_hw_params(handle, hwparams);
00051
00052 printf ("buffer_size %d; period_size %d\n", buffer_size, period_size);
00053 }
00054
00055 static void
00056 set_swparams(snd_pcm_t *handle)
00057 {
00058 snd_pcm_sw_params_t *swparams;
00059
00060 snd_pcm_sw_params_malloc(&swparams);
00061
00062 snd_pcm_sw_params_current(handle, swparams);
00063
00064
00065
00066 snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);
00067
00068
00069 snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
00070
00071
00072 snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
00073
00074 snd_pcm_sw_params(handle, swparams);
00075 }
00076
00077 snd_pcm_t *pcm;
00078
00079 void
00080 sound_init (void)
00081 {
00082 int err;
00083 char *device;
00084
00085 device = "plughw:0,0";
00086
00087 printf ("opening pcm device %s\n", device);
00088 if ((err = snd_pcm_open(&pcm, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
00089 printf("Playback open error: %s\n", snd_strerror(err));
00090 exit (1);
00091 }
00092
00093 set_hwparams(pcm);
00094 set_swparams(pcm);
00095 }
00096
00097 int soundbuf_size;
00098 unsigned char *soundbuf;
00099 int soundbuf_used;
00100 int soundbuf_off;
00101 int soundbuf_playing;
00102
00103
00104 int
00105 sound_step (void)
00106 {
00107 int avail, n;
00108
00109 if (soundbuf_playing == 0)
00110 return (0);
00111
00112 if ((avail = soundbuf_used - soundbuf_off) == 0) {
00113 soundbuf_playing = 0;
00114
00115 snd_pcm_drain (pcm);
00116 return (0);
00117 }
00118
00119 if (avail > period_size)
00120 avail = period_size;
00121
00122 n = snd_pcm_writei (pcm, soundbuf + soundbuf_off, avail);
00123
00124 if (n < 0) {
00125 if (n == -EAGAIN) {
00126 usleep (1);
00127 return (1);
00128 }
00129 if (n == -EPIPE) {
00130 xrun_count++;
00131 snd_pcm_prepare (pcm);
00132 return (1);
00133 }
00134
00135 printf ("sound write error: %s\n",
00136 snd_strerror(n));
00137 exit (1);
00138 }
00139
00140
00141
00142
00143 soundbuf_off += n;
00144
00145 return (1);
00146 }
00147
00148 void
00149 sound_play (unsigned char *buf, int size)
00150 {
00151 unsigned char *start_buf;
00152
00153 if (size > soundbuf_size) {
00154 if (soundbuf)
00155 free (soundbuf);
00156 soundbuf_size = size;
00157 if ((soundbuf = malloc (soundbuf_size)) == NULL) {
00158 fprintf (stderr, "out of memory\n");
00159 exit (1);
00160 }
00161 }
00162
00163 memcpy (soundbuf, buf, size);
00164
00165 soundbuf_used = size;
00166 soundbuf_off = 0;
00167 soundbuf_playing = 1;
00168
00169 snd_pcm_start (pcm);
00170 snd_pcm_prepare (pcm);
00171
00172 start_buf = malloc (buffer_size);
00173 memset (start_buf, 0x80, buffer_size);
00174 snd_pcm_writei (pcm, start_buf, buffer_size);
00175 free (start_buf);
00176
00177 sound_step ();
00178 }
00179
00180 double
00181 get_time (void)
00182 {
00183 struct timeval tv;
00184 gettimeofday (&tv, NULL);
00185 return (tv.tv_sec + tv.tv_usec / 1e6);
00186 }
00187
00188 void
00189 busywait (double secs)
00190 {
00191 double start;
00192 start = get_time ();
00193 while (get_time () - start < secs)
00194 ;
00195 }
00196
00197 void
00198 usage (void)
00199 {
00200 fprintf (stderr, "usage: vtest idx\n");
00201 exit (1);
00202 }
00203
00204 int
00205 main (int argc, char **argv)
00206 {
00207 int c;
00208 char *filename;
00209 int idx;
00210 FILE *f;
00211 char *rawbuf;
00212 FILE *outf;
00213 int i;
00214
00215 struct TM {
00216 long offset;
00217 long size;
00218 } ABSnd;
00219
00220 filename = "/l/baris/gamedat/unews.cdr";
00221
00222 while ((c = getopt (argc, argv, "")) != EOF) {
00223 switch (c) {
00224 default:
00225 usage ();
00226 }
00227 }
00228
00229 if (optind >= argc)
00230 usage ();
00231
00232 idx = atoi (argv[optind++]);
00233
00234 if (optind != argc)
00235 usage ();
00236
00237 if ((f = fopen (filename, "rb")) == NULL) {
00238 fprintf (stderr, "can't open %s\n", filename);
00239 exit (1);
00240 }
00241
00242 fseek (f, idx * sizeof (ABSnd), SEEK_SET);
00243 fread (&ABSnd, sizeof ABSnd, 1, f);
00244
00245 printf ("offset %ld; size %ld\n", ABSnd.offset, ABSnd.size);
00246
00247 if ((rawbuf = malloc (ABSnd.size)) == NULL) {
00248 fprintf (stderr, "out of memory\n");
00249 exit (1);
00250 }
00251
00252 fseek (f, ABSnd.offset, SEEK_SET);
00253 fread (rawbuf, 1, ABSnd.size, f);
00254
00255 outf = fopen ("x", "wb");
00256 fwrite (rawbuf, 1, ABSnd.size, outf);
00257 fclose (outf);
00258
00259 outf = fopen ("y", "wb");
00260 for (i = 0; i < ABSnd.size; i++)
00261 fprintf (outf, "%d\n", rawbuf[i] & 0xff);
00262 fclose (outf);
00263
00264 sound_init ();
00265
00266 usleep (250 * 1000);
00267
00268 sound_play ((unsigned char *)rawbuf, ABSnd.size);
00269 while (sound_step ())
00270 ;
00271
00272 usleep (250 * 1000);
00273
00274 printf ("total xruns %d\n", xrun_count);
00275
00276 return (0);
00277 }
00278