21 # include <sys/time.h>
22 # include <sys/types.h>
23 # include <sys/stat.h>
30 #include "SDL_mixer.h"
34 #include "mve_audio.h"
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
47 #define MVE_OPCODE_DISPLAYVIDEO 0x07
48 #define MVE_OPCODE_AUDIOFRAMEDATA 0x08
49 #define MVE_OPCODE_AUDIOFRAMESILENCE 0x09
50 #define MVE_OPCODE_INITVIDEOMODE 0x0A
52 #define MVE_OPCODE_SETPALETTE 0x0C
53 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
55 #define MVE_OPCODE_SETDECODINGMAP 0x0F
57 #define MVE_OPCODE_VIDEODATA 0x11
59 #define MVE_AUDIO_FLAGS_STEREO 1
60 #define MVE_AUDIO_FLAGS_16BIT 2
61 #define MVE_AUDIO_FLAGS_COMPRESSED 4
64 static int g_spdFactorDenom=10;
65 static int g_frameUpdated = 0;
67 static short get_short(unsigned char *data)
70 value = data[0] | (data[1] << 8);
74 static unsigned short get_ushort(unsigned char *data)
77 value = data[0] | (data[1] << 8);
81 static int get_int(unsigned char *data)
84 value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
88 static unsigned int unhandled_chunks[32*256];
90 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
92 unhandled_chunks[major<<8|minor]++;
93 //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
98 /*************************
100 *************************/
101 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
106 /*************************
108 *************************/
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;
118 #if defined(_WIN32) || defined(macintosh)
120 unsigned long int timer_getmicroseconds()
122 static int counter = 0;
124 DWORD now = GetTickCount();
126 long now = TickCount();
130 return now * 1000 + counter;
135 unsigned long int timer_getmicroseconds()
138 static time_t starttime = 0;
140 gettimeofday(&tv, NULL);
143 starttime = tv.tv_sec;
145 return (tv.tv_sec - starttime) * 1000000 + tv.tv_usec;
150 void timer_sleepmicroseconds(unsigned long int usec)
154 #elif defined(macintosh)
158 ts.tv_sec = usec / 1000000;
159 ts.tv_nsec = usec % 1000000 * 1000;
160 nanosleep(&ts, NULL);
164 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
167 #if !defined(_WIN32) && !defined(macintosh) // FIXME
168 __extension__ long long temp;
178 micro_frame_delay = get_int(data) * (int)get_short(data+4);
179 if (g_spdFactorNum != 0)
181 temp = micro_frame_delay;
182 temp *= g_spdFactorNum;
183 temp /= g_spdFactorDenom;
184 micro_frame_delay = (int)temp;
190 static void timer_stop(void)
196 static void timer_start(void)
198 timer_expire = timer_getmicroseconds();
199 timer_expire += micro_frame_delay;
203 static void do_timer_wait(void)
205 unsigned long int ts;
206 unsigned long int tv;
211 tv = timer_getmicroseconds();
212 if (tv > timer_expire)
215 ts = timer_expire - tv;
217 timer_sleepmicroseconds(ts);
220 timer_expire += micro_frame_delay;
223 /*************************
225 *************************/
227 #define TOTAL_AUDIO_BUFFERS 64
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;
242 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
246 if (mve_audio_bufhead == mve_audio_buftail)
249 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
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 */
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 */
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 */
266 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
267 mve_audio_bufhead = 0;
268 mve_audio_curbuf_curpos = 0;
271 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
274 if (len != 0 /* ospace remaining */
275 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
277 memcpy(stream, /* dest */
278 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
281 mve_audio_curbuf_curpos += len; /* advance input */
282 stream += len; /* advance output (unnecessary) */
283 len -= len; /* advance output (unnecessary) */
285 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
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;
291 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
292 mve_audio_bufhead = 0;
293 mve_audio_curbuf_curpos = 0;
297 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
301 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
314 if (!mve_audio_enabled)
317 if (audiobuf_created)
320 audiobuf_created = 1;
322 flags = get_ushort(data + 2);
323 sample_rate = get_ushort(data + 4);
324 desired_buffer = get_int(data + 6);
326 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
327 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
330 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
335 mve_audio_compressed = compressed;
338 #ifdef WORDS_BIGENDIAN
339 format = AUDIO_S16MSB;
341 format = AUDIO_S16LSB;
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);
351 if (Mix_OpenAudio(sample_rate, format, stereo ? 2 : 1, 4096) == 0)
353 fprintf(stderr, " success\n");
354 mve_audio_canplay = 1;
358 fprintf(stderr, " failure : %s\n", Mix_GetError());
359 mve_audio_canplay = 0;
362 Mix_SetPostMix(mve_audio_callback, NULL);
363 mve_audio_canplay = 1;
365 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
366 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
372 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
375 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
378 mve_audio_playing = 1;
384 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
387 static const int selected_chan=1;
390 if (mve_audio_canplay)
392 chan = get_ushort(data + 2);
393 nsamp = get_ushort(data + 4);
394 if (chan & selected_chan)
396 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
397 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
398 if (mve_audio_compressed) {
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 */
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);
413 mve_audio_buflens[mve_audio_buftail] = nsamp;
414 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
416 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
419 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
420 mve_audio_buftail = 0;
422 if (mve_audio_buftail == mve_audio_bufhead)
423 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
431 /*************************
433 *************************/
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;
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;
446 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
449 short count, truecolor;
451 if (videobuf_created)
454 videobuf_created = 1;
457 h = get_short(data+2);
460 count = get_short(data+4);
466 truecolor = get_short(data+6);
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);
479 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
481 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
484 memset(g_vBackBuf1, 0, g_width * g_height * 4);
487 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
490 g_truecolor = truecolor;
495 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
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;
502 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
503 g_width, g_height, g_destX, g_destY);
510 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
514 if (video_initialized)
515 return 1; /* maybe we actually need to change width/height here? */
517 video_initialized = 1;
519 width = get_short(data);
520 height = get_short(data+2);
521 g_screenWidth = width;
522 g_screenHeight = height;
527 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
532 start = get_short(data);
533 count = get_short(data+2);
537 mve_setpalette(p - 3*start, start, count);
542 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
549 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
551 short nFrameHot, nFrameCold;
552 short nXoffset, nYoffset;
553 short nXsize, nYsize;
554 unsigned short nFlags;
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);
567 temp = (unsigned char *)g_vBackBuf1;
568 g_vBackBuf1 = g_vBackBuf2;
572 /* convert the frame */
574 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
576 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
582 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
589 static MVESTREAM *mve = NULL;
591 void MVE_ioCallbacks(mve_cb_Read io_read)
596 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
598 mve_alloc = mem_alloc;
602 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
604 mve_showframe = showframe;
607 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
609 mve_setpalette = setpalette;
612 int MVE_rmPrepMovie(void *src, int x, int y, int track)
629 for (i = 0; i < 32; i++)
630 mve_set_handler(mve, i, default_seg_handler);
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);
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);
644 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
645 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
647 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
649 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
651 mve_play_next_chunk(mve); /* video initialization chunk */
652 if (mve_audio_enabled)
653 mve_play_next_chunk(mve); /* audio initialization chunk */
659 void MVE_getVideoSpec(MVE_videoSpec *vSpec)
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;
669 int MVE_rmStepMovie()
671 static int init_timer=0;
677 while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
678 cont = mve_play_next_chunk(mve);
684 if (micro_frame_delay && !init_timer) {
694 void MVE_rmEndMovie()
704 if (mve_audio_canplay) {
705 // only close audio if we opened it
707 mve_audio_canplay = 0;
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;
719 mve_audio_compressed=0;
720 audiobuf_created = 0;
723 mve_free(g_vBuffers);
727 videobuf_created = 0;
728 video_initialized = 0;
735 void MVE_rmHoldMovie()
741 void MVE_sndInit(int x)
745 mve_audio_enabled = 0;
747 mve_audio_enabled = 1;