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