]> icculus.org git repositories - btb/d2x.git/blob - libmve/mveplay.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / libmve / mveplay.c
1 #ifdef HAVE_CONFIG_H
2 #include <conf.h>
3 #endif
4
5 #ifndef __MSDOS__
6 #define AUDIO
7 #endif
8 //#define DEBUG
9
10 #include <string.h>
11 #ifdef _WIN32
12 # include <windows.h>
13 #else
14 # include <errno.h>
15 # include <time.h>
16 # include <fcntl.h>
17 # ifdef macintosh
18 #  include <types.h>
19 #  include <OSUtils.h>
20 # else
21 #  include <sys/time.h>
22 #  include <sys/types.h>
23 #  include <sys/stat.h>
24 #  include <unistd.h>
25 # endif // macintosh
26 #endif // _WIN32
27
28 #if defined(AUDIO)
29 #include <SDL.h>
30 #include "SDL_mixer.h"
31 #endif
32
33 #include "mvelib.h"
34 #include "mve_audio.h"
35
36 #include "decoders.h"
37
38 #include "libmve.h"
39
40 #define MVE_OPCODE_ENDOFSTREAM          0x00
41 #define MVE_OPCODE_ENDOFCHUNK           0x01
42 #define MVE_OPCODE_CREATETIMER          0x02
43 #define MVE_OPCODE_INITAUDIOBUFFERS     0x03
44 #define MVE_OPCODE_STARTSTOPAUDIO       0x04
45 #define MVE_OPCODE_INITVIDEOBUFFERS     0x05
46
47 #define MVE_OPCODE_DISPLAYVIDEO         0x07
48 #define MVE_OPCODE_AUDIOFRAMEDATA       0x08
49 #define MVE_OPCODE_AUDIOFRAMESILENCE    0x09
50 #define MVE_OPCODE_INITVIDEOMODE        0x0A
51
52 #define MVE_OPCODE_SETPALETTE           0x0C
53 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
54
55 #define MVE_OPCODE_SETDECODINGMAP       0x0F
56
57 #define MVE_OPCODE_VIDEODATA            0x11
58
59 #define MVE_AUDIO_FLAGS_STEREO     1
60 #define MVE_AUDIO_FLAGS_16BIT      2
61 #define MVE_AUDIO_FLAGS_COMPRESSED 4
62
63 int g_spdFactorNum=0;
64 static int g_spdFactorDenom=10;
65 static int g_frameUpdated = 0;
66
67 static short get_short(unsigned char *data)
68 {
69         short value;
70         value = data[0] | (data[1] << 8);
71         return value;
72 }
73
74 static unsigned short get_ushort(unsigned char *data)
75 {
76         unsigned short value;
77         value = data[0] | (data[1] << 8);
78         return value;
79 }
80
81 static int get_int(unsigned char *data)
82 {
83         int value;
84         value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
85         return value;
86 }
87
88 static unsigned int unhandled_chunks[32*256];
89
90 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
91 {
92         unhandled_chunks[major<<8|minor]++;
93         //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
94         return 1;
95 }
96
97
98 /*************************
99  * general handlers
100  *************************/
101 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
102 {
103         return 0;
104 }
105
106 /*************************
107  * timer handlers
108  *************************/
109
110 /*
111  * timer variables
112  */
113 static int timer_created = 0;
114 static int micro_frame_delay=0;
115 static int timer_started=0;
116 static unsigned long int timer_expire = 0;
117
118 #if defined(_WIN32) || defined(macintosh)
119
120 unsigned long int timer_getmicroseconds()
121 {
122         static int counter = 0;
123 #ifdef _WIN32
124         DWORD now = GetTickCount();
125 #else
126         long now = TickCount();
127 #endif
128         counter++;
129
130         return now * 1000 + counter;
131 }
132
133 #else
134
135 unsigned long int timer_getmicroseconds()
136 {
137         struct timeval tv;
138         static time_t starttime = 0;
139
140         gettimeofday(&tv, NULL);
141
142         if (!starttime)
143                 starttime = tv.tv_sec;
144
145         return (tv.tv_sec - starttime) * 1000000 + tv.tv_usec;
146 }
147
148 #endif
149
150 void timer_sleepmicroseconds(unsigned long int usec)
151 {
152 #ifdef _WIN32
153         Sleep(usec / 1000);
154 #elif defined(macintosh)
155         Delay(usec / 1000);
156 #else
157         struct timespec ts;
158         ts.tv_sec = usec / 1000000;
159         ts.tv_nsec = usec % 1000000 * 1000;
160         nanosleep(&ts, NULL);
161 #endif
162 }
163
164 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
165 {
166
167 #if !defined(_WIN32) && !defined(macintosh) // FIXME
168         __extension__ long long temp;
169 #else
170         long temp;
171 #endif
172
173         if (timer_created)
174                 return 1;
175         else
176                 timer_created = 1;
177
178         micro_frame_delay = get_int(data) * (int)get_short(data+4);
179         if (g_spdFactorNum != 0)
180         {
181                 temp = micro_frame_delay;
182                 temp *= g_spdFactorNum;
183                 temp /= g_spdFactorDenom;
184                 micro_frame_delay = (int)temp;
185         }
186
187         return 1;
188 }
189
190 static void timer_stop(void)
191 {
192         timer_expire = 0;
193         timer_started = 0;
194 }
195
196 static void timer_start(void)
197 {
198         timer_expire = timer_getmicroseconds();
199         timer_expire += micro_frame_delay;
200         timer_started=1;
201 }
202
203 static void do_timer_wait(void)
204 {
205         unsigned long int ts;
206         unsigned long int tv;
207
208         if (! timer_started)
209                 return;
210
211         tv = timer_getmicroseconds();
212         if (tv > timer_expire)
213                 goto end;
214
215         ts = timer_expire - tv;
216
217         timer_sleepmicroseconds(ts);
218
219  end:
220         timer_expire += micro_frame_delay;
221 }
222
223 /*************************
224  * audio handlers
225  *************************/
226 #ifdef AUDIO
227 #define TOTAL_AUDIO_BUFFERS 64
228
229 static int audiobuf_created = 0;
230 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
231 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
232 static int    mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
233 static int    mve_audio_curbuf_curpos=0;
234 static int mve_audio_bufhead=0;
235 static int mve_audio_buftail=0;
236 static int mve_audio_playing=0;
237 static int mve_audio_canplay=0;
238 static int mve_audio_compressed=0;
239 static int mve_audio_enabled = 1;
240
241
242 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
243 {
244         int total=0;
245         int length;
246         if (mve_audio_bufhead == mve_audio_buftail)
247                 return /* 0 */;
248
249         //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
250
251         while (mve_audio_bufhead != mve_audio_buftail                                           /* while we have more buffers  */
252                    &&  len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos))        /* and while we need more data */
253         {
254                 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
255                 memcpy(stream,                                                                  /* cur output position */
256                        ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos,           /* cur input position  */
257                        length);                                                                 /* cur input length    */
258
259                 total += length;
260                 stream += length;                                                               /* advance output */
261                 len -= length;                                                                  /* decrement avail ospace */
262                 mve_free(mve_audio_buffers[mve_audio_bufhead]);                                 /* free the buffer */
263                 mve_audio_buffers[mve_audio_bufhead]=NULL;                                      /* free the buffer */
264                 mve_audio_buflens[mve_audio_bufhead]=0;                                         /* free the buffer */
265
266                 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS)                                 /* next buffer */
267                         mve_audio_bufhead = 0;
268                 mve_audio_curbuf_curpos = 0;
269         }
270
271         //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
272         /*    return total; */
273
274         if (len != 0                                                                        /* ospace remaining  */
275                 &&  mve_audio_bufhead != mve_audio_buftail)                                     /* buffers remaining */
276         {
277                 memcpy(stream,                                                                  /* dest */
278                            ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos,         /* src */
279                            len);                                                                    /* length */
280
281                 mve_audio_curbuf_curpos += len;                                                 /* advance input */
282                 stream += len;                                                                  /* advance output (unnecessary) */
283                 len -= len;                                                                     /* advance output (unnecessary) */
284
285                 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead])            /* if this ends the current chunk */
286                 {
287                         mve_free(mve_audio_buffers[mve_audio_bufhead]);                             /* free buffer */
288                         mve_audio_buffers[mve_audio_bufhead]=NULL;
289                         mve_audio_buflens[mve_audio_bufhead]=0;
290
291                         if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS)                             /* next buffer */
292                                 mve_audio_bufhead = 0;
293                         mve_audio_curbuf_curpos = 0;
294                 }
295         }
296
297         //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
298 }
299 #endif
300
301 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
302 {
303 #ifdef AUDIO
304         int flags;
305         int sample_rate;
306         int desired_buffer;
307
308         int stereo;
309         int bitsize;
310         int compressed;
311
312         int format;
313
314         if (!mve_audio_enabled)
315                 return 1;
316
317         if (audiobuf_created)
318                 return 1;
319         else
320                 audiobuf_created = 1;
321
322         flags = get_ushort(data + 2);
323         sample_rate = get_ushort(data + 4);
324         desired_buffer = get_int(data + 6);
325
326         stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
327         bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
328
329         if (minor > 0) {
330                 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
331         } else {
332                 compressed = 0;
333         }
334
335         mve_audio_compressed = compressed;
336
337         if (bitsize == 1) {
338 #ifdef WORDS_BIGENDIAN
339                 format = AUDIO_S16MSB;
340 #else
341                 format = AUDIO_S16LSB;
342 #endif
343         } else {
344                 format = AUDIO_U8;
345         }
346
347         fprintf(stderr, "creating audio buffers:\n");
348         fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
349                         sample_rate, stereo, bitsize ? 16 : 8, compressed);
350
351         if (Mix_OpenAudio(sample_rate, format, stereo ? 2 : 1, 4096) == 0)
352         {
353                 fprintf(stderr, "   success\n");
354                 mve_audio_canplay = 1;
355         }
356         else
357         {
358                 fprintf(stderr, "   failure : %s\n", Mix_GetError());
359                 mve_audio_canplay = 0;
360         }
361
362         Mix_SetPostMix(mve_audio_callback, NULL);
363         mve_audio_canplay = 1;
364
365         memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
366         memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
367 #endif
368
369         return 1;
370 }
371
372 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
373 {
374 #ifdef AUDIO
375         if (mve_audio_canplay  &&  !mve_audio_playing  &&  mve_audio_bufhead != mve_audio_buftail)
376         {
377                 Mix_Resume(-1);
378                 mve_audio_playing = 1;
379         }
380 #endif
381         return 1;
382 }
383
384 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
385 {
386 #ifdef AUDIO
387         static const int selected_chan=1;
388         int chan;
389         int nsamp;
390         if (mve_audio_canplay)
391         {
392                 chan = get_ushort(data + 2);
393                 nsamp = get_ushort(data + 4);
394                 if (chan & selected_chan)
395                 {
396                         /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
397                         if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
398                                 if (mve_audio_compressed) {
399                                         nsamp += 4;
400
401                                         mve_audio_buflens[mve_audio_buftail] = nsamp;
402                                         mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
403                                         mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
404                                 } else {
405                                         nsamp -= 8;
406                                         data += 8;
407
408                                         mve_audio_buflens[mve_audio_buftail] = nsamp;
409                                         mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
410                                         memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
411                                 }
412                         } else {
413                                 mve_audio_buflens[mve_audio_buftail] = nsamp;
414                                 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
415
416                                 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
417                         }
418
419                         if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
420                                 mve_audio_buftail = 0;
421
422                         if (mve_audio_buftail == mve_audio_bufhead)
423                                 fprintf(stderr, "d'oh!  buffer ring overrun (%d)\n", mve_audio_bufhead);
424                 }
425         }
426 #endif
427
428         return 1;
429 }
430
431 /*************************
432  * video handlers
433  *************************/
434
435 static int videobuf_created = 0;
436 static int video_initialized = 0;
437 int g_width, g_height;
438 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
439
440 static int g_destX, g_destY;
441 static int g_screenWidth, g_screenHeight;
442 static unsigned char *g_pCurMap=NULL;
443 static int g_nMapLength=0;
444 static int g_truecolor;
445
446 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
447 {
448         short w, h;
449         short count, truecolor;
450
451         if (videobuf_created)
452                 return 1;
453         else
454                 videobuf_created = 1;
455
456         w = get_short(data);
457         h = get_short(data+2);
458
459         if (minor > 0) {
460                 count = get_short(data+4);
461         } else {
462                 count = 1;
463         }
464
465         if (minor > 1) {
466                 truecolor = get_short(data+6);
467         } else {
468                 truecolor = 0;
469         }
470
471         g_width = w << 3;
472         g_height = h << 3;
473
474         /* TODO: * 4 causes crashes on some files */
475         /* only malloc once */
476         if (g_vBuffers == NULL)
477                 g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
478         if (truecolor) {
479                 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
480         } else {
481                 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
482         }
483
484         memset(g_vBackBuf1, 0, g_width * g_height * 4);
485
486 #ifdef DEBUG
487         fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
488 #endif
489
490         g_truecolor = truecolor;
491
492         return 1;
493 }
494
495 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
496 {
497         if (g_destX == -1) // center it
498                 g_destX = (g_screenWidth - g_width) >> 1;
499         if (g_destY == -1) // center it
500                 g_destY = (g_screenHeight - g_height) >> 1;
501
502         mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
503                       g_width, g_height, g_destX, g_destY);
504
505         g_frameUpdated = 1;
506
507         return 1;
508 }
509
510 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
511 {
512         short width, height;
513
514         if (video_initialized)
515                 return 1; /* maybe we actually need to change width/height here? */
516         else
517                 video_initialized = 1;
518
519         width = get_short(data);
520         height = get_short(data+2);
521         g_screenWidth = width;
522         g_screenHeight = height;
523
524         return 1;
525 }
526
527 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
528 {
529         short start, count;
530         unsigned char *p;
531
532         start = get_short(data);
533         count = get_short(data+2);
534
535         p = data + 4;
536
537         mve_setpalette(p - 3*start, start, count);
538
539         return 1;
540 }
541
542 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
543 {
544         g_pCurMap = data;
545         g_nMapLength = len;
546         return 1;
547 }
548
549 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
550 {
551         short nFrameHot, nFrameCold;
552         short nXoffset, nYoffset;
553         short nXsize, nYsize;
554         unsigned short nFlags;
555         unsigned char *temp;
556
557         nFrameHot  = get_short(data);
558         nFrameCold = get_short(data+2);
559         nXoffset   = get_short(data+4);
560         nYoffset   = get_short(data+6);
561         nXsize     = get_short(data+8);
562         nYsize     = get_short(data+10);
563         nFlags     = get_ushort(data+12);
564
565         if (nFlags & 1)
566         {
567                 temp = (unsigned char *)g_vBackBuf1;
568                 g_vBackBuf1 = g_vBackBuf2;
569                 g_vBackBuf2 = temp;
570         }
571
572         /* convert the frame */
573         if (g_truecolor) {
574                 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
575         } else {
576                 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
577         }
578
579         return 1;
580 }
581
582 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
583 {
584         g_pCurMap=NULL;
585         return 1;
586 }
587
588
589 static MVESTREAM *mve = NULL;
590
591 void MVE_ioCallbacks(mve_cb_Read io_read)
592 {
593         mve_read = io_read;
594 }
595
596 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
597 {
598         mve_alloc = mem_alloc;
599         mve_free = mem_free;
600 }
601
602 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
603 {
604         mve_showframe = showframe;
605 }
606
607 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
608 {
609         mve_setpalette = setpalette;
610 }
611
612 int MVE_rmPrepMovie(void *src, int x, int y, int track)
613 {
614         int i;
615
616         if (mve) {
617                 mve_reset(mve);
618                 return 0;
619         }
620
621         mve = mve_open(src);
622
623         if (!mve)
624                 return 1;
625
626         g_destX = x;
627         g_destY = y;
628
629         for (i = 0; i < 32; i++)
630                 mve_set_handler(mve, i, default_seg_handler);
631
632         mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM,          end_movie_handler);
633         mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK,           end_chunk_handler);
634         mve_set_handler(mve, MVE_OPCODE_CREATETIMER,          create_timer_handler);
635         mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS,     create_audiobuf_handler);
636         mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO,       play_audio_handler);
637         mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS,     create_videobuf_handler);
638
639         mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO,         display_video_handler);
640         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA,       audio_data_handler);
641         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE,    audio_data_handler);
642         mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE,        init_video_handler);
643
644         mve_set_handler(mve, MVE_OPCODE_SETPALETTE,           video_palette_handler);
645         mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
646
647         mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP,       video_codemap_handler);
648
649         mve_set_handler(mve, MVE_OPCODE_VIDEODATA,            video_data_handler);
650
651         mve_play_next_chunk(mve); /* video initialization chunk */
652         if (mve_audio_enabled)
653                 mve_play_next_chunk(mve); /* audio initialization chunk */
654
655         return 0;
656 }
657
658
659 void MVE_getVideoSpec(MVE_videoSpec *vSpec)
660 {
661         vSpec->screenWidth = g_screenWidth;
662         vSpec->screenHeight = g_screenHeight;
663         vSpec->width = g_width;
664         vSpec->height = g_height;
665         vSpec->truecolor = g_truecolor;
666 }
667
668
669 int MVE_rmStepMovie()
670 {
671         static int init_timer=0;
672         int cont=1;
673
674         if (!timer_started)
675                 timer_start();
676
677         while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
678                 cont = mve_play_next_chunk(mve);
679         g_frameUpdated = 0;
680
681         if (!cont)
682                 return MVE_ERR_EOF;
683
684         if (micro_frame_delay  && !init_timer) {
685                 timer_start();
686                 init_timer = 1;
687         }
688
689         do_timer_wait();
690
691         return 0;
692 }
693
694 void MVE_rmEndMovie()
695 {
696 #ifdef AUDIO
697         int i;
698 #endif
699
700         timer_stop();
701         timer_created = 0;
702
703 #ifdef AUDIO
704         if (mve_audio_canplay) {
705                 // only close audio if we opened it
706                 Mix_CloseAudio();
707                 mve_audio_canplay = 0;
708         }
709         for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
710                 if (mve_audio_buffers[i] != NULL)
711                         mve_free(mve_audio_buffers[i]);
712         memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
713         memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
714         mve_audio_curbuf_curpos=0;
715         mve_audio_bufhead=0;
716         mve_audio_buftail=0;
717         mve_audio_playing=0;
718         mve_audio_canplay=0;
719         mve_audio_compressed=0;
720         audiobuf_created = 0;
721 #endif
722
723         mve_free(g_vBuffers);
724         g_vBuffers = NULL;
725         g_pCurMap=NULL;
726         g_nMapLength=0;
727         videobuf_created = 0;
728         video_initialized = 0;
729
730         mve_close(mve);
731         mve = NULL;
732 }
733
734
735 void MVE_rmHoldMovie()
736 {
737         timer_started = 0;
738 }
739
740
741 void MVE_sndInit(int x)
742 {
743 #ifdef AUDIO
744         if (x == -1)
745                 mve_audio_enabled = 0;
746         else
747                 mve_audio_enabled = 1;
748 #endif
749 }