most of Q2's keyboard handling ported over - what this means: keypad is now separatel...
[divverent/darkplaces.git] / wavefile.c
1
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "wavefile.h"
6
7 wavefile_t *waveopen(char *filename, char **errorstring)
8 {
9         int validfmt, position, length, l;
10         char *error;
11         wavefile_t *w;
12         FILE *file;
13         unsigned char buffer[1024];
14         error = NULL;
15         file = fopen(filename, "rb");
16         if (file)
17         {
18                 w = malloc(sizeof(*w));
19                 memset(w, 0, sizeof(*w));
20                 if (w)
21                 {
22                         w->file = file;
23                         if (fread(buffer, 12, 1, w->file))
24                         {
25                                 if (!memcmp(buffer, "RIFF", 4))
26                                 {
27                                         if (!memcmp(buffer + 8, "WAVE", 4))
28                                         {
29                                                 validfmt = 0;
30                                                 for(;;)
31                                                 {
32                                                         if (!fread(buffer, 8, 1, w->file))
33                                                         {
34                                                                 //error = "error reading chunk\n");
35                                                                 break;
36                                                         }
37                                                         position = ftell(w->file);
38                                                         length = buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24);
39                                                         if (!memcmp(buffer, "fmt ", 4))
40                                                         {
41                                                                 validfmt = 0;
42                                                                 l = length;
43                                                                 if (l > 16)
44                                                                         l = 16;
45                                                                 if (!fread(buffer, l, 1, w->file))
46                                                                 {
47                                                                         error = "error reading \"fmt \" chunk\n";
48                                                                         break;
49                                                                 }
50                                                                 w->info_format = buffer[0] | (buffer[1] << 8);
51                                                                 if (w->info_format != 1)
52                                                                 {
53                                                                         error = "only PCM format supported\n";
54                                                                         break;
55                                                                 }
56                                                                 w->info_channels = buffer[2] | (buffer[3] << 8);
57                                                                 if (w->info_channels != 1 && w->info_channels != 2)
58                                                                 {
59                                                                         error = "only mono and stereo supported\n";
60                                                                         break;
61                                                                 }
62                                                                 w->info_rate = buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24);
63                                                                 if (w->info_rate < 1)
64                                                                 {
65                                                                         error = "only rates 1hz-100khz supported\n";
66                                                                         break;
67                                                                 }
68                                                                 w->info_bits = buffer[14] | (buffer[15] << 8);
69                                                                 if (w->info_bits != 8 && w->info_bits != 16)
70                                                                 {
71                                                                         error = "only 8bit and 16bit supported\n";
72                                                                         break;
73                                                                 }
74                                                                 validfmt = 1;
75                                                         }
76                                                         else if (!memcmp(buffer, "data", 4))
77                                                         {
78                                                                 if (validfmt)
79                                                                 {
80                                                                         w->datalength = length;
81                                                                         w->dataposition = position;
82                                                                 }
83                                                         }
84                                                         // other chunks that might be of interest:
85                                                         // "cue " (for looping)
86                                                         if (fseek(w->file, position + length, SEEK_SET))
87                                                         {
88                                                                 error = "error seeking to next chunk\n";
89                                                                 break;
90                                                         }
91                                                 }
92                                                 if (w->datalength && validfmt)
93                                                 {
94                                                         w->info_bytesperchannel = w->info_bits / 8;
95                                                         w->info_bytespersample = w->info_channels * w->info_bytesperchannel;
96                                                         w->length = w->datalength / w->info_bytespersample;
97                                                         w->position = 0;
98                                                         fseek(w->file, w->dataposition, SEEK_SET);
99                                                         return w;
100                                                 }
101                                         }
102                                         else
103                                                 error = "not a RIFF WAVE file\n";
104                                 }
105                                 else
106                                         error = "not a RIFF file\n";
107                         }
108                         else
109                                 error = "error reading file\n";
110                         free(w);
111                 }
112                 else
113                         error = "unable to allocate memory\n";
114                 fclose(file);
115         }
116         else
117                 error = "unable to open file\n";
118         if (errorstring)
119                 *errorstring = error;
120         return NULL;
121 }
122
123 void waveclose(wavefile_t *f)
124 {
125         if (f)
126         {
127                 fclose(f->file);
128                 free(f);
129         }
130 }
131
132 unsigned int waveread16stereo(wavefile_t *w, short *soundbuffer, unsigned int samples)
133 {
134         unsigned int i;
135         unsigned int length;
136         unsigned char *in;
137         short *out;
138         length = samples;
139         if (length > w->length - w->position)
140                 length = w->length - w->position;
141         if (w->bufferlength < length)
142         {
143                 if (w->buffer)
144                         free(w->buffer);
145                 w->bufferlength = length + 100;
146                 w->buffer = malloc(w->bufferlength * w->info_bytespersample);
147         }
148         length = fread(w->buffer, w->info_bytespersample, length, w->file);
149         w->position += length;
150         if (length > 0)
151         {
152                 if (w->info_bytesperchannel == 2)
153                 {
154                         if (w->info_channels == 2)
155                         {
156                                 for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 4, out += 2)
157                                 {
158                                         out[0] = in[0] | (in[1] << 8);
159                                         out[1] = in[2] | (in[3] << 8);
160                                 }
161                         }
162                         else
163                                 for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 2, out += 2)
164                                         out[0] = out[1] = in[0] | (in[1] << 8);
165                 }
166                 else
167                 {
168                         if (w->info_channels == 2)
169                         {
170                                 for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 2, out += 2)
171                                 {
172                                         out[0] = (in[0] - 128) << 8;
173                                         out[1] = (in[1] - 128) << 8;
174                                 }
175                         }
176                         else
177                                 for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 1, out += 2)
178                                         out[0] = out[1] = (in[0] - 128) << 8;
179                 }
180         }
181         return length;
182 }
183
184 unsigned int waveseek(wavefile_t *w, unsigned int samples)
185 {
186         if (samples > w->datalength)
187                 return 1;
188         else
189         {
190                 w->position = samples;
191                 fseek(w->file, w->dataposition + w->position * w->info_bytespersample, SEEK_SET);
192                 return 0;
193         }
194 }