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