fixed by preloading samples. the audio callback is being called from the
[dos_auplay] / src / auwav.c
1 #include <stdio.h>\r
2 #include <stdlib.h>\r
3 #include "aufile.h"\r
4 #include "inttypes.h"\r
5 \r
6 struct format {\r
7         uint16_t fmt;\r
8         uint16_t nchan;\r
9         uint32_t rate;\r
10         uint16_t avgbaud;\r
11         uint16_t block_align;\r
12         uint16_t sample_bytes;\r
13 };\r
14 \r
15 struct playback_data {\r
16         uint32_t start, size;\r
17         uint32_t bytes_left;\r
18 };\r
19 \r
20 #define FOURCC(a, b, c, d) \\r
21         ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))\r
22 \r
23 enum {\r
24         ID_RIFF = FOURCC('R', 'I', 'F', 'F'),\r
25         ID_WAVE = FOURCC('W', 'A', 'V', 'E'),\r
26         ID_FMT = FOURCC('f', 'm', 't', ' '),\r
27         ID_DATA = FOURCC('d', 'a', 't', 'a')\r
28 };\r
29 \r
30 static void close_wav(struct au_file *au);\r
31 static void reset_wav(struct au_file *au);\r
32 static int read_wav(struct au_file *au, void *buf, int size);\r
33 static int read_uint32(uint32_t *res, FILE *fp);\r
34 static int read_format(struct format *fmt, int fmtsize, FILE *fp);\r
35 \r
36 \r
37 int au_open_wav(struct au_file *au)\r
38 {\r
39         uint32_t id, len;\r
40         struct format fmt;\r
41         struct playback_data *pb;\r
42 \r
43         if(read_uint32(&id, au->fp) == -1 || id != ID_RIFF)\r
44                 return -1;\r
45         fseek(au->fp, 4, SEEK_CUR);\r
46         if(read_uint32(&id, au->fp) == -1 || id != ID_WAVE)\r
47                 return -1;\r
48         if(read_uint32(&id, au->fp) == -1 || id != ID_FMT)\r
49                 return -1;\r
50         if(read_uint32(&len, au->fp) == -1)\r
51                 return -1;\r
52         if(read_format(&fmt, len, au->fp) == -1)\r
53                 return -1;\r
54         if(read_uint32(&id, au->fp) == -1 || id != ID_DATA)\r
55                 return -1;\r
56         if(read_uint32(&len, au->fp) == -1)\r
57                 return -1;\r
58 \r
59         if(!(pb = malloc(sizeof *pb))) {\r
60                 fprintf(stderr, "failed to allocate wav playback data block\n");\r
61                 return -1;\r
62         }\r
63         pb->start = ftell(au->fp);\r
64         pb->size = pb->bytes_left = len;\r
65 \r
66         au->rate = fmt.rate;\r
67         au->bits = fmt.sample_bytes * 8;\r
68         au->chan = fmt.nchan;\r
69         au->size = pb->size;\r
70         au->data = pb;\r
71 \r
72         au->close = close_wav;\r
73         au->reset = reset_wav;\r
74         au->read = read_wav;\r
75         return 0;\r
76 }\r
77 \r
78 static void close_wav(struct au_file *au)\r
79 {\r
80         free(au->data);\r
81 }\r
82 \r
83 static void reset_wav(struct au_file *au)\r
84 {\r
85         struct playback_data *pb = au->data;\r
86         pb->bytes_left = pb->size;\r
87         fseek(au->fp, pb->start, SEEK_SET);\r
88 }\r
89 \r
90 static int read_wav(struct au_file *au, void *buf, int size)\r
91 {\r
92         struct playback_data *pb = au->data;\r
93         size_t rd;\r
94 \r
95         if(size > pb->bytes_left) {\r
96                 size = pb->bytes_left;\r
97         }\r
98         if(size <= 0) {\r
99                 return 0;\r
100         }\r
101         if((rd = fread(buf, 1, size, au->fp)) == -1) {\r
102                 pb->bytes_left = 0;\r
103                 return -1;\r
104         }\r
105         pb->bytes_left -= rd;\r
106         return rd;\r
107 }\r
108 \r
109 #ifdef BIGENDIAN\r
110 static void swap_uint32(uint32_t *val)\r
111 {\r
112         uint32_t x = *val;\r
113         *val = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);\r
114 }\r
115 \r
116 static void swap_uint16(uint16_t *val)\r
117 {\r
118         uint16_t x = *val;\r
119         *val = (x << 8) | (x >> 8);\r
120 }\r
121 #endif\r
122 \r
123 static int read_uint32(uint32_t *res, FILE *fp)\r
124 {\r
125         if(fread(res, 4, 1, fp) < 1) {\r
126                 return -1;\r
127         }\r
128 #ifdef BIGENDIAN\r
129         swap_uint32(res);\r
130 #endif\r
131         return 0;\r
132 }\r
133 \r
134 static int read_format(struct format *fmt, int fmtsize, FILE *fp)\r
135 {\r
136         if(fread(fmt, 1, fmtsize, fp) < fmtsize) {\r
137                 return -1;\r
138         }\r
139 #ifdef BIGENDIAN\r
140         swap_uint16(&fmt->fmt);\r
141         swap_uint16(&fmt->nchan);\r
142         swap_uint32(&fmt->rate);\r
143         swap_uint16(&fmt->avgbaud);\r
144         swap_uint16(&fmt->block_align);\r
145 #endif\r
146         return 0;\r
147 }\r