]> icculus.org git repositories - divverent/darkplaces.git/blob - dpvsimpledecode.c
added comment support to COM_ReadAndTokenizeLine
[divverent/darkplaces.git] / dpvsimpledecode.c
1
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <math.h>
5 #include <string.h>
6 #include "dpvsimpledecode.h"
7 #include "wavefile.h"
8
9 #define EMBEDDEDHZREAD 1
10
11 #ifndef EMBEDDEDHZREAD
12 #include "hz_read.h"
13 #include "hz_read.c"
14 #else
15 #define HZREADERROR_OK 0
16 #define HZREADERROR_EOF 1
17 #define HZREADERROR_MALLOCFAILED 2
18
19 #define HZREADBLOCKSIZE 16000
20
21 typedef struct
22 {
23         qfile_t *file;
24         int endoffile;
25 }
26 hz_bitstream_read_t;
27
28 typedef struct hz_bitstream_readblock_s
29 {
30         struct hz_bitstream_readblock_s *next;
31         unsigned int size;
32         unsigned char data[HZREADBLOCKSIZE];
33 }
34 hz_bitstream_readblock_t;
35
36 typedef struct
37 {
38         hz_bitstream_readblock_t *blocks;
39         hz_bitstream_readblock_t *current;
40         unsigned int position;
41         unsigned int store;
42         int count;
43 }
44 hz_bitstream_readblocks_t;
45
46 hz_bitstream_read_t *hz_bitstream_read_open(char *filename)
47 {
48         qfile_t *file;
49         hz_bitstream_read_t *stream;
50         if ((file = FS_Open (filename, "rb", false)))
51         {
52                 stream = malloc(sizeof(hz_bitstream_read_t));
53                 memset(stream, 0, sizeof(*stream));
54                 stream->file = file;
55                 return stream;
56         }
57         else
58                 return NULL;
59 }
60
61 void hz_bitstream_read_close(hz_bitstream_read_t *stream)
62 {
63         if (stream)
64         {
65                 FS_Close(stream->file);
66                 free(stream);
67         }
68 }
69
70 hz_bitstream_readblocks_t *hz_bitstream_read_blocks_new(void)
71 {
72         hz_bitstream_readblocks_t *blocks;
73         blocks = malloc(sizeof(hz_bitstream_readblocks_t));
74         if (blocks == NULL)
75                 return NULL;
76         memset(blocks, 0, sizeof(hz_bitstream_readblocks_t));
77         return blocks;
78 }
79
80 void hz_bitstream_read_blocks_free(hz_bitstream_readblocks_t *blocks)
81 {
82         hz_bitstream_readblock_t *b, *n;
83         if (blocks == NULL)
84                 return;
85         for (b = blocks->blocks;b;b = n)
86         {
87                 n = b->next;
88                 free(b);
89         }
90         free(blocks);
91 }
92
93 void hz_bitstream_read_flushbits(hz_bitstream_readblocks_t *blocks)
94 {
95         blocks->store = 0;
96         blocks->count = 0;
97 }
98
99 int hz_bitstream_read_blocks_read(hz_bitstream_readblocks_t *blocks, hz_bitstream_read_t *stream, unsigned int size)
100 {
101         int s;
102         hz_bitstream_readblock_t *b, *p;
103         s = size;
104         p = NULL;
105         b = blocks->blocks;
106         while (s > 0)
107         {
108                 if (b == NULL)
109                 {
110                         b = malloc(sizeof(hz_bitstream_readblock_t));
111                         if (b == NULL)
112                                 return HZREADERROR_MALLOCFAILED;
113                         b->next = NULL;
114                         b->size = 0;
115                         if (p != NULL)
116                                 p->next = b;
117                         else
118                                 blocks->blocks = b;
119                 }
120                 if (s > HZREADBLOCKSIZE)
121                         b->size = HZREADBLOCKSIZE;
122                 else
123                         b->size = s;
124                 s -= b->size;
125                 if (FS_Read(stream->file, b->data, b->size) != b->size)
126                 {
127                         stream->endoffile = 1;
128                         break;
129                 }
130                 p = b;
131                 b = b->next;
132         }
133         while (b)
134         {
135                 b->size = 0;
136                 b = b->next;
137         }
138         blocks->current = blocks->blocks;
139         blocks->position = 0;
140         hz_bitstream_read_flushbits(blocks);
141         if (stream->endoffile)
142                 return HZREADERROR_EOF;
143         return HZREADERROR_OK;
144 }
145
146 unsigned int hz_bitstream_read_blocks_getbyte(hz_bitstream_readblocks_t *blocks)
147 {
148         while (blocks->current != NULL && blocks->position >= blocks->current->size)
149         {
150                 blocks->position = 0;
151                 blocks->current = blocks->current->next;
152         }
153         if (blocks->current == NULL)
154                 return 0;
155         return blocks->current->data[blocks->position++];
156 }
157
158 int hz_bitstream_read_bit(hz_bitstream_readblocks_t *blocks)
159 {
160         if (!blocks->count)
161         {
162                 blocks->count += 8;
163                 blocks->store <<= 8;
164                 blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF;
165         }
166         blocks->count--;
167         return (blocks->store >> blocks->count) & 1;
168 }
169
170 unsigned int hz_bitstream_read_bits(hz_bitstream_readblocks_t *blocks, int size)
171 {
172         unsigned int num = 0;
173         // we can only handle about 24 bits at a time safely
174         // (there might be up to 7 bits more than we need in the bit store)
175         if (size > 24)
176         {
177                 size -= 8;
178                 num |= hz_bitstream_read_bits(blocks, 8) << size;
179         }
180         while (blocks->count < size)
181         {
182                 blocks->count += 8;
183                 blocks->store <<= 8;
184                 blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF;
185         }
186         blocks->count -= size;
187         num |= (blocks->store >> blocks->count) & ((1 << size) - 1);
188         return num;
189 }
190
191 unsigned int hz_bitstream_read_byte(hz_bitstream_readblocks_t *blocks)
192 {
193         return hz_bitstream_read_blocks_getbyte(blocks);
194 }
195
196 unsigned int hz_bitstream_read_short(hz_bitstream_readblocks_t *blocks)
197 {
198         return (hz_bitstream_read_byte(blocks) << 8)
199              | (hz_bitstream_read_byte(blocks));
200 }
201
202 unsigned int hz_bitstream_read_int(hz_bitstream_readblocks_t *blocks)
203 {
204         return (hz_bitstream_read_byte(blocks) << 24)
205              | (hz_bitstream_read_byte(blocks) << 16)
206              | (hz_bitstream_read_byte(blocks) << 8)
207              | (hz_bitstream_read_byte(blocks));
208 }
209
210 void hz_bitstream_read_bytes(hz_bitstream_readblocks_t *blocks, void *outdata, unsigned int size)
211 {
212         unsigned char *out;
213         out = outdata;
214         while (size--)
215                 *out++ = hz_bitstream_read_byte(blocks);
216 }
217 #endif
218
219 #define BLOCKSIZE 8
220
221 typedef struct dpvsimpledecodestream_s
222 {
223         hz_bitstream_read_t *bitstream;
224         hz_bitstream_readblocks_t *framedatablocks;
225
226         int error;
227
228         double info_framerate;
229         unsigned int info_frames;
230
231         unsigned int info_imagewidth;
232         unsigned int info_imageheight;
233         unsigned int info_imagebpp;
234         unsigned int info_imageRloss;
235         unsigned int info_imageRmask;
236         unsigned int info_imageRshift;
237         unsigned int info_imageGloss;
238         unsigned int info_imageGmask;
239         unsigned int info_imageGshift;
240         unsigned int info_imageBloss;
241         unsigned int info_imageBmask;
242         unsigned int info_imageBshift;
243         unsigned int info_imagesize;
244
245         // current video frame (needed because of delta compression)
246         int videoframenum;
247         // current video frame data (needed because of delta compression)
248         unsigned int *videopixels;
249
250         // wav file the sound is being read from
251         wavefile_t *wavefile;
252 }
253 dpvsimpledecodestream_t;
254
255 static int dpvsimpledecode_setpixelformat(dpvsimpledecodestream_t *s, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel)
256 {
257         int Rshift, Rbits, Gshift, Gbits, Bshift, Bbits;
258         if (!Rmask)
259         {
260                 s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK;
261                 return s->error;
262         }
263         if (!Gmask)
264         {
265                 s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK;
266                 return s->error;
267         }
268         if (!Bmask)
269         {
270                 s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK;
271                 return s->error;
272         }
273         if (Rmask & Gmask || Rmask & Bmask || Gmask & Bmask)
274         {
275                 s->error = DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP;
276                 return s->error;
277         }
278         switch (bytesperpixel)
279         {
280         case 2:
281                 if ((Rmask | Gmask | Bmask) > 65536)
282                 {
283                         s->error = DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP;
284                         return s->error;
285                 }
286                 break;
287         case 4:
288                 break;
289         default:
290                 s->error = DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP;
291                 return s->error;
292                 break;
293         }
294         for (Rshift = 0;!(Rmask & 1);Rshift++, Rmask >>= 1);
295         for (Gshift = 0;!(Gmask & 1);Gshift++, Gmask >>= 1);
296         for (Bshift = 0;!(Bmask & 1);Bshift++, Bmask >>= 1);
297         if (((Rmask + 1) & Rmask) != 0)
298         {
299                 s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK;
300                 return s->error;
301         }
302         if (((Gmask + 1) & Gmask) != 0)
303         {
304                 s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK;
305                 return s->error;
306         }
307         if (((Bmask + 1) & Bmask) != 0)
308         {
309                 s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK;
310                 return s->error;
311         }
312         for (Rbits = 0;Rmask & 1;Rbits++, Rmask >>= 1);
313         for (Gbits = 0;Gmask & 1;Gbits++, Gmask >>= 1);
314         for (Bbits = 0;Bmask & 1;Bbits++, Bmask >>= 1);
315         if (Rbits > 8)
316         {
317                 Rshift += (Rbits - 8);
318                 Rbits = 8;
319         }
320         if (Gbits > 8)
321         {
322                 Gshift += (Gbits - 8);
323                 Gbits = 8;
324         }
325         if (Bbits > 8)
326         {
327                 Bshift += (Bbits - 8);
328                 Bbits = 8;
329         }
330         s->info_imagebpp = bytesperpixel;
331         s->info_imageRloss = 16 + (8 - Rbits);
332         s->info_imageGloss =  8 + (8 - Gbits);
333         s->info_imageBloss =  0 + (8 - Bbits);
334         s->info_imageRmask = (1 << Rbits) - 1;
335         s->info_imageGmask = (1 << Gbits) - 1;
336         s->info_imageBmask = (1 << Bbits) - 1;
337         s->info_imageRshift = Rshift;
338         s->info_imageGshift = Gshift;
339         s->info_imageBshift = Bshift;
340         s->info_imagesize = s->info_imagewidth * s->info_imageheight * s->info_imagebpp;
341         return s->error;
342 }
343
344 // opening and closing streams
345
346 static void StripExtension(char *in, char *out)
347 {
348         char *dot, *c;
349         dot = NULL;
350         for (c = in;*c;c++)
351         {
352                 if (*c == ':' || *c == '\\' || *c == '/')
353                         dot = NULL;
354                 if (*c == '.')
355                         dot = c;
356         }
357         if (dot == NULL)
358         {
359                 // nothing to remove
360                 strcpy(out, in);
361                 return;
362         }
363         else
364         {
365                 memcpy(out, in, dot - in);
366                 out[dot - in] = 0;
367         }
368 }
369
370 // opens a stream
371 void *dpvsimpledecode_open(char *filename, char **errorstring)
372 {
373         dpvsimpledecodestream_t *s;
374         char t[8], *wavename;
375         if (errorstring != NULL)
376                 *errorstring = NULL;
377         s = malloc(sizeof(dpvsimpledecodestream_t));
378         if (s != NULL)
379         {
380                 s->bitstream = hz_bitstream_read_open(filename);
381                 if (s->bitstream != NULL)
382                 {
383                         // check file identification
384                         s->framedatablocks = hz_bitstream_read_blocks_new();
385                         if (s->framedatablocks != NULL)
386                         {
387                                 hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
388                                 hz_bitstream_read_bytes(s->framedatablocks, t, 8);
389                                 if (!memcmp(t, "DPVideo", 8))
390                                 {
391                                         // check version number
392                                         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 2);
393                                         if (hz_bitstream_read_short(s->framedatablocks) == 1)
394                                         {
395                                                 hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 12);
396                                                 s->info_imagewidth = hz_bitstream_read_short(s->framedatablocks);
397                                                 s->info_imageheight = hz_bitstream_read_short(s->framedatablocks);
398                                                 s->info_framerate = (double) hz_bitstream_read_int(s->framedatablocks) * (1.0 / 65536.0);
399
400                                                 if (s->info_framerate > 0.0)
401                                                 {
402                                                         s->videopixels = malloc(s->info_imagewidth * s->info_imageheight * sizeof(*s->videopixels));
403                                                         if (s->videopixels != NULL)
404                                                         {
405                                                                 wavename = malloc(strlen(filename) + 10);
406                                                                 if (wavename)
407                                                                 {
408                                                                         StripExtension(filename, wavename);
409                                                                         strcat(wavename, ".wav");
410                                                                         s->wavefile = waveopen(wavename, NULL);
411                                                                         free(wavename);
412                                                                 }
413                                                                 // all is well...
414                                                                 s->videoframenum = -10000;
415                                                                 return s;
416                                                         }
417                                                         else if (errorstring != NULL)
418                                                                 *errorstring = "unable to allocate video image buffer";
419                                                 }
420                                                 else if (errorstring != NULL)
421                                                         *errorstring = "error in video info chunk";
422                                         }
423                                         else if (errorstring != NULL)
424                                                 *errorstring = "read error";
425                                 }
426                                 else if (errorstring != NULL)
427                                         *errorstring = "not a dpvideo file";
428                                 hz_bitstream_read_blocks_free(s->framedatablocks);
429                         }
430                         else if (errorstring != NULL)
431                                 *errorstring = "unable to allocate memory for reading buffer";
432                         hz_bitstream_read_close(s->bitstream);
433                 }
434                 else if (errorstring != NULL)
435                         *errorstring = "unable to open file";
436                 free(s);
437         }
438         else if (errorstring != NULL)
439                 *errorstring = "unable to allocate memory for stream info structure";
440         return NULL;
441 }
442
443 // closes a stream
444 void dpvsimpledecode_close(void *stream)
445 {
446         dpvsimpledecodestream_t *s = stream;
447         if (s == NULL)
448                 return;
449         if (s->videopixels)
450                 free(s->videopixels);
451         if (s->wavefile)
452                 waveclose(s->wavefile);
453         if (s->framedatablocks)
454                 hz_bitstream_read_blocks_free(s->framedatablocks);
455         if (s->bitstream)
456                 hz_bitstream_read_close(s->bitstream);
457         free(s);
458 }
459
460 // utilitarian functions
461
462 // returns the current error number for the stream, and resets the error
463 // number to DPVSIMPLEDECODEERROR_NONE
464 // if the supplied string pointer variable is not NULL, it will be set to the
465 // error message
466 int dpvsimpledecode_error(void *stream, char **errorstring)
467 {
468         dpvsimpledecodestream_t *s = stream;
469         int e;
470         e = s->error;
471         s->error = 0;
472         if (errorstring)
473         {
474                 switch (e)
475                 {
476                         case DPVSIMPLEDECODEERROR_NONE:
477                                 *errorstring = "no error";
478                                 break;
479                         case DPVSIMPLEDECODEERROR_EOF:
480                                 *errorstring = "end of file reached (this is not an error)";
481                                 break;
482                         case DPVSIMPLEDECODEERROR_READERROR:
483                                 *errorstring = "read error (corrupt or incomplete file)";
484                                 break;
485                         case DPVSIMPLEDECODEERROR_SOUNDBUFFERTOOSMALL:
486                                 *errorstring = "sound buffer is too small for decoding frame (please allocate it as large as dpvsimpledecode_getneededsoundbufferlength suggests)";
487                                 break;
488                         case DPVSIMPLEDECODEERROR_INVALIDRMASK:
489                                 *errorstring = "invalid red bits mask";
490                                 break;
491                         case DPVSIMPLEDECODEERROR_INVALIDGMASK:
492                                 *errorstring = "invalid green bits mask";
493                                 break;
494                         case DPVSIMPLEDECODEERROR_INVALIDBMASK:
495                                 *errorstring = "invalid blue bits mask";
496                                 break;
497                         case DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP:
498                                 *errorstring = "color bit masks overlap";
499                                 break;
500                         case DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP:
501                                 *errorstring = "color masks too big for specified bytes per pixel";
502                                 break;
503                         case DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP:
504                                 *errorstring = "unsupported bytes per pixel (must be 2 for 16bit, or 4 for 32bit)";
505                                 break;
506                         default:
507                                 *errorstring = "unknown error";
508                                 break;
509                 }
510         }
511         return e;
512 }
513
514 // returns the width of the image data
515 unsigned int dpvsimpledecode_getwidth(void *stream)
516 {
517         dpvsimpledecodestream_t *s = stream;
518         return s->info_imagewidth;
519 }
520
521 // returns the height of the image data
522 unsigned int dpvsimpledecode_getheight(void *stream)
523 {
524         dpvsimpledecodestream_t *s = stream;
525         return s->info_imageheight;
526 }
527
528 // returns the sound sample rate of the stream
529 unsigned int dpvsimpledecode_getsoundrate(void *stream)
530 {
531         dpvsimpledecodestream_t *s = stream;
532         if (s->wavefile)
533                 return s->wavefile->info_rate;
534         else
535                 return 0;
536 }
537
538 // returns the framerate of the stream
539 double dpvsimpledecode_getframerate(void *stream)
540 {
541         dpvsimpledecodestream_t *s = stream;
542         return s->info_framerate;
543 }
544
545
546
547
548
549 static int dpvsimpledecode_convertpixels(dpvsimpledecodestream_t *s, void *imagedata, int imagebytesperrow)
550 {
551         unsigned int a, x, y, width, height;
552         unsigned int Rloss, Rmask, Rshift, Gloss, Gmask, Gshift, Bloss, Bmask, Bshift;
553         unsigned int *in;
554
555         width = s->info_imagewidth;
556         height = s->info_imageheight;
557
558         Rloss = s->info_imageRloss;
559         Rmask = s->info_imageRmask;
560         Rshift = s->info_imageRshift;
561         Gloss = s->info_imageGloss;
562         Gmask = s->info_imageGmask;
563         Gshift = s->info_imageGshift;
564         Bloss = s->info_imageBloss;
565         Bmask = s->info_imageBmask;
566         Bshift = s->info_imageBshift;
567
568         in = s->videopixels;
569         if (s->info_imagebpp == 4)
570         {
571                 unsigned int *outrow;
572                 for (y = 0;y < height;y++)
573                 {
574                         outrow = (void *)((unsigned char *)imagedata + y * imagebytesperrow);
575                         for (x = 0;x < width;x++)
576                         {
577                                 a = *in++;
578                                 outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
579                         }
580                 }
581         }
582         else
583         {
584                 unsigned short *outrow;
585                 for (y = 0;y < height;y++)
586                 {
587                         outrow = (void *)((unsigned char *)imagedata + y * imagebytesperrow);
588                         if (Rloss == 19 && Gloss == 10 && Bloss == 3 && Rshift == 11 && Gshift == 5 && Bshift == 0)
589                         {
590                                 // optimized
591                                 for (x = 0;x < width;x++)
592                                 {
593                                         a = *in++;
594                                         outrow[x] = ((a >> 8) & 0xF800) | ((a >> 5) & 0x07E0) | ((a >> 3) & 0x001F);
595                                 }
596                         }
597                         else
598                         {
599                                 for (x = 0;x < width;x++)
600                                 {
601                                         a = *in++;
602                                         outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
603                                 }
604                         }
605                 }
606         }
607         return s->error;
608 }
609
610 static int dpvsimpledecode_decompressimage(dpvsimpledecodestream_t *s)
611 {
612         int i, a, b, colors, g, x1, y1, bw, bh, width, height, palettebits;
613         unsigned int palette[256], *outrow, *out;
614         g = BLOCKSIZE;
615         width = s->info_imagewidth;
616         height = s->info_imageheight;
617         for (y1 = 0;y1 < height;y1 += g)
618         {
619                 outrow = s->videopixels + y1 * width;
620                 bh = g;
621                 if (y1 + bh > height)
622                         bh = height - y1;
623                 for (x1 = 0;x1 < width;x1 += g)
624                 {
625                         out = outrow + x1;
626                         bw = g;
627                         if (x1 + bw > width)
628                                 bw = width - x1;
629                         if (hz_bitstream_read_bit(s->framedatablocks))
630                         {
631                                 // updated block
632                                 palettebits = hz_bitstream_read_bits(s->framedatablocks, 3);
633                                 colors = 1 << palettebits;
634                                 for (i = 0;i < colors;i++)
635                                         palette[i] = hz_bitstream_read_bits(s->framedatablocks, 24);
636                                 if (palettebits)
637                                 {
638                                         for (b = 0;b < bh;b++, out += width)
639                                                 for (a = 0;a < bw;a++)
640                                                         out[a] = palette[hz_bitstream_read_bits(s->framedatablocks, palettebits)];
641                                 }
642                                 else
643                                 {
644                                         for (b = 0;b < bh;b++, out += width)
645                                                 for (a = 0;a < bw;a++)
646                                                         out[a] = palette[0];
647                                 }
648                         }
649                 }
650         }
651         return s->error;
652 }
653
654 // decodes a video frame to the supplied output pixels
655 int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
656 {
657         dpvsimpledecodestream_t *s = stream;
658         unsigned int framedatasize;
659         char t[4];
660         s->error = DPVSIMPLEDECODEERROR_NONE;
661         if (dpvsimpledecode_setpixelformat(s, Rmask, Gmask, Bmask, bytesperpixel))
662                 return s->error;
663
664         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
665         hz_bitstream_read_bytes(s->framedatablocks, t, 4);
666         if (memcmp(t, "VID0", 4))
667         {
668                 if (t[0] == 0)
669                         return (s->error = DPVSIMPLEDECODEERROR_EOF);
670                 else
671                         return (s->error = DPVSIMPLEDECODEERROR_READERROR);
672         }
673         framedatasize = hz_bitstream_read_int(s->framedatablocks);
674         hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, framedatasize);
675         if (dpvsimpledecode_decompressimage(s))
676                 return s->error;
677
678         dpvsimpledecode_convertpixels(s, imagedata, imagebytesperrow);
679         return s->error;
680 }
681
682 // (note: sound is 16bit stereo native-endian, left channel first)
683 int dpvsimpledecode_audio(void *stream, short *soundbuffer, int requestedlength)
684 {
685         int samples;
686         dpvsimpledecodestream_t *s = stream;
687         s->error = DPVSIMPLEDECODEERROR_NONE;
688         if (requestedlength)
689         {
690                 samples = 0;
691                 if (s->wavefile && requestedlength)
692                         samples = waveread16stereo(s->wavefile, soundbuffer, requestedlength);
693                 if (samples < requestedlength)
694                         memset(soundbuffer + samples * 2, 0, (requestedlength - samples) * sizeof(short[2]));
695         }
696         return s->error;
697 }