diff -NaHudr a/config.h b/config.h --- a/config.h 2006-08-14 02:09:28.000000000 +0300 +++ b/config.h 2006-08-14 02:33:44.000000000 +0300 @@ -2,7 +2,7 @@ #define CONFIG_H #undef WITH_HOME -#undef VCR_SUPPORT +#define VCR_SUPPORT #define GTK2_SUPPORT 1 #endif /* CONFIG_H */ diff -NaHudr a/config.log b/config.log --- a/config.log 1970-01-01 02:00:00.000000000 +0200 +++ b/config.log 2006-08-14 02:33:41.000000000 +0300 @@ -0,0 +1,2 @@ +Mon Aug 14 02:37:26 EEST 2006 +Everything ok diff -NaHudr a/main/gui_gtk/main_gtk.c b/main/gui_gtk/main_gtk.c --- a/main/gui_gtk/main_gtk.c 2006-08-14 02:09:26.000000000 +0300 +++ b/main/gui_gtk/main_gtk.c 2006-08-14 02:07:04.000000000 +0300 @@ -828,7 +828,7 @@ // really hide dialog (let gtk work) while( g_main_iteration( FALSE ) ); - if (VCR_startRecord( filename, false, NULL, NULL ) < 0) + if (VCR_startRecord( filename, 0, NULL, NULL ) < 0) messagebox( tr( "VCR" ), MB_ICONERROR | MB_OK, tr( "Couldn't start recording." ) ); } diff -NaHudr a/main/nesvideos-piece.c b/main/nesvideos-piece.c --- a/main/nesvideos-piece.c 2006-08-14 02:09:26.000000000 +0300 +++ b/main/nesvideos-piece.c 1970-01-01 02:00:00.000000000 +0200 @@ -1,516 +0,0 @@ -#include -#include -#include -//#include - -/* Note: This module assumes everyone uses RGB15 as display depth */ - -static const char* VIDEO_CMD = - "mencoder - -o test0.avi" - " -noskip -mc 0" - " -ovc lavc" - " -oac mp3lame" - " -lameopts preset=256:aq=2:mode=3" - " -lavcopts vcodec=ffv1:context=0:format=BGR32:coder=0:vstrict=-1" - " >& mencoder.log"; - -static void FlushWrite(FILE* fp, const unsigned char*buf, unsigned length); - -#define BGR24 (0x42475218) // BGR24 fourcc -#define BGR16 (0x42475210) // BGR16 fourcc -#define BGR15 (0x4247520F) // BGR15 fourcc - -static FILE* (*openFunc) (const char*, const char*) = NULL; -static int (*closeFunc) (FILE*) = NULL; - -#ifdef __WIN32__ - #include - #define popen _popen; - #define pclose _pclose; -#endif - -#define u32(n) (n)&255,((n)>>8)&255,((n)>>16)&255,((n)>>24)&255 -#define u16(n) (n)&255,((n)>>8)&255 -#define s4(s) s[0],s[1],s[2],s[3] - -static const unsigned FPS_SCALE = (0x1000000); - -// general-purpose A/V sync debugging, ignored unless explicitly enabled with NESVideoEnableDebugging -static void (*debugVideoMessageFunc)(const char *msg) = NULL; -static void (*debugAudioMessageFunc)(const char *msg) = NULL; -static unsigned audioFramesWritten=0, videoFramesWritten=1; // logo adds 1 "frame" to audio, so offset that (A/V frames shouldn't necessarily match up depending on the rates, but should at least make them start out matching in case they do) -static double audioSecondsWritten=0, videoSecondsWritten=0; - - -static struct -{ - FILE* avifp; - - char KnowVideo; - unsigned width; - unsigned height; - unsigned fps_scaled; - unsigned char* VideoBuffer; - - char KnowAudio; - unsigned rate; - unsigned chans; - unsigned bits; - unsigned char* AudioBuffer; - -//public: - void Create() - { - avifp = NULL; - KnowVideo = FALSE; - KnowAudio = FALSE; - } - void Destruct() - { - if(avifp) - closeFunc(avifp); - } - - void Audio(unsigned r,unsigned b,unsigned c, - const unsigned char*d, unsigned nsamples) - { - if(!KnowAudio) - { - rate = r; - chans = c; - bits = b; - KnowAudio = true; - CheckFlushing(); - } - unsigned bytes = nsamples*chans*(bits/8); - - if(debugAudioMessageFunc) - { - audioFramesWritten++; - audioSecondsWritten += (double)nsamples / (double)rate; // += bytes times seconds per byte - char temp [64]; - sprintf(temp, "A: %.2lf s, %d f", audioSecondsWritten, audioFramesWritten); - debugAudioMessageFunc(temp); - } - - if(KnowVideo) - SendAudioFrame(d, bytes); - else - { - AudioBuffer.insert(AudioBuffer.end(), d, d+bytes); - fprintf(stderr, "Buffering %u bytes of audio\n", bytes); - } - } - void Video(unsigned w,unsigned h,unsigned f, const unsigned char*d) - { - if(!KnowVideo) - { - width=w; - height=h; - fps_scaled=f; - KnowVideo = true; - CheckFlushing(); - } - - unsigned bytes = width*height*2; - - //std::vector tmp(bytes, 'k'); - //d = &tmp[0]; - - if(debugVideoMessageFunc) - { - videoFramesWritten++; - videoSecondsWritten += (double)FPS_SCALE / (double)fps_scaled; // += seconds per frame - char temp [64]; - sprintf(temp, "V: %.2lf s, %d f", videoSecondsWritten, videoFramesWritten); - debugVideoMessageFunc(temp); - } - - if(KnowAudio) - SendVideoFrame(d, bytes); - else - { - VideoBuffer.insert(VideoBuffer.end(), d, d+bytes); - fprintf(stderr, "Buffering %u bytes of video\n", bytes); - } - } - -private: - void CheckFlushing() - { - //AudioBuffer.clear(); - //VideoBuffer.clear(); - - if(KnowAudio && KnowVideo) - { - unsigned last_offs; - - // Flush Audio - - last_offs = 0; - while(last_offs < AudioBuffer.size()) - { - unsigned bytes = rate / (fps_scaled / FPS_SCALE); - bytes *= chans*(bits/8); - - unsigned remain = AudioBuffer.size() - last_offs; - if(bytes > remain) bytes = remain; - if(!bytes) break; - - unsigned begin = last_offs; - last_offs += bytes; - SendAudioFrame(&AudioBuffer[begin], bytes); - } - AudioBuffer.erase(AudioBuffer.begin(), AudioBuffer.begin()+last_offs); - - // Flush Video - - last_offs = 0; - while(last_offs < VideoBuffer.size()) - { - unsigned bytes = width*height*2; - unsigned remain = VideoBuffer.size() - last_offs; - if(bytes > remain) bytes = remain; - if(!bytes)break; - - unsigned begin = last_offs; - last_offs += bytes; - SendVideoFrame(&VideoBuffer[begin], bytes); - } - VideoBuffer.erase(VideoBuffer.begin(), VideoBuffer.begin()+last_offs); - } - } - - void SendVideoFrame(const unsigned char* vidbuf, unsigned framesize) - { - CheckBegin(); - - //fprintf(stderr, "Writing 00dc of %u bytes\n", framesize); - - const unsigned char header[] = { s4("00dc"), u32(framesize) }; - FlushWrite(avifp, header, sizeof(header)); - FlushWrite(avifp, vidbuf, framesize); - } - - void SendAudioFrame(const unsigned char* audbuf, unsigned framesize) - { - CheckBegin(); - - //fprintf(stderr, "Writing 01wb of %u bytes\n", framesize); - - const unsigned char header[] = { s4("01wb"), u32(framesize) }; - FlushWrite(avifp, header, sizeof(header)); - FlushWrite(avifp, audbuf, framesize); - } - - void CheckBegin() - { - if(avifp) return; - - if(!openFunc) openFunc = popen; // default - if(!closeFunc) closeFunc = pclose; // default - - avifp = openFunc(VIDEO_CMD.c_str(), "wb"); - if(!avifp) return; - - const unsigned fourcc = BGR16; - const unsigned framesize = width*height*2; - - const unsigned aud_rate = rate; - const unsigned aud_chans = chans; - const unsigned aud_bits = bits; - - const unsigned nframes = 0; //unknown - const unsigned scale = FPS_SCALE; - const unsigned scaled_fps = fps_scaled; - - const unsigned SIZE_strh_vids = 4 + 4*2 + 2*2 + 8*4 + 2*4; - const unsigned SIZE_strf_vids = 4*3 + 2*2 + 4*6; - const unsigned SIZE_strl_vids = 4+ 4+(4+SIZE_strh_vids) + 4+(4+SIZE_strf_vids); - - const unsigned SIZE_strh_auds = 4 + 4*3 + 2*2 + 4*8 + 2*4; - const unsigned SIZE_strf_auds = 2*2 + 4*2 + 2*3; - const unsigned SIZE_strl_auds = 4+ 4+(4+SIZE_strh_auds) + 4+(4+SIZE_strf_auds); - - const unsigned SIZE_avih = 4*12; - const unsigned SIZE_hdrl = 4+4+ (4+SIZE_avih) + 4 + (4+SIZE_strl_vids) + 4 + (4+SIZE_strl_auds); - const unsigned SIZE_movi = 4 + nframes*(4+4+framesize); - const unsigned SIZE_avi = 4+4+ (4+SIZE_hdrl) + 4 + (4+SIZE_movi); - - const unsigned char AVIheader[] = - { - s4("RIFF"), - u32(SIZE_avi), - s4("AVI "), - - // HEADER - - s4("LIST"), - u32(SIZE_hdrl), - s4("hdrl"), - - s4("avih"), - u32(SIZE_avih), - u32(0), - u32(0), - u32(0), - u32(0), - u32(nframes), - u32(0), - u32(2), // two streams - u32(0), - u32(0), - u32(0), - u32(0), - u32(0), - - // VIDEO HEADER - - s4("LIST"), - u32(SIZE_strl_vids), - s4("strl"), - - s4("strh"), - u32(SIZE_strh_vids), - s4("vids"), - u32(0), - u32(0), - u16(0), - u16(0), - u32(0), - u32(scale), - u32(scaled_fps), - u32(0), - u32(0), - u32(0), - u32(0), - u32(0), - u16(0), - u16(0), - u16(0), - u16(0), - - s4("strf"), - u32(SIZE_strf_vids), - u32(0), - u32(width), - u32(height), - u16(0), - u16(0), - u32(fourcc), - u32(0), - u32(0), - u32(0), - u32(0), - u32(0), - - // AUDIO HEADER - - s4("LIST"), - u32(SIZE_strl_auds), - s4("strl"), - - s4("strh"), - u32(SIZE_strh_auds), - s4("auds"), - u32(0), //fourcc - u32(0), //handler - u32(0), //flags - u16(0), //prio - u16(0), //lang - u32(0), //init frames - u32(1), //scale - u32(aud_rate), - u32(0), //start - u32(0), //rate*length - u32(1048576), //suggested bufsize - u32(0), //quality - u32(aud_chans * (aud_bits / 8)), //sample size - u16(0), //frame size - u16(0), - u16(0), - u16(0), - - s4("strf"), - u32(SIZE_strf_auds), - u16(1), // pcm format - u16(aud_chans), - u32(aud_rate), - u32(aud_rate * aud_chans * (aud_bits/8)), // samples per second - u16(aud_chans * (aud_bits/8)), //block align - u16(aud_bits), //bits - u16(0), //cbSize - - // MOVIE - - s4("LIST"), - u32(SIZE_movi), - s4("movi") - }; - - FlushWrite(avifp, AVIheader, sizeof(AVIheader)); - } -} AVI; - -extern "C" -{ - int LoggingEnabled = 0; /* 0=no, 1=yes, 2=recording! */ - - const char* NESVideoGetVideoCmd() - { - return VIDEO_CMD.c_str(); - } - void NESVideoSetVideoCmd(const char *cmd) - { - VIDEO_CMD = cmd; - } - void NESVideoEnableDebugging( void videoMessageFunc(const char *msg), void audioMessageFunc(const char *msg) ) - { - debugVideoMessageFunc = videoMessageFunc; - debugAudioMessageFunc = audioMessageFunc; - } - void NESVideoSetFileFuncs( FILE* open(const char *,const char *), int close(FILE*) ) - { - openFunc = open; - closeFunc = close; - } - - void NESVideoLoggingVideo - (const void*data, unsigned width,unsigned height, - unsigned fps_scaled - ) - { - if(LoggingEnabled < 2) return; - - unsigned LogoFrames = fps_scaled >> 24; - - static bool First = true; - if(First) - { - First=false; - /* Bisqwit's logo addition routine. */ - /* If you don't have his files, this function does nothing - * and it does not matter at all. - */ - - const char *background = - width==320 ? "logo320_240" - : width==160 ? "logo160_144" - : width==240 ? "logo240_160" - : height>224 ? "logo256_240" - : "logo256_224"; - - /* Note: This should be 1 second long. */ - for(unsigned frame = 0; frame < LogoFrames; ++frame) - { - char Buf[4096]; - sprintf(Buf, "/shares/home/bisqwit/povray/nesvlogo/%s_f%u.tga", - background, frame); - - FILE*fp = fopen(Buf, "rb"); - if(!fp) // write blackness when missing frames to keep the intro 1 second long: - { - unsigned bytes = width*height*2; - unsigned char* buf = (unsigned char*)malloc(bytes); - if(buf) - { - memset(buf,0,bytes); - AVI.Video(width,height,fps_scaled, buf); - if(debugVideoMessageFunc) videoFramesWritten--; - free(buf); - } - } - else // write 1 frame of the logo: - { - int idlen = fgetc(fp); - /* Silently ignore all other header data. - * These files are assumed to be uncompressed BGR24 tga files with Y swapped. - * Even their geometry is assumed to match perfectly. - */ - fseek(fp, 1+1+2+2+1+ /*org*/2+2+ /*geo*/2+2+ 1+1+idlen, SEEK_CUR); - - bool yflip=true; - std::vector data(width*height*3); - for(unsigned y=height; y-->0; ) - fread(&data[y*width*3], 1, width*3, fp); - fclose(fp); - - std::vector result(width*height); - for(unsigned pos=0, max=result.size(); pos 0) - { - unsigned bytes = n*chans*(bits/8); - unsigned char* buf = (unsigned char*)malloc(bytes); - if(buf) - { - memset(buf,0,bytes); - AVI.Audio(rate,bits,chans, buf, n); - free(buf); - } - } - } - - AVI.Audio(rate,bits,chans, (const unsigned char*) data, nsamples); - } -} /* extern "C" */ - - - -static void FlushWrite(FILE* fp, const unsigned char*buf, unsigned length) -{ -/// unsigned failures = 0; -/// const static int FAILURE_THRESH = 8092; // don't want to loop infinitely if we keep failing to make progress - actually maybe you would want this, so the checking is disabled - while(length > 0 /*&& failures < FAILURE_THRESH*/) - { - unsigned written = fwrite(buf, 1, length, fp); -/// if(written == 0) -/// failures++; -/// else -/// { - length -= written; - buf += written; -/// failures = 0; -/// } - } -/// if(failures >= FAILURE_THRESH) -/// { -/// fprintf(stderr, "FlushWrite() failed to write %d bytes %d times - giving up.", length, failures); -/// LoggingEnabled = 0; -/// } -} diff -NaHudr a/main/nesvideos-piece.cpp b/main/nesvideos-piece.cpp --- a/main/nesvideos-piece.cpp 2006-08-14 02:09:27.000000000 +0300 +++ b/main/nesvideos-piece.cpp 1970-01-01 02:00:00.000000000 +0200 @@ -1,502 +0,0 @@ -/* -#include -#include -#include -#include - -// Note: This module assumes everyone uses RGB15 as display depth - -static std::string VIDEO_CMD = - "mencoder - -o test0.avi" - " -noskip -mc 0" - " -ovc lavc" - " -oac mp3lame" - " -lameopts preset=256:aq=2:mode=3" - " -lavcopts vcodec=ffv1:context=0:format=BGR32:coder=0:vstrict=-1" - " >& mencoder.log"; - -static void FlushWrite(FILE* fp, const unsigned char*buf, unsigned length); - -#define BGR24 (0x42475218) // BGR24 fourcc -#define BGR16 (0x42475210) // BGR16 fourcc -#define BGR15 (0x4247520F) // BGR15 fourcc - -static FILE* (*openFunc) (const char*, const char*) = NULL; -static int (*closeFunc) (FILE*) = NULL; - -#if (defined(WIN32) || defined(win32)) // capital is standard, but check for either - #include - #define popen _popen; - #define pclose _pclose; -#endif - -#define u32(n) (n)&255,((n)>>8)&255,((n)>>16)&255,((n)>>24)&255 -#define u16(n) (n)&255,((n)>>8)&255 -#define s4(s) s[0],s[1],s[2],s[3] - -static const unsigned FPS_SCALE = (0x1000000); - -// general-purpose A/V sync debugging, ignored unless explicitly enabled with NESVideoEnableDebugging -static void (*debugVideoMessageFunc)(const char *msg) = NULL; -static void (*debugAudioMessageFunc)(const char *msg) = NULL; -static unsigned audioFramesWritten=0, videoFramesWritten=1; // logo adds 1 "frame" to audio, so offset that (A/V frames shouldn't necessarily match up depending on the rates, but should at least make them start out matching in case they do) -static double audioSecondsWritten=0, videoSecondsWritten=0; - - -static class AVI -{ - FILE* avifp; - - bool KnowVideo; - unsigned width; - unsigned height; - unsigned fps_scaled; - std::vector VideoBuffer; - - bool KnowAudio; - unsigned rate; - unsigned chans; - unsigned bits; - std::vector AudioBuffer; - -public: - AVI() : - avifp(NULL), - KnowVideo(false), - KnowAudio(false) - { - } - ~AVI() - { - if(avifp) closeFunc(avifp); - } - - void Audio(unsigned r,unsigned b,unsigned c, - const unsigned char*d, unsigned nsamples) - { - if(!KnowAudio) - { - rate = r; - chans = c; - bits = b; - KnowAudio = true; - CheckFlushing(); - } - unsigned bytes = nsamples*chans*(bits/8); - - if(debugAudioMessageFunc) - { - audioFramesWritten++; - audioSecondsWritten += (double)nsamples / (double)rate; // += bytes times seconds per byte - char temp [64]; - sprintf(temp, "A: %.2lf s, %d f", audioSecondsWritten, audioFramesWritten); - debugAudioMessageFunc(temp); - } - - if(KnowVideo) - SendAudioFrame(d, bytes); - else - { - AudioBuffer.insert(AudioBuffer.end(), d, d+bytes); - fprintf(stderr, "Buffering %u bytes of audio\n", bytes); - } - } - void Video(unsigned w,unsigned h,unsigned f, const unsigned char*d) - { - if(!KnowVideo) - { - width=w; - height=h; - fps_scaled=f; - KnowVideo = true; - CheckFlushing(); - } - - unsigned bytes = width*height*2; - - //std::vector tmp(bytes, 'k'); - //d = &tmp[0]; - - if(debugVideoMessageFunc) - { - videoFramesWritten++; - videoSecondsWritten += (double)FPS_SCALE / (double)fps_scaled; // += seconds per frame - char temp [64]; - sprintf(temp, "V: %.2lf s, %d f", videoSecondsWritten, videoFramesWritten); - debugVideoMessageFunc(temp); - } - - if(KnowAudio) - SendVideoFrame(d, bytes); - else - { - VideoBuffer.insert(VideoBuffer.end(), d, d+bytes); - fprintf(stderr, "Buffering %u bytes of video\n", bytes); - } - } - -private: - void CheckFlushing() - { - //AudioBuffer.clear(); - //VideoBuffer.clear(); - - if(KnowAudio && KnowVideo) - { - unsigned last_offs; - - // Flush Audio - - last_offs = 0; - while(last_offs < AudioBuffer.size()) - { - unsigned bytes = rate / (fps_scaled / FPS_SCALE); - bytes *= chans*(bits/8); - - unsigned remain = AudioBuffer.size() - last_offs; - if(bytes > remain) bytes = remain; - if(!bytes) break; - - unsigned begin = last_offs; - last_offs += bytes; - SendAudioFrame(&AudioBuffer[begin], bytes); - } - AudioBuffer.erase(AudioBuffer.begin(), AudioBuffer.begin()+last_offs); - - // Flush Video - - last_offs = 0; - while(last_offs < VideoBuffer.size()) - { - unsigned bytes = width*height*2; - unsigned remain = VideoBuffer.size() - last_offs; - if(bytes > remain) bytes = remain; - if(!bytes)break; - - unsigned begin = last_offs; - last_offs += bytes; - SendVideoFrame(&VideoBuffer[begin], bytes); - } - VideoBuffer.erase(VideoBuffer.begin(), VideoBuffer.begin()+last_offs); - } - } - - void SendVideoFrame(const unsigned char* vidbuf, unsigned framesize) - { - CheckBegin(); - - //fprintf(stderr, "Writing 00dc of %u bytes\n", framesize); - - const unsigned char header[] = { s4("00dc"), u32(framesize) }; - FlushWrite(avifp, header, sizeof(header)); - FlushWrite(avifp, vidbuf, framesize); - } - - void SendAudioFrame(const unsigned char* audbuf, unsigned framesize) - { - CheckBegin(); - - //fprintf(stderr, "Writing 01wb of %u bytes\n", framesize); - - const unsigned char header[] = { s4("01wb"), u32(framesize) }; - FlushWrite(avifp, header, sizeof(header)); - FlushWrite(avifp, audbuf, framesize); - } - - void CheckBegin() - { - if(avifp) return; - - if(!openFunc) openFunc = popen; // default - if(!closeFunc) closeFunc = pclose; // default - - avifp = openFunc(VIDEO_CMD.c_str(), "wb"); - if(!avifp) return; - - const unsigned fourcc = BGR16; - const unsigned framesize = width*height*2; - - const unsigned aud_rate = rate; - const unsigned aud_chans = chans; - const unsigned aud_bits = bits; - - const unsigned nframes = 0; //unknown - const unsigned scale = FPS_SCALE; - const unsigned scaled_fps = fps_scaled; - - const unsigned SIZE_strh_vids = 4 + 4*2 + 2*2 + 8*4 + 2*4; - const unsigned SIZE_strf_vids = 4*3 + 2*2 + 4*6; - const unsigned SIZE_strl_vids = 4+ 4+(4+SIZE_strh_vids) + 4+(4+SIZE_strf_vids); - - const unsigned SIZE_strh_auds = 4 + 4*3 + 2*2 + 4*8 + 2*4; - const unsigned SIZE_strf_auds = 2*2 + 4*2 + 2*3; - const unsigned SIZE_strl_auds = 4+ 4+(4+SIZE_strh_auds) + 4+(4+SIZE_strf_auds); - - const unsigned SIZE_avih = 4*12; - const unsigned SIZE_hdrl = 4+4+ (4+SIZE_avih) + 4 + (4+SIZE_strl_vids) + 4 + (4+SIZE_strl_auds); - const unsigned SIZE_movi = 4 + nframes*(4+4+framesize); - const unsigned SIZE_avi = 4+4+ (4+SIZE_hdrl) + 4 + (4+SIZE_movi); - - const unsigned char AVIheader[] = - { - s4("RIFF"), - u32(SIZE_avi), - s4("AVI "), - - // HEADER - - s4("LIST"), - u32(SIZE_hdrl), - s4("hdrl"), - - s4("avih"), - u32(SIZE_avih), - u32(0), - u32(0), - u32(0), - u32(0), - u32(nframes), - u32(0), - u32(2), // two streams - u32(0), - u32(0), - u32(0), - u32(0), - u32(0), - - // VIDEO HEADER - - s4("LIST"), - u32(SIZE_strl_vids), - s4("strl"), - - s4("strh"), - u32(SIZE_strh_vids), - s4("vids"), - u32(0), - u32(0), - u16(0), - u16(0), - u32(0), - u32(scale), - u32(scaled_fps), - u32(0), - u32(0), - u32(0), - u32(0), - u32(0), - u16(0), - u16(0), - u16(0), - u16(0), - - s4("strf"), - u32(SIZE_strf_vids), - u32(0), - u32(width), - u32(height), - u16(0), - u16(0), - u32(fourcc), - u32(0), - u32(0), - u32(0), - u32(0), - u32(0), - - // AUDIO HEADER - - s4("LIST"), - u32(SIZE_strl_auds), - s4("strl"), - - s4("strh"), - u32(SIZE_strh_auds), - s4("auds"), - u32(0), //fourcc - u32(0), //handler - u32(0), //flags - u16(0), //prio - u16(0), //lang - u32(0), //init frames - u32(1), //scale - u32(aud_rate), - u32(0), //start - u32(0), //rate*length - u32(1048576), //suggested bufsize - u32(0), //quality - u32(aud_chans * (aud_bits / 8)), //sample size - u16(0), //frame size - u16(0), - u16(0), - u16(0), - - s4("strf"), - u32(SIZE_strf_auds), - u16(1), // pcm format - u16(aud_chans), - u32(aud_rate), - u32(aud_rate * aud_chans * (aud_bits/8)), // samples per second - u16(aud_chans * (aud_bits/8)), //block align - u16(aud_bits), //bits - u16(0), //cbSize - - // MOVIE - - s4("LIST"), - u32(SIZE_movi), - s4("movi") - }; - - FlushWrite(avifp, AVIheader, sizeof(AVIheader)); - } -} AVI; - -//extern "C" -//{ - int LoggingEnabled = 0; // 0=no, 1=yes, 2=recording! - - const char* NESVideoGetVideoCmd() - { - return VIDEO_CMD.c_str(); - } - void NESVideoSetVideoCmd(const char *cmd) - { - VIDEO_CMD = cmd; - } - void NESVideoEnableDebugging( void videoMessageFunc(const char *msg), void audioMessageFunc(const char *msg) ) - { - debugVideoMessageFunc = videoMessageFunc; - debugAudioMessageFunc = audioMessageFunc; - } - void NESVideoSetFileFuncs( FILE* open(const char *,const char *), int close(FILE*) ) - { - openFunc = open; - closeFunc = close; - } - - void NESVideoLoggingVideo - (const void*data, unsigned width,unsigned height, - unsigned fps_scaled - ) - { - if(LoggingEnabled < 2) return; - - unsigned LogoFrames = fps_scaled >> 24; - - static bool First = true; - if(First) - { - First=false; - // Bisqwit's logo addition routine. - // If you don't have his files, this function does nothing - // and it does not matter at all. - - const char *background = - width==320 ? "logo320_240" - : width==160 ? "logo160_144" - : width==240 ? "logo240_160" - : height>224 ? "logo256_240" - : "logo256_224"; - - // Note: This should be 1 second long. - for(unsigned frame = 0; frame < LogoFrames; ++frame) - { - char Buf[4096]; - sprintf(Buf, "/shares/home/bisqwit/povray/nesvlogo/%s_f%u.tga", - background, frame); - - FILE*fp = fopen(Buf, "rb"); - if(!fp) // write blackness when missing frames to keep the intro 1 second long: - { - unsigned bytes = width*height*2; - unsigned char* buf = (unsigned char*)malloc(bytes); - if(buf) - { - memset(buf,0,bytes); - AVI.Video(width,height,fps_scaled, buf); - if(debugVideoMessageFunc) videoFramesWritten--; - free(buf); - } - } - else // write 1 frame of the logo: - { - int idlen = fgetc(fp); - // Silently ignore all other header data. - // These files are assumed to be uncompressed BGR24 tga files with Y swapped. - // Even their geometry is assumed to match perfectly. - fseek(fp, 1+1+2+2+1+ 2+2+ 2+2+ 1+1+idlen, SEEK_CUR); - - bool yflip=true; - std::vector data(width*height*3); - for(unsigned y=height; y-->0; ) - fread(&data[y*width*3], 1, width*3, fp); - fclose(fp); - - std::vector result(width*height); - for(unsigned pos=0, max=result.size(); pos 0) - { - unsigned bytes = n*chans*(bits/8); - unsigned char* buf = (unsigned char*)malloc(bytes); - if(buf) - { - memset(buf,0,bytes); - AVI.Audio(rate,bits,chans, buf, n); - free(buf); - } - } - } - - AVI.Audio(rate,bits,chans, (const unsigned char*) data, nsamples); - } -//} // extern "C" - - - -static void FlushWrite(FILE* fp, const unsigned char*buf, unsigned length) -{ - while(length > 0) - { - unsigned written = fwrite(buf, 1, length, fp); - length -= written; - buf += written; - } -} -*/ diff -NaHudr a/main/nesvideos-piece.h b/main/nesvideos-piece.h --- a/main/nesvideos-piece.h 2006-08-14 02:09:27.000000000 +0300 +++ b/main/nesvideos-piece.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,41 +0,0 @@ -#ifndef NESVPIECEh -#define NESVPIECEh - -#define NESVIDEOS_LOGGING 1 - -/* Is video logging enabled? 0=no, 1=yes, 2=active. Default value: 0 */ -extern int LoggingEnabled; - -/* Get and set the video recording command (shell command) */ -extern const char* NESVideoGetVideoCmd(); -extern void NESVideoSetVideoCmd(const char *cmd); - -/* Tells to use these functions for obtaining/releasing FILE pointers for writing - if not specified, popen/pclose are used. */ -extern void NESVideoSetFileFuncs( FILE* openFunc(const char *,const char *), int closeFunc(FILE*) ); - -/* Tells to call these functions per frame with amounts (seconds and frames) of video and audio progress */ -extern void NESVideoEnableDebugging( void videoMessageFunc(const char *msg), void audioMessageFunc(const char *msg) ); - -/* Save 1 frame of video. (Assumed to be 16-bit RGB) */ -/* FPS is scaled by 24 bits (*0x1000000) */ -/* Does not do anything if LoggingEnabled<2. */ -extern void NESVideoLoggingVideo - (const void*data, unsigned width, unsigned height, - unsigned fps_scaled); - -/* Save N bytes of audio. bytes_per_second is required on the first call. */ -/* Does not do anything if LoggingEnabled<2. */ -/* The interval of calling this function is not important, as long as all the audio - * data is eventually written without too big delay (5 seconds is too big) - * This function may be called multiple times per video frame, or once per a few video - * frames, or anything in between. Just that all audio data must be written exactly once, - * and in order. */ -extern void NESVideoLoggingAudio - (const void*data, - unsigned rate, unsigned bits, unsigned chans, - unsigned nsamples); -/* nsamples*chans*(bits/8) = bytes in *data. */ -/* rate*chans*(bits/8) = bytes per second. */ - - -#endif diff -NaHudr a/main/savestates.h b/main/savestates.h --- a/main/savestates.h 2006-08-14 02:09:27.000000000 +0300 +++ b/main/savestates.h 2006-08-14 11:13:41.000000000 +0300 @@ -35,7 +35,7 @@ void savestates_save(); void savestates_load(); -void savestates_select_slot(); -void savestates_select_filename(); +void savestates_select_slot(unsigned int s); +void savestates_select_filename(char* fn); unsigned const char * savestates_get_selected_filename(); diff -NaHudr a/main/vcr.c b/main/vcr.c --- a/main/vcr.c 2006-08-14 02:09:26.000000000 +0300 +++ b/main/vcr.c 1970-01-01 02:00:00.000000000 +0200 @@ -1,1885 +0,0 @@ -#include "../config.h" -#ifdef VCR_SUPPORT - -#include "vcr.h" -#include "vcr_compress.h" -#include "vcr_resample.h" - -#include "plugin.h" -#include "rom.h" -#include "savestates.h" -#include "../memory/memory.h" - -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include - -#ifndef __WIN32__ -#include // for getting callback_startEmulation and callback_stopEmulation -#include // for truncate -#include -#define stricmp strcasecmp -#else -#include // for SendMessage, SB_SETTEXT -#include // for truncate functions -#include <../../winproject/resource.h> // for EMU_RESET -#endif - -//void ShowInfo(char*, ...); -//#define printf ShowInfo // temporary debuggification - -#define MUP_MAGIC (0x1a34364d) // M64\0x1a -#define MUP_VERSION (3) -#define MUP_HEADER_SIZE_OLD (512) // bytes -#define MUP_HEADER_SIZE (sizeof(SMovieHeader)) -#define MUP_HEADER_SIZE_CUR (m_header.version <= 2 ? MUP_HEADER_SIZE_OLD : MUP_HEADER_SIZE) - - - -#define BUFFER_GROWTH_SIZE (4096) - -static const char *m_errCodeName[] = -{ - "Success", - "Wrong Format", - "Wrong Version", - "File Not Found", - "Not From This Movie", - "Not From A Movie", - "Invalid Frame", - "Unknown Error" -}; - - -enum ETask -{ - Idle = 0, - StartRecording, - StartRecordingFromSnapshot, - Recording, - StartPlayback, - StartPlaybackFromSnapshot, - Playback -}; -/* -static const char *m_taskName[] = -{ - "Idle", - "StartRecording", - "StartRecordingFromSnapshot", - "Recording", - "StartPlayback", - "StartPlaybackFromSnapshot", - "Playback" -}; -*/ - -static char m_filename[PATH_MAX]; -static FILE* m_file = 0; -static int m_task = Idle; - -static SMovieHeader m_header; -static BOOL m_readOnly = FALSE; - -long m_currentSample = -1; // should = length_samples when recording, and be < length_samples when playing -long m_currentVI = -1; -static char* m_inputBuffer = NULL; -static unsigned long m_inputBufferSize = 0; -static char* m_inputBufferPtr = NULL; -//static BOOL m_intro = TRUE; -static unsigned long m_lastController1Keys = 0; // for input display - -static int m_capture = 0; // capture movie -static int m_audioFreq = 33000; //0x30018; -static int m_audioBitrate = 16; // 16 bits -static float m_videoFrame = 0; -static float m_audioFrame = 0; -static char soundBuf [44100*2]; -static char soundBufEmpty [44100*2]; -static int soundBufPos = 0; -long lastSound = 0; -volatile BOOL captureFrameValid = FALSE; - - -static void printWarning (char* str) -{ -#ifdef __WIN32__ - extern BOOL cmdlineNoGui; - if(cmdlineNoGui) - printf( "Warning: %s\n", str ); - else - MessageBox(NULL, str, "Warning", MB_OK | MB_ICONWARNING); -#else - extern int g_GuiEnabled; - if (!g_GuiEnabled) - printf( "Warning: %s\n", str ); - else - messagebox(tr("Warning"), MB_OK, str ); -#endif -} - -static void printError (char* str) -{ -#ifdef __WIN32__ - extern BOOL cmdlineNoGui; - if(cmdlineNoGui) - fprintf(stderr, "Error: %s\n", str ); - else - MessageBox(NULL, str, "Error", MB_OK | MB_ICONERROR); -#else - extern int g_GuiEnabled; - if (!g_GuiEnabled) - fprintf(stderr, "Error: %s\n", str ); - else - messagebox(tr("Error"), MB_OK, str ); -#endif -} - -static void hardResetAndClearAllSaveData () -{ -#ifdef __WIN32__ -// extern void resetEmu(); - extern BOOL clear_sram_on_restart_mode; - extern BOOL continue_vcr_on_restart_mode; - extern HWND mainHWND; - clear_sram_on_restart_mode = TRUE; - continue_vcr_on_restart_mode = TRUE; -// resetEmu(); - SendMessage(mainHWND, WM_COMMAND, EMU_RESET, 0); -#else - extern void callback_startEmulation( GtkWidget *widget, gpointer data ); - extern void callback_stopEmulation( GtkWidget *widget, gpointer data ); - callback_stopEmulation( NULL, NULL ); - VCR_clearAllSaveData(); - callback_startEmulation( NULL, NULL ); -#endif -} - -static int visByCountrycode() -{ - switch(ROM_HEADER ? (ROM_HEADER->Country_code&0xFF) : -1) - { - case 0x44: - case 0x46: - case 0x49: - case 0x50: - case 0x53: - case 0x55: - case 0x58: - case 0x59: - return 50; - break; - - case 0x37: - case 0x41: - case 0x45: - case 0x4a: - return 60; - break; - } - printWarning("[VCR]: Warning - unknown country code, using 60 FPS for video.\n"); - return 60; -} - -static void setROMInfo (SMovieHeader* header) -{ - - // FIXME - switch(ROM_HEADER ? (ROM_HEADER->Country_code&0xFF) : -1) - { - case 0x37: - case 0x41: - case 0x45: - case 0x4a: - default: - header->vis_per_second = 60; // NTSC - break; - case 0x44: - case 0x46: - case 0x49: - case 0x50: - case 0x53: - case 0x55: - case 0x58: - case 0x59: - header->vis_per_second = 50; // PAL - break; - } - - header->controllerFlags = 0; - header->num_controllers = 0; - if(Controls[0].Present) - header->controllerFlags |= CONTROLLER_1_PRESENT, header->num_controllers++; - if(Controls[1].Present) - header->controllerFlags |= CONTROLLER_2_PRESENT, header->num_controllers++; - if(Controls[2].Present) - header->controllerFlags |= CONTROLLER_3_PRESENT, header->num_controllers++; - if(Controls[3].Present) - header->controllerFlags |= CONTROLLER_4_PRESENT, header->num_controllers++; - if(Controls[0].Plugin == PLUGIN_MEMPAK) - header->controllerFlags |= CONTROLLER_1_MEMPAK; - if(Controls[1].Plugin == PLUGIN_MEMPAK) - header->controllerFlags |= CONTROLLER_2_MEMPAK; - if(Controls[2].Plugin == PLUGIN_MEMPAK) - header->controllerFlags |= CONTROLLER_3_MEMPAK; - if(Controls[3].Plugin == PLUGIN_MEMPAK) - header->controllerFlags |= CONTROLLER_4_MEMPAK; - if(Controls[0].Plugin == PLUGIN_RUMBLE_PAK) - header->controllerFlags |= CONTROLLER_1_RUMBLE; - if(Controls[1].Plugin == PLUGIN_RUMBLE_PAK) - header->controllerFlags |= CONTROLLER_2_RUMBLE; - if(Controls[2].Plugin == PLUGIN_RUMBLE_PAK) - header->controllerFlags |= CONTROLLER_3_RUMBLE; - if(Controls[3].Plugin == PLUGIN_RUMBLE_PAK) - header->controllerFlags |= CONTROLLER_4_RUMBLE; - - extern rom_header *ROM_HEADER; - if(ROM_HEADER) - strncpy(header->romNom, ROM_HEADER->nom, 32); - else - strncpy(header->romNom, "(Unknown)", 32); - header->romCRC = ROM_HEADER ? ROM_HEADER->CRC1 : 0; - header->romCountry = ROM_HEADER ? ROM_HEADER->Country_code : -1; - - header->inputPluginName[0] = '\0'; - header->videoPluginName[0] = '\0'; - header->soundPluginName[0] = '\0'; - header->rspPluginName[0] = '\0'; - -#ifdef __WIN32__ -/* ROM_INFO* pRomInfo = NULL;//getSelectedRom(); // FIXME - what if the user selected one ROM and File->Opened a different one? - if(pRomInfo) - { - DEFAULT_ROM_SETTINGS TempRomSettings = GetDefaultRomSettings( pRomInfo->InternalName); - strncpy(header->inputPluginName, TempRomSettings.InputPluginName, 64); - strncpy(header->videoPluginName, TempRomSettings.GfxPluginName, 64); - strncpy(header->soundPluginName, TempRomSettings.SoundPluginName, 64); - strncpy(header->rspPluginName, TempRomSettings.RspPluginName, 64); - }*/ - - extern char gfx_name[255]; - extern char input_name[255]; - extern char sound_name[255]; - extern char rsp_name[255]; - -// if(!header->videoPluginName[0]) - strncpy(header->videoPluginName, gfx_name, 64); -// if(!header->inputPluginName[0]) - strncpy(header->inputPluginName, input_name, 64); -// if(!header->soundPluginName[0]) - strncpy(header->soundPluginName, sound_name, 64); -// if(!header->rspPluginName[0]) - strncpy(header->rspPluginName, rsp_name, 64); -#else - { - char *name; - extern char *plugin_name_by_filename(const char *filename); // from main_gtk.c - extern const char * config_get_string( const char *key, const char *def ); // from config.c - - name = plugin_name_by_filename( config_get_string( "Gfx Plugin", "" ) ); - if(name) - strncpy(header->videoPluginName, name, 64); - - name = plugin_name_by_filename( config_get_string( "Input Plugin", "" ) ); - if(name) - strncpy(header->inputPluginName, name, 64); - - name = plugin_name_by_filename( config_get_string( "Audio Plugin", "" ) ); - if(name) - strncpy(header->soundPluginName, name, 64); - - name = plugin_name_by_filename( config_get_string( "RSP Plugin", "" ) ); - if(name) - strncpy(header->rspPluginName, name, 64); - } -#endif -} - -static void reserve_buffer_space(unsigned long space_needed) -{ - if(space_needed > m_inputBufferSize) - { - unsigned long ptr_offset = m_inputBufferPtr - m_inputBuffer; - unsigned long alloc_chunks = space_needed / BUFFER_GROWTH_SIZE; - m_inputBufferSize = BUFFER_GROWTH_SIZE * (alloc_chunks+1); - m_inputBuffer = (char*)realloc(m_inputBuffer, m_inputBufferSize); - m_inputBufferPtr = m_inputBuffer + ptr_offset; - } -} - -static void truncateMovie() -{ - // truncate movie controller data to header.length_samples length - - long truncLen = MUP_HEADER_SIZE + sizeof(BUTTONS)*(m_header.length_samples+1); - -#ifdef __WIN32__ - HANDLE fileHandle = CreateFile(m_filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - if(fileHandle != NULL) - { - SetFilePointer(fileHandle, truncLen, 0, FILE_BEGIN); - SetEndOfFile(fileHandle); - CloseHandle(fileHandle); - } -#else - truncate(m_filename, truncLen); -#endif -} - -static int read_movie_header(FILE * file, SMovieHeader * header) -{ -// assert(file != NULL); -// assert(MUP_HEADER_SIZE == sizeof(SMovieHeader)); // sanity check on the header type definition - -// ShowInfo("SIZE = %d",sizeof(SMovieHeader)); - - fseek(file, 0L, SEEK_SET); - - SMovieHeader newHeader; - memset(&newHeader, 0, sizeof(SMovieHeader)); - - if(fread(&newHeader, 1, MUP_HEADER_SIZE_OLD, file) != MUP_HEADER_SIZE_OLD) - return WRONG_FORMAT; - - if(newHeader.magic != MUP_MAGIC) - return WRONG_FORMAT; - - if(newHeader.version <= 0 || newHeader.version > MUP_VERSION) - return WRONG_VERSION; - - if(newHeader.version == 1 || newHeader.version == 2) - { - // attempt to recover screwed-up plugin data caused by - // version mishandling and format problems of first versions - - #define isAlpha(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= 'a' && (x) <= 'z') || ((x) == '1')) - int i; - for(i = 0 ; i < 56+64 ; i++) - if(isAlpha(newHeader.reservedBytes[i]) - && isAlpha(newHeader.reservedBytes[i+64]) - && isAlpha(newHeader.reservedBytes[i+64+64]) - && isAlpha(newHeader.reservedBytes[i+64+64+64])) - break; - if(i != 56+64) - { - memmove(newHeader.videoPluginName, newHeader.reservedBytes + i, 256); - } - else - { - for(i = 0 ; i < 56+64 ; i++) - if(isAlpha(newHeader.reservedBytes[i]) - && isAlpha(newHeader.reservedBytes[i+64]) - && isAlpha(newHeader.reservedBytes[i+64+64])) - break; - if(i != 56+64) - memmove(newHeader.soundPluginName, newHeader.reservedBytes + i, 256-64); - else - { - for(i = 0 ; i < 56+64 ; i++) - if(isAlpha(newHeader.reservedBytes[i]) - && isAlpha(newHeader.reservedBytes[i+64])) - break; - if(i != 56+64) - memmove(newHeader.inputPluginName, newHeader.reservedBytes + i, 256-64-64); - else - { - for(i = 0 ; i < 56+64 ; i++) - if(isAlpha(newHeader.reservedBytes[i])) - break; - if(i != 56+64) - memmove(newHeader.rspPluginName, newHeader.reservedBytes + i, 256-64-64-64); - else - strncpy(newHeader.rspPluginName, "(unknown)", 64); - - strncpy(newHeader.inputPluginName, "(unknown)", 64); - } - strncpy(newHeader.soundPluginName, "(unknown)", 64); - } - strncpy(newHeader.videoPluginName, "(unknown)", 64); - } - // attempt to convert old author and description to utf8 - strncpy(newHeader.authorInfo, newHeader.oldAuthorInfo, 48); - strncpy(newHeader.description, newHeader.oldDescription, 80); - } - if(newHeader.version >= 3 && newHeader.version <= MUP_VERSION) - { - // read rest of header - if(fread((char*)(&newHeader) + MUP_HEADER_SIZE_OLD, 1, MUP_HEADER_SIZE-MUP_HEADER_SIZE_OLD, file) != MUP_HEADER_SIZE-MUP_HEADER_SIZE_OLD) - return WRONG_FORMAT; - } - - *header = newHeader; - - return SUCCESS; -} - - -static void write_movie_header(FILE * file, int numBytes) -{ -// assert(ftell(file) == 0); // we assume file points to beginning of movie file - fseek(file, 0L, SEEK_SET); - - m_header.version = MUP_VERSION; // make sure to update the version! -/// m_header.length_vis = m_header.length_samples / m_header.num_controllers; // wrong - - fwrite(&m_header, 1, MUP_HEADER_SIZE, file); - - fseek(file, 0L, SEEK_END); -} - - -void flush_movie() -{ - if(m_file && (m_task == Recording || m_task == StartRecording || m_task == StartRecordingFromSnapshot)) - { - // (over-)write the header - write_movie_header(m_file, MUP_HEADER_SIZE); - - // (over-)write the controller data - fseek(m_file, MUP_HEADER_SIZE, SEEK_SET); - fwrite(m_inputBuffer, 1, sizeof(BUTTONS)*(m_header.length_samples+1), m_file); - - fflush(m_file); - } -} - -SMovieHeader VCR_getHeaderInfo(const char* filename) -{ - char buf [PATH_MAX]; - char temp_filename [PATH_MAX]; - FILE* tempFile = NULL; - SMovieHeader tempHeader; - memset(&tempHeader, 0, sizeof(SMovieHeader)); - tempHeader.romCountry = -1; - strcpy(tempHeader.romNom, "(no ROM)"); - - flush_movie(); - - strncpy( temp_filename, filename, PATH_MAX ); - char *p = strrchr( temp_filename, '.' ); - if (p) - { - if (!strcasecmp( p, ".m64" ) || !strcasecmp( p, ".st" )) - *p = '\0'; - } - // open record file - strncpy( buf, temp_filename, PATH_MAX ); - tempFile = fopen( buf, "rb+" ); - if (tempFile == 0 && (tempFile = fopen( buf, "rb" )) == 0) - { - strncat( buf, ".m64", PATH_MAX ); - tempFile = fopen( buf, "rb+" ); - if (tempFile == 0 && (tempFile = fopen( buf, "rb" )) == 0) - { - fprintf( stderr, "[VCR]: Could not get header info of .m64 file\n\"%s\": %s\n", filename, strerror( errno ) ); - return tempHeader; - } - } - - read_movie_header(tempFile, &tempHeader); - return tempHeader; -} - -// clear all SRAM, EEPROM, and mempaks -void VCR_clearAllSaveData () -{ - int i; - extern char *get_savespath(); // defined in either win\guifuncs.c or gui_gtk/main_gtk.c - - // clear SRAM - { - char *filename; - FILE *f; - filename = malloc(strlen(get_savespath())+ - strlen(ROM_SETTINGS.goodname)+4+1); - strcpy(filename, get_savespath()); - strcat(filename, ROM_SETTINGS.goodname); - strcat(filename, ".sra"); - f = fopen(filename, "rb"); - if(f) - { - fclose(f); - f = fopen(filename, "wb"); - if(f) - { - extern unsigned char sram[0x8000]; - for (i=0; i<0x8000; i++) sram[i] = 0; - fwrite(sram, 1, 0x8000, f); - fclose(f); - } - } - free(filename); - } - // clear EEPROM - { - char *filename; - FILE *f; - int i; - filename = malloc(strlen(get_savespath())+ - strlen(ROM_SETTINGS.goodname)+4+1); - strcpy(filename, get_savespath()); - strcat(filename, ROM_SETTINGS.goodname); - strcat(filename, ".eep"); - f = fopen(filename, "rb"); - if (f) - { - fclose(f); - f = fopen(filename, "wb"); - if(f) - { - extern unsigned char eeprom[0x8000]; - for (i=0; i<0x800; i++) eeprom[i] = 0; - fwrite(eeprom, 1, 0x800, f); - fclose(f); - } - } - free(filename); - } - // clear mempaks - { - char *filename; - FILE *f; - filename = malloc(strlen(get_savespath())+ - strlen(ROM_SETTINGS.goodname)+4+1); - strcpy(filename, get_savespath()); - strcat(filename, ROM_SETTINGS.goodname); - strcat(filename, ".mpk"); - - f = fopen(filename, "rb"); - if (f) - { - fclose(f); - f = fopen(filename, "wb"); - if(f) - { - extern unsigned char mempack[4][0x8000]; - int j; - for (j=0; j<4; j++) - { - for (i=0; i<0x800; i++) mempack[j][i] = 0; - fwrite(mempack[j], 1, 0x800, f); - } - fclose(f); - } - } - - free(filename); - } - -} - - - -BOOL -VCR_isActive( ) -{ - return (m_task == Recording || m_task == Playback) ? TRUE : FALSE; -} - -BOOL -VCR_isIdle( ) -{ - return (m_task == Idle) ? TRUE : FALSE; -} - -BOOL -VCR_isPlaying( ) -{ - return (m_task == Playback) ? TRUE : FALSE; -} - -BOOL -VCR_isRecording( ) -{ - return (m_task == Recording) ? TRUE : FALSE; -} - -BOOL -VCR_isCapturing( ) -{ - return m_capture ? TRUE : FALSE; -} - -BOOL -VCR_getReadOnly( ) -{ - return m_readOnly; -} -void -VCR_setReadOnly(BOOL val) -{ -#ifdef __WIN32__ - extern HWND mainHWND; - if(m_readOnly != val) - CheckMenuItem( GetMenu(mainHWND), EMU_VCRTOGGLEREADONLY, MF_BYCOMMAND | (val ? MFS_CHECKED : MFS_UNCHECKED)); -#endif - m_readOnly = val; -} - -unsigned long VCR_getLengthVIs() -{ - return VCR_isActive() ? m_header.length_vis : 0; -} -unsigned long VCR_getLengthSamples() -{ - return VCR_isActive() ? m_header.length_samples : 0; -} -void VCR_setLengthVIs(unsigned long val) -{ - m_header.length_vis = val; -} -void VCR_setLengthSamples(unsigned long val) -{ - m_header.length_samples = val; -} - -void -VCR_movieFreeze (char** buf, unsigned long* size) -{ - // sanity check - if(!VCR_isActive()) - { - return; - } - - *buf = NULL; - *size = 0; - - // compute size needed for the buffer - unsigned long size_needed = sizeof(m_header.uid) + sizeof(m_currentSample) + sizeof(m_currentVI) + sizeof(m_header.length_samples); // room for header.uid, currentFrame, and header.length_samples - size_needed += (unsigned long)(sizeof(BUTTONS) * (m_header.length_samples+1)); - *buf=malloc(size_needed); - *size=size_needed; - - char* ptr = *buf; - if(!ptr) - { - return; - } - - *((unsigned long*)ptr) = m_header.uid; - ptr += sizeof(m_header.uid); - *((unsigned long*)ptr) = m_currentSample; - ptr += sizeof(m_currentSample); - *((unsigned long*)ptr) = m_currentVI; - ptr += sizeof(m_currentVI); - *((unsigned long*)ptr) = m_header.length_samples; - ptr += sizeof(m_header.length_samples); - -/// // temp debugging check -///char str [1024]; -///sprintf(str, "size_needed=%d, ptr=0x%x, m_inputBuffer=0x%x, m_header.uid=%d, m_currentSample=%d, m_header.length_samples=%d\n", size_needed, ptr, m_inputBuffer, m_header.uid, m_currentSample, m_header.length_samples); -///ShowInfo(str); - - memcpy(ptr, m_inputBuffer, sizeof(BUTTONS) * (m_header.length_samples+1)); -} - -int VCR_movieUnfreeze (const char* buf, unsigned long size) -{ -// m_intro = FALSE; - - // sanity check - if(VCR_isIdle()) - { - return NOT_FROM_A_MOVIE; // probably wrong error code - } - - const char* ptr = buf; - if(size < sizeof(m_header.uid) + sizeof(m_currentSample) + sizeof(m_currentVI) + sizeof(m_header.length_samples)) - { - return WRONG_FORMAT; - } - - unsigned long movie_id = *((unsigned long*)ptr); - ptr += sizeof(unsigned long); - unsigned long current_sample = *((unsigned long*)ptr); - ptr += sizeof(unsigned long); - unsigned long current_vi = *((unsigned long*)ptr); - ptr += sizeof(unsigned long); - unsigned long max_sample = *((unsigned long*)ptr); - ptr += sizeof(unsigned long); - - unsigned long space_needed = (sizeof(BUTTONS) * (max_sample+1)); - - if(movie_id != m_header.uid) - return NOT_FROM_THIS_MOVIE; - - if(current_sample > max_sample) - return INVALID_FRAME; - - if(space_needed > size) - return WRONG_FORMAT; - - int lastTask = m_task; - if(!m_readOnly) - { - // here, we are going to take the input data from the savestate - // and make it the input data for the current movie, then continue - // writing new input data at the currentFrame pointer -// change_state(MOVIE_STATE_RECORD); - m_task = Recording; - flush_movie(); -/// systemScreenMessage("Movie re-record"); - -#ifdef __WIN32__ - extern void EnableEmulationMenuItems(BOOL flag); - if(lastTask == Playback) - EnableEmulationMenuItems(TRUE); -#else - // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? -#endif - // update header with new ROM info - if(lastTask == Playback) - setROMInfo(&m_header); - - m_currentSample = current_sample; - m_header.length_samples = current_sample; - m_currentVI = current_vi; - - m_header.rerecord_count++; - - reserve_buffer_space(space_needed); - memcpy(m_inputBuffer, ptr, space_needed); - flush_movie(); - fseek(m_file, MUP_HEADER_SIZE_CUR+(sizeof(BUTTONS) * (m_currentSample+1)), SEEK_SET); - } - else - { - // here, we are going to keep the input data from the movie file - // and simply rewind to the currentFrame pointer - // this will cause a desync if the savestate is not in sync - // with the on-disk recording data, but it's easily solved - // by loading another savestate or playing the movie from the beginning - - // and older savestate might have a currentFrame pointer past - // the end of the input data, so check for that here - if(current_sample > m_header.length_samples) - return INVALID_FRAME; - - m_task = Playback; - flush_movie(); -// change_state(MOVIE_STATE_PLAY); -/// systemScreenMessage("Movie rewind"); - -#ifdef __WIN32__ - extern void EnableEmulationMenuItems(BOOL flag); - if(lastTask == Recording) - EnableEmulationMenuItems(TRUE); -#else - // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? -#endif - - m_currentSample = current_sample; - m_currentVI = current_vi; - } - - m_inputBufferPtr = m_inputBuffer + (sizeof(BUTTONS) * m_currentSample); - -/// for(int controller = 0 ; controller < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS ; controller++) -/// if((m_header.controllerFlags & MOVIE_CONTROLLER(controller)) != 0) -/// read_frame_controller_data(controller); -/// read_frame_controller_data(0); // correct if we can assume the first controller is active, which we can on all GBx/xGB systems - - return SUCCESS; -} - - -extern BOOL continue_vcr_on_restart_mode; -extern BOOL just_restarted_flag; - -void -VCR_getKeys( int Control, BUTTONS *Keys ) -{ - if (m_task != Playback && m_task != StartPlayback && m_task != StartPlaybackFromSnapshot) - getKeys( Control, Keys ); - - if(Control == 0) - memcpy(&m_lastController1Keys, Keys, sizeof(unsigned long)); - - if (m_task == Idle) - return; - - if (m_task == StartRecording) - { - if(!continue_vcr_on_restart_mode) - { - if(just_restarted_flag) - { - just_restarted_flag = FALSE; - m_currentSample = 0; - m_currentVI = 0; - m_task = Recording; - memset(Keys, 0, sizeof(BUTTONS)); - } - else - { - printf( "[VCR]: Starting recording...\n" ); - hardResetAndClearAllSaveData(); - } - } -/// return; - } - - if (m_task == StartRecordingFromSnapshot) - { - // wait until state is saved, then record - if ((savestates_job & SAVESTATE) == 0) - { - printf( "[VCR]: Starting recording from Snapshot...\n" ); - m_task = Recording; - memset(Keys, 0, sizeof(BUTTONS)); - } -/// return; - } - - if (m_task == StartPlayback) - { -#ifdef __WIN32__ - if(!continue_vcr_on_restart_mode) - { - if(just_restarted_flag) - { - just_restarted_flag = FALSE; - m_currentSample = 0; - m_currentVI = 0; - m_task = Playback; - } - else - { - printf( "[VCR]: Starting playback...\n" ); - hardResetAndClearAllSaveData(); - } - } -#else - printf( "[VCR]: Starting playback...\n" ); - m_currentSample = 0; - m_currentVI = 0; - m_task = Playback; - hardResetAndClearAllSaveData(); -#endif -/// return; - } - - if (m_task == StartPlaybackFromSnapshot) - { - // wait until state is loaded, then playback - if ((savestates_job & LOADSTATE) == 0) - { - extern BOOL savestates_job_success; - if(!savestates_job_success) - { - char str [2048]; - sprintf(str, "Couldn't find or load this movie's snapshot,\n\"%s\".\nMake sure that file is where Mupen64 can find it.", savestates_get_selected_filename()); - printError(str); - m_task = Idle; - getKeys( Control, Keys ); - return; - } - printf( "[VCR]: Starting playback...\n" ); - m_task = Playback; - } -/// return; - } - - if (m_task == Recording) - { -// long cont = Control; -// fwrite( &cont, 1, sizeof (long), m_file ); // write the controller # - - reserve_buffer_space((unsigned long)((m_inputBufferPtr+sizeof(BUTTONS))-m_inputBuffer)); - - *((BUTTONS*)m_inputBufferPtr) = *Keys; - m_inputBufferPtr += sizeof(BUTTONS); - -// fwrite( Keys, 1, sizeof (BUTTONS), m_file ); // write the data for this controller (sizeof(BUTTONS) == 4 the last time I checked) - m_header.length_samples++; - m_currentSample++; - - // flush data every 5 seconds or so - if((m_header.length_samples % (m_header.num_controllers * 150)) == 0) - { - flush_movie(); - } - - return; - } - - if (m_task == Playback) - { -// long cont; -// fread( &cont, 1, sizeof (long), m_file ); -// if (cont == -1) // end - - if(m_currentSample >= m_header.length_samples - || m_currentVI >= m_header.length_vis) - { -// if (m_capture != 0) -// VCR_stopCapture(); -// else - VCR_stopPlayback(); - return; - } -// if (cont != Control) -// { -// printf( "[VCR]: Warning - controller num from file doesn't match requested number\n" ); -// // ... -// } - - if(m_header.controllerFlags & CONTROLLER_X_PRESENT(Control)) - { - *Keys = *((BUTTONS*)m_inputBufferPtr); - m_inputBufferPtr += sizeof(BUTTONS); - - // fread( Keys, 1, sizeof (BUTTONS), m_file ); - m_currentSample++; - } - else - { - memset(Keys, 0, sizeof(BUTTONS)); - } - - if(Control == 0) - memcpy(&m_lastController1Keys, Keys, sizeof(unsigned long)); - - return; - } -} - - - - -int -VCR_startRecord( const char *filename, BOOL fromSnapshot, const char *authorUTF8, const char *descriptionUTF8 ) -{ - VCR_coreStopped(); - - char buf[PATH_MAX]; -/* - if (m_task != Idle) - { - fprintf( stderr, "[VCR]: Cannot start recording, current task is \"%s\"\n", m_taskName[m_task] ); - return -1; - } -*/ - strncpy( m_filename, filename, PATH_MAX ); - - // open record file - strcpy( buf, m_filename ); - { - char* dot = strrchr(buf, '.'); - char* s1 = strrchr(buf, '\\'); - char* s2 = strrchr(buf, '/'); - if (!dot || ((s1 && s1 > dot) || (s2 && s2 > dot)) ) { - strncat( buf, ".m64", PATH_MAX ); - } - } - m_file = fopen( buf, "wb" ); - if (m_file == 0) - { - fprintf( stderr, "[VCR]: Cannot start recording, could not open file '%s': %s\n", filename, strerror( errno ) ); - return -1; - } - - VCR_setReadOnly(FALSE); - - memset(&m_header, 0, MUP_HEADER_SIZE); - - m_header.magic = MUP_MAGIC; - m_header.version = MUP_VERSION; - m_header.uid = (unsigned long)time(NULL); - m_header.length_vis = 0; - m_header.length_samples = 0; - m_header.rerecord_count = 0; - m_header.startFlags = fromSnapshot ? MOVIE_START_FROM_SNAPSHOT : MOVIE_START_FROM_NOTHING; - - reserve_buffer_space(4096); - - if(fromSnapshot) - { - // save state - printf( "[VCR]: Saving state...\n" ); - strcpy( buf, m_filename ); - - // remove extension - for(;;) - { - char* dot = strrchr(buf, '.'); - if(dot && (dot > strrchr(buf, '\\') && dot > strrchr(buf, '/'))) - *dot = '\0'; - else - break; - } - - strncat( buf, ".st", PATH_MAX ); - savestates_select_filename( buf ); - savestates_job |= SAVESTATE; - m_task = StartRecordingFromSnapshot; - } else{ - m_task = StartRecording; - } - - setROMInfo(&m_header); - - // utf8 strings are also null-terminated so this method still works - if(authorUTF8) - strncpy(m_header.authorInfo, authorUTF8, MOVIE_AUTHOR_DATA_SIZE); - m_header.authorInfo[MOVIE_AUTHOR_DATA_SIZE-1] = '\0'; - if(descriptionUTF8) - strncpy(m_header.description, descriptionUTF8, MOVIE_DESCRIPTION_DATA_SIZE); - m_header.description[MOVIE_DESCRIPTION_DATA_SIZE-1] = '\0'; - -//int i; -//for(i = 0 ; i < MOVIE_AUTHOR_DATA_SIZE*4 ; i++) -// ShowInfo("authorUTF8[%d] = %c", i, authorUTF8[i]); -//for(i = 0 ; i < MOVIE_AUTHOR_DATA_SIZE ; i++) -// ShowInfo("authorWC[%d] = %lc", i, authorWC[i]); - - write_movie_header(m_file, MUP_HEADER_SIZE); - - m_currentSample = 0; - m_currentVI = 0; - - return 0; - -} - - -int -VCR_stopRecord() -{ - int retVal = -1; - - if (m_task == StartRecording) - { - char buf[PATH_MAX]; - - m_task = Idle; - if (m_file) - { - fclose( m_file ); - m_file = 0; - } - printf( "[VCR]: Removing files (nothing recorded)\n" ); - - strcpy( buf, m_filename ); - strncat( m_filename, ".st", PATH_MAX ); - if (unlink( buf ) < 0) - fprintf( stderr, "[VCR]: Couldn't remove save state: %s\n", strerror( errno ) ); - - strcpy( buf, m_filename ); - strncat( m_filename, ".m64", PATH_MAX ); - if (unlink( buf ) < 0) - fprintf( stderr, "[VCR]: Couldn't remove recorded file: %s\n", strerror( errno ) ); - - retVal = 0; - } - - if (m_task == Recording) - { -// long end = -1; - - m_task = Idle; - - setROMInfo(&m_header); - - flush_movie(); - -// fwrite( &end, 1, sizeof (long), m_file ); -// fwrite( &m_header.length_samples, 1, sizeof (long), m_file ); - fclose( m_file ); - m_file = NULL; - - truncateMovie(); - - printf( "[VCR]: Record stopped. Recorded %ld input samples\n", m_header.length_samples ); - -#ifdef __WIN32__ - extern void EnableEmulationMenuItems(BOOL flag); - EnableEmulationMenuItems(TRUE); -#else - // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? -#endif - -#ifdef __WIN32__ - extern HWND hStatus/*, hStatusProgress*/; - SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Stopped recording."); -#endif - - retVal = 0; - } - - if(m_inputBuffer) - { - free(m_inputBuffer); - m_inputBuffer = NULL; - m_inputBufferPtr = NULL; - m_inputBufferSize = 0; - } - - return retVal; -} - - -int -VCR_startPlayback( const char *filename, const char *authorUTF8, const char *descriptionUTF8 ) -{ - VCR_coreStopped(); -// m_intro = TRUE; - - char buf[PATH_MAX]; -/* - if (m_task != Idle) - { - fprintf( stderr, "[VCR]: Cannot start playback, current task is \"%s\"\n", m_taskName[m_task] ); - return -1; - } -*/ - strncpy( m_filename, filename, PATH_MAX ); - char *p = strrchr( m_filename, '.' ); - if (p) - { - if (!strcasecmp( p, ".m64" ) || !strcasecmp( p, ".st" )) - *p = '\0'; - } - // open record file - strcpy( buf, m_filename ); - m_file = fopen( buf, "rb+" ); - if (m_file == 0 && (m_file = fopen( buf, "rb" )) == 0) - { - strncat( buf, ".m64", PATH_MAX ); - m_file = fopen( buf, "rb+" ); - if (m_file == 0 && (m_file = fopen( buf, "rb" )) == 0) - { - fprintf( stderr, "[VCR]: Cannot start playback, could not open .m64 file '%s': %s\n", filename, strerror( errno ) ); - return -1; - } - } - - { - int code = read_movie_header(m_file, &m_header); - - switch(code) - { - case SUCCESS: - { - char warningStr [8092]; - warningStr[0] = '\0'; - - BOOL dontPlay = FALSE; - - if(!Controls[0].Present && (m_header.controllerFlags & CONTROLLER_1_PRESENT)) - { - strcat(warningStr, "Error: You have controller 1 disabled, but it is enabled in the movie file.\nIt cannot play back correctly unless you fix this first (in your input settings).\n"); - dontPlay = TRUE; - } - if(Controls[0].Present && !(m_header.controllerFlags & CONTROLLER_1_PRESENT)) - strcat(warningStr, "Warning: You have controller 1 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you change this first (in your input settings).\n"); - else - { - if(Controls[0].Present && (Controls[0].Plugin != PLUGIN_MEMPAK) && (m_header.controllerFlags & CONTROLLER_1_MEMPAK)) - strcat(warningStr, "Warning: Controller 1 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[0].Present && (Controls[0].Plugin != PLUGIN_RUMBLE_PAK) && (m_header.controllerFlags & CONTROLLER_1_RUMBLE)) - strcat(warningStr, "Warning: Controller 1 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[0].Present && (Controls[0].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_1_MEMPAK|CONTROLLER_1_RUMBLE))) - strcat(warningStr, "Warning: Controller 1 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - } - - if(!Controls[1].Present && (m_header.controllerFlags & CONTROLLER_2_PRESENT)) - { - strcat(warningStr, "Error: You have controller 2 disabled, but it is enabled in the movie file.\nIt cannot back correctly unless you change this first (in your input settings).\n"); - dontPlay = TRUE; - } - if(Controls[1].Present && !(m_header.controllerFlags & CONTROLLER_2_PRESENT)) - strcat(warningStr, "Warning: You have controller 2 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you fix this first (in your input settings).\n"); - else - { - if(Controls[1].Present && (Controls[1].Plugin != PLUGIN_MEMPAK) && (m_header.controllerFlags & CONTROLLER_2_MEMPAK)) - strcat(warningStr, "Warning: Controller 2 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[1].Present && (Controls[1].Plugin != PLUGIN_RUMBLE_PAK) && (m_header.controllerFlags & CONTROLLER_2_RUMBLE)) - strcat(warningStr, "Warning: Controller 2 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[1].Present && (Controls[1].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_2_MEMPAK|CONTROLLER_2_RUMBLE))) - strcat(warningStr, "Warning: Controller 2 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - } - - if(!Controls[2].Present && (m_header.controllerFlags & CONTROLLER_3_PRESENT)) - { - strcat(warningStr, "Error: You have controller 3 disabled, but it is enabled in the movie file.\nIt cannot play back correctly unless you change this first (in your input settings).\n"); - dontPlay = TRUE; - } - if(Controls[2].Present && !(m_header.controllerFlags & CONTROLLER_3_PRESENT)) - strcat(warningStr, "Warning: You have controller 3 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you fix this first (in your input settings).\n"); - else - { - if(Controls[2].Present && (Controls[2].Plugin != PLUGIN_MEMPAK) && !(m_header.controllerFlags & CONTROLLER_3_MEMPAK)) - strcat(warningStr, "Warning: Controller 3 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[2].Present && (Controls[2].Plugin != PLUGIN_RUMBLE_PAK) && !(m_header.controllerFlags & CONTROLLER_3_RUMBLE)) - strcat(warningStr, "Warning: Controller 3 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[2].Present && (Controls[2].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_3_MEMPAK|CONTROLLER_3_RUMBLE))) - strcat(warningStr, "Warning: Controller 3 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - } - - if(!Controls[3].Present && (m_header.controllerFlags & CONTROLLER_4_PRESENT)) - { - strcat(warningStr, "Error: You have controller 4 disabled, but it is enabled in the movie file.\nIt cannot play back correctly unless you change this first (in your input settings).\n"); - dontPlay = TRUE; - } - if(Controls[3].Present && !(m_header.controllerFlags & CONTROLLER_4_PRESENT)) - strcat(warningStr, "Error: You have controller 4 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you fix this first (in your input settings).\n"); - else - { - if(Controls[3].Present && (Controls[3].Plugin != PLUGIN_MEMPAK) && !(m_header.controllerFlags & CONTROLLER_4_MEMPAK)) - strcat(warningStr, "Warning: Controller 4 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[3].Present && (Controls[3].Plugin != PLUGIN_RUMBLE_PAK) && !(m_header.controllerFlags & CONTROLLER_4_RUMBLE)) - strcat(warningStr, "Warning: Controller 4 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - if(Controls[3].Present && (Controls[3].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_4_MEMPAK|CONTROLLER_4_RUMBLE))) - strcat(warningStr, "Warning: Controller 4 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); - } - - char str [512], name [512]; - extern rom_header *ROM_HEADER; - if(ROM_HEADER && stricmp(m_header.romNom, ROM_HEADER->nom) != 0) - { - sprintf(str, "The movie was recorded with the ROM \"%s\",\nbut you are using the ROM \"%s\",\nso the movie probably won't play properly.\n", m_header.romNom, ROM_HEADER->nom); - strcat(warningStr, str); - } - else - { - if(ROM_HEADER && m_header.romCountry != ROM_HEADER->Country_code) - { - sprintf(str, "The movie was recorded with a ROM with country code \"%d\",\nbut you are using a ROM with country code \"%d\",\nso the movie may not play properly.\n", m_header.romCountry, ROM_HEADER->Country_code); - strcat(warningStr, str); - } - else if(ROM_HEADER && m_header.romCRC != ROM_HEADER->CRC1) - { - sprintf(str, "The movie was recorded with a ROM that has CRC \"0x%x\",\nbut you are using a ROM with CRC \"0x%x\",\nso the movie may not play properly.\n", (unsigned int)m_header.romCRC, (unsigned int)ROM_HEADER->CRC1); - strcat(warningStr, str); - } - } - - if(strlen(warningStr) > 0) - { - if(dontPlay) - printError(warningStr); - else - printWarning(warningStr); - } - - extern char gfx_name[255]; - extern char input_name[255]; - extern char sound_name[255]; - extern char rsp_name[255]; -// ROM_INFO* pRomInfo = getSelectedRom(); // FIXME -// DEFAULT_ROM_SETTINGS TempRomSettings = GetDefaultRomSettings( pRomInfo->InternalName); -// if(TempRomSettings.InputPluginName[0]) -// strncpy(name, TempRomSettings.InputPluginName, 64); -// else - strncpy(name, input_name, 64); - if(name[0] && m_header.inputPluginName[0] && stricmp(m_header.inputPluginName, name) != 0) - { - printf("Warning: The movie was recorded with the input plugin \"%s\",\nbut you are using the input plugin \"%s\",\nso the movie may not play properly.", m_header.inputPluginName, name); - } -// if(TempRomSettings.GfxPluginName[0]) -// strncpy(name, TempRomSettings.GfxPluginName, 64); -// else - strncpy(name, gfx_name, 64); - if(name[0] && m_header.videoPluginName[0] && stricmp(m_header.videoPluginName, name) != 0) - { - printf("Warning: The movie was recorded with the graphics plugin \"%s\",\nbut you are using the graphics plugin \"%s\",\nso the movie might not play properly.", m_header.videoPluginName, name); - } -// if(TempRomSettings.SoundPluginName[0]) -// strncpy(name, TempRomSettings.SoundPluginName, 64); -// else - strncpy(name, sound_name, 64); - if(name[0] && m_header.soundPluginName[0] && stricmp(m_header.soundPluginName, name) != 0) - { - printf("Warning: The movie was recorded with the sound plugin \"%s\",\nbut you are using the sound plugin \"%s\",\nso the movie might not play properly.", m_header.soundPluginName, name); - } -// if(TempRomSettings.RspPluginName[0]) -// strncpy(name, TempRomSettings.RspPluginName, 64); -// else - strncpy(name, rsp_name, 64); - if(name[0] && m_header.rspPluginName[0] && stricmp(m_header.rspPluginName, name) != 0) - { - printf("Warning: The movie was recorded with the RSP plugin \"%s\",\nbut you are using the RSP plugin \"%s\",\nso the movie probably won't play properly.", m_header.rspPluginName, name); - } - - - - if(dontPlay) - return -1; - - - // recalculate length of movie from the file size -// fseek(m_file, 0, SEEK_END); -// int fileSize = ftell(m_file); -// m_header.length_samples = (fileSize - MUP_HEADER_SIZE) / sizeof(BUTTONS) - 1; - - fseek(m_file, MUP_HEADER_SIZE_CUR, SEEK_SET); - - // read controller data - m_inputBufferPtr = m_inputBuffer; - unsigned long to_read = sizeof(BUTTONS) * (m_header.length_samples+1); - reserve_buffer_space(to_read); - fread(m_inputBufferPtr, 1, to_read, m_file); - - // read "baseline" controller data -/// read_frame_controller_data(0); // correct if we can assume the first controller is active, which we can on all GBx/xGB systems -// m_currentSample = 0; - - fseek(m_file, 0, SEEK_END); - - - } break; - default: - fprintf( stderr, "[VCR]: Error playing movie: %s.\n", m_errCodeName[code]); - break; - } - - m_currentSample = 0; - m_currentVI = 0; - - if(m_header.startFlags & MOVIE_START_FROM_SNAPSHOT) - { - // load state - printf( "[VCR]: Loading state...\n" ); - strcpy( buf, m_filename ); - - // remove extension - for(;;) - { - char* dot = strrchr(buf, '.'); - if(dot && (dot > strrchr(buf, '\\') && dot > strrchr(buf, '/'))) - *dot = '\0'; - else - break; - } - - strncat( buf, ".st", PATH_MAX ); - savestates_select_filename( buf ); - savestates_job |= LOADSTATE; - m_task = StartPlaybackFromSnapshot; - } else { - m_task = StartPlayback; - } - - // utf8 strings are also null-terminated so this method still works - if(authorUTF8) - strncpy(m_header.authorInfo, authorUTF8, MOVIE_AUTHOR_DATA_SIZE); - m_header.authorInfo[MOVIE_AUTHOR_DATA_SIZE-1] = '\0'; - if(descriptionUTF8) - strncpy(m_header.description, descriptionUTF8, MOVIE_DESCRIPTION_DATA_SIZE); - m_header.description[MOVIE_DESCRIPTION_DATA_SIZE-1] = '\0'; - - return code; - } -} - - -int -VCR_stopPlayback() -{ - if(m_inputBuffer) - { - free(m_inputBuffer); - m_inputBuffer = NULL; - m_inputBufferPtr = NULL; - m_inputBufferSize = 0; - } - - if (m_file) - { - fclose( m_file ); - m_file = 0; - } - - if (m_task == StartPlayback) - { - m_task = Idle; - return 0; - } - - if (m_task == Playback) - { - m_task = Idle; - printf( "[VCR]: Playback stopped (%ld samples played)\n", m_currentSample ); - -#ifdef __WIN32__ - extern void EnableEmulationMenuItems(BOOL flag); - EnableEmulationMenuItems(TRUE); -#else - // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? -#endif - -#ifdef __WIN32__ - extern HWND hStatus; - SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Stopped playback."); -#endif - - return 0; - } - - return -1; -} - - - - - - -void VCR_invalidatedCaptureFrame() -{ - captureFrameValid = FALSE; -} - -void -VCR_updateScreen() -{ -// ShowInfo("VCR_updateScreen()"); - extern int externalReadScreen; - void *image; -// static void* lastImage = NULL; - long width, height; - static int frame = 0; - - if (m_capture == 0 || readScreen == 0) - { -#ifdef __WIN32__ - extern BOOL manualFPSLimit; - if(!manualFPSLimit) - { - // skip 7/8 frames if fast-forwarding and not capturing to AVI - frame++; - if((frame % 8) != 0) - return; - } -#endif - - updateScreen(); -// captureFrameValid = TRUE; - return; - } - -// // skip every other frame -// frame ^= 1; -// if (!frame) -// return; - - updateScreen(); -// captureFrameValid = TRUE; - readScreen( &image, &width, &height ); - if (image == 0) - { - fprintf( stderr, "[VCR]: Couldn't read screen (out of memory?)\n" ); - return; - } - -//char str[256]; -//sprintf(str, "[VCR]: width = %d, height = %d, image = 0x%x", (int)width, (int)height, image); -//ShowInfo(str); - -// if(captureFrameValid || externalReadScreen) -// { -// if(image) -// { - if(!VCRComp_addVideoFrame(image)) - { -// ShowInfo("Video codec failure!\nA call to addVideoFrame() (AVIStreamWrite) failed.\nPerhaps you ran out of memory?"); - printError("Video codec failure!\nA call to addVideoFrame() (AVIStreamWrite) failed.\nPerhaps you ran out of memory?"); - VCR_stopCapture(); - } -// } -// } -// else -// { -// if(lastImage) -// { -// image = lastImage; -// if(!VCRComp_addVideoFrame(image);) -// { -// printError("Video codec failure!\nA call to addVideoFrame() (AVIStreamWrite) failed.\nPerhaps you ran out of memory?"); -// VCR_stopCapture(); -// } -// } -// } - - m_videoFrame += 1.0; - - if(externalReadScreen /*|| (!captureFrameValid && lastImage != image)*/) - { - if(image) - free(image); - } -/* else - { - if(lastImage != image) - { - if(lastImage) - free(lastImage); - lastImage = image; - } - }*/ -// ShowInfo("VCR_updateScreen() done"); -} - - -void -VCR_aiDacrateChanged( int SystemType ) -{ - aiDacrateChanged( SystemType ); - - m_audioBitrate = ai_register.ai_bitrate+1; - switch (SystemType) - { - case SYSTEM_NTSC: - m_audioFreq = 48681812 / (ai_register.ai_dacrate + 1); - break; - case SYSTEM_PAL: - m_audioFreq = 49656530 / (ai_register.ai_dacrate + 1); - break; - case SYSTEM_MPAL: - m_audioFreq = 48628316 / (ai_register.ai_dacrate + 1); - break; - } -} - -// assumes: len <= writeSize -static void writeSound(char* buf, int len, int minWriteSize, int maxWriteSize, BOOL force) -{ - if((len <= 0 && !force) || len > maxWriteSize) - return; -// ShowInfo("writeSound()"); - - if(soundBufPos + len > minWriteSize || force) - { - int len2 = VCR_getResampleLen( 44100, m_audioFreq, m_audioBitrate, soundBufPos ); - if((len2 % 8) == 0 || len > maxWriteSize) - { - static short *buf2 = NULL; - len2 = VCR_resample( &buf2, 44100, (short*)soundBuf, m_audioFreq, m_audioBitrate, soundBufPos ); - if(len2 > 0) - { - if((len2 % 4) != 0) - { - printf("[VCR]: Warning: Possible stereo sound error detected.\n"); - fprintf(stderr, "[VCR]: Warning: Possible stereo sound error detected.\n"); - } - if(!VCRComp_addAudioData((char*)buf2, len2)) - { -// ShowInfo("Audio output failure!\nA call to addAudioData() (AVIStreamWrite) failed.\nPerhaps you ran out of memory?"); - printError("Audio output failure!\nA call to addAudioData() (AVIStreamWrite) failed.\nPerhaps you ran out of memory?"); - VCR_stopCapture(); - } - } -// if(buf2) -// free(buf2); - soundBufPos = 0; - } - } - - if(len > 0) - { - memcpy(soundBuf + soundBufPos, (char*)buf, len); - m_audioFrame += ((len/4)/(float)m_audioFreq)*visByCountrycode(); - soundBufPos += len; - } -// ShowInfo("writeSound() done"); -} - -void VCR_aiLenChanged() -{ - short *p = (short *)((char*)rdram + (ai_register.ai_dram_addr & 0xFFFFFF)); - char* buf = (char*)p; - int aiLen = ai_register.ai_len; - - aiLenChanged(); - if (m_capture == 0) - return; - - // hack - mupen64 updates bitrate after calling aiDacrateChanged - m_audioBitrate = ai_register.ai_bitrate+1; - - if (aiLen > 0) - { - int len = aiLen; - int writeSize = 2*m_audioFreq; // we want (writeSize * 44100 / m_audioFreq) to be an integer - -/* - // TEMP PARANOIA - if(len > writeSize) - { - char str [256]; - printf("Sound AVI Output Failure: %d > %d", len, writeSize); - fprintf(stderr, "Sound AVI Output Failure: %d > %d", len, writeSize); - sprintf(str, "Sound AVI Output Failure: %d > %d", len, writeSize); - printError(str); - printWarning(str); - exit(0); - } -*/ - - - { - float desync = m_videoFrame - m_audioFrame; - if (desync >= 0.0) - { - int len3; - printf( "[VCR]: Correcting for A/V desynchronization of %+f frames\n", desync ); - len3 = (m_audioFreq/(float)visByCountrycode()) * desync; - len3 <<= 2; - - int emptySize = len3 > writeSize ? writeSize : len3; - int i; - for(i = 0 ; i < emptySize ; i += 4) - *((long*)(soundBufEmpty + i)) = lastSound; - while(len3 > writeSize) - { - writeSound(soundBufEmpty, writeSize, m_audioFreq, writeSize, FALSE); - len3 -= writeSize; - } - writeSound(soundBufEmpty, len3, m_audioFreq, writeSize, FALSE); - } - else if (desync <= -10.0) - { - printf( "[VCR]: Waiting from A/V desynchronization of %+f frames\n", desync ); - } - } - - - writeSound(buf, len, m_audioFreq, writeSize, FALSE); - - lastSound = *((long*)(buf + len) - 1); - - } -} - - - - - - -#ifdef __WIN32__ -void init_readScreen(); -#endif - -int -VCR_startCapture( const char *recFilename, const char *aviFilename ) -{ -#ifdef __WIN32__ - extern BOOL emu_paused; - BOOL wasPaused = emu_paused; - if(!emu_paused) - { - extern void pauseEmu(BOOL quiet); - pauseEmu(TRUE); - } - init_readScreen(); -#endif - if (readScreen == 0) - { - printError("AVI capture failed because the active video plugin does not support ReadScreen()!"); - return -1; - } - - memset(soundBufEmpty, 0, 44100*2); - memset(soundBuf, 0, 44100*2); - lastSound = 0; - - m_videoFrame = 0.0; - m_audioFrame = 0.0; - void *dest; - long width, height; - readScreen( &dest, &width, &height ); - if (dest) - free( dest ); - VCRComp_startFile( aviFilename, width, height, visByCountrycode() ); - m_capture = 1; -/* if (VCR_startPlayback( recFilename ) < 0) - { - printError("Cannot start capture; could not play movie file!\n" ); - return -1; - }*/ - -#ifdef __WIN32__ - // disable the toolbar (m_capture==1 causes this call to do that) - // because a bug means part of it could get captured into the AVI - extern void EnableToolbar(); - EnableToolbar(); - - if(!wasPaused || (m_task == Playback || m_task == StartPlayback || m_task == StartPlaybackFromSnapshot)) - { - extern void resumeEmu(BOOL quiet); - resumeEmu(TRUE); - } -#endif - - VCR_invalidatedCaptureFrame(); - - printf( "[VCR]: Starting capture...\n" ); - - return 0; -} - -void -VCR_toggleReadOnly () -{ - VCR_setReadOnly(!m_readOnly); - -#ifdef __WIN32__ - extern HWND hStatus/*, hStatusProgress*/; - SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)(m_readOnly ? "read-only" : "read+write")); -#else - printf("%s\n", m_readOnly ? "read-only" : "read+write"); -#endif -} - - -int -VCR_stopCapture() -{ -// ShowInfo("VCR_stopCapture()"); - m_capture = 0; - writeSound(NULL, 0, m_audioFreq, m_audioFreq*2, TRUE); - VCR_invalidatedCaptureFrame(); - -#ifdef __WIN32__ - // re-enable the toolbar (m_capture==0 causes this call to do that) - extern void EnableToolbar(); - EnableToolbar(); -#else - usleep( 100000 ); // HACK - is this really necessary? -#endif -// VCR_stopPlayback(); - VCRComp_finishFile(); - printf( "[VCR]: Capture finished.\n" ); -// ShowInfo("VCR_stopCapture() done"); - return 0; -} - - - - -void -VCR_coreStopped() -{ - extern BOOL continue_vcr_on_restart_mode; - if(continue_vcr_on_restart_mode) - return; - - switch (m_task) - { - case StartRecording: - case StartRecordingFromSnapshot: - case Recording: - VCR_stopRecord(); - break; - case StartPlayback: - case StartPlaybackFromSnapshot: - case Playback: - VCR_stopPlayback(); - break; - } - - if (m_capture != 0) - VCR_stopCapture(); -} - -// update frame counter -void VCR_updateFrameCounter () -{ - // input display - char inputDisplay [64]; - inputDisplay[0] = '\0'; - { - BOOL a, b, z, l, r, s, cl, cu, cr, cd, dl, du, dr, dd; - signed char x, y; - dr = (m_lastController1Keys & (0x0001)) != 0; - dl = (m_lastController1Keys & (0x0002)) != 0; - dd = (m_lastController1Keys & (0x0004)) != 0; - du = (m_lastController1Keys & (0x0008)) != 0; - s = (m_lastController1Keys & (0x0010)) != 0; // start button - z = (m_lastController1Keys & (0x0020)) != 0; - b = (m_lastController1Keys & (0x0040)) != 0; - a = (m_lastController1Keys & (0x0080)) != 0; - cr = (m_lastController1Keys & (0x0100)) != 0; - cl = (m_lastController1Keys & (0x0200)) != 0; - cd = (m_lastController1Keys & (0x0400)) != 0; - cu = (m_lastController1Keys & (0x0800)) != 0; - r = (m_lastController1Keys & (0x1000)) != 0; - l = (m_lastController1Keys & (0x2000)) != 0; - x = ((m_lastController1Keys & (0x00FF0000)) >> 16); - y = ((m_lastController1Keys & (0xFF000000)) >> 24); - - if(!x && !y) - strcpy(inputDisplay, ""); - else - { - int xamt = (x<0?-x:x) * 99/127; if(!xamt && x) xamt = 1; - int yamt = (y<0?-y:y) * 99/127; if(!yamt && y) yamt = 1; - if(x && y) - sprintf(inputDisplay, "%c%d %c%d ", x<0?'<':'>', xamt, y<0?'v':'^', yamt); - else if(x) - sprintf(inputDisplay, "%c%d ", x<0?'<':'>', xamt); - else //if(y) - sprintf(inputDisplay, "%c%d ", y<0?'v':'^', yamt); - } - - if(s) strcat(inputDisplay, "S"); - if(z) strcat(inputDisplay, "Z"); - if(a) strcat(inputDisplay, "A"); - if(b) strcat(inputDisplay, "B"); - if(l) strcat(inputDisplay, "L"); - if(r) strcat(inputDisplay, "R"); - if(cu||cd||cl||cr) - { - strcat(inputDisplay, " C"); - if(cu) strcat(inputDisplay, "^"); - if(cd) strcat(inputDisplay, "v"); - if(cl) strcat(inputDisplay, "<"); - if(cr) strcat(inputDisplay, ">"); - } - if(du||dd||dl||dr) - { - strcat(inputDisplay, " D"); - if(du) strcat(inputDisplay, "^"); - if(dd) strcat(inputDisplay, "v"); - if(dl) strcat(inputDisplay, "<"); - if(dr) strcat(inputDisplay, ">"); - } - } - - char str [128]; - if(VCR_isRecording()) - sprintf(str, "%d (%d) %s", (int)m_currentVI, (int)m_currentSample, inputDisplay); - else if(VCR_isPlaying()) - sprintf(str, "%d/%d (%d/%d) %s", (int)m_currentVI, (int)VCR_getLengthVIs(), (int)m_currentSample, (int)VCR_getLengthSamples(), inputDisplay); - else - strcpy(str, inputDisplay); - -#ifdef __WIN32__ - extern HWND hStatus/*, hStatusProgress*/; - -// // oops, this control isn't even visible during emulation... -// if(VCR_isPlaying()) -// SendMessage( hStatusProgress, PBM_SETPOS, (int)(100.0f * (float)m_currentSample / (float)VCR_getLengthFrames() + 0.5f), 0 ); - -// if(m_intro && m_currentSample < 60 && VCR_isPlaying()) -// sprintf(str, "%d re-records, %d frames", (int)m_header.rerecord_count, (int)m_header.length_vis); - - SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)str); - -#else - fprintf(stderr, "%s\r", str); -#endif -} - - - -#endif // VCR_SUPPORT diff -NaHudr a/main/vcr_compress.cpp b/main/vcr_compress.cpp --- a/main/vcr_compress.cpp 2006-08-14 02:09:27.000000000 +0300 +++ b/main/vcr_compress.cpp 2006-08-14 01:51:32.000000000 +0300 @@ -41,7 +41,7 @@ void -VCRComp_startFile( const char *filename, long width, long height, int fps ) +VCRComp_startFile( const char *filename, long* width, long* height, long* rate, int fps ) { if (GetAvifileVersion() != AVIFILE_VERSION) { @@ -58,16 +58,18 @@ m_file = 0; m_videoStream = 0; m_audioStream = 0; + + *rate = 48000; try { - m_videoFormat = new BitmapInfo( width, -height, 24 ); // RGB, flipped + m_videoFormat = new BitmapInfo( *width, -*height, 24 ); // RGB, flipped m_audioFormat = new WAVEFORMATEX; memset( m_audioFormat, 0, sizeof (WAVEFORMATEX) ); m_audioFormat->wFormatTag = WAVE_FORMAT_PCM; m_audioFormat->nChannels = 2; - m_audioFormat->nSamplesPerSec = 44100; + m_audioFormat->nSamplesPerSec = *rate; m_audioFormat->nBlockAlign = 4; m_audioFormat->nAvgBytesPerSec = m_audioFormat->nSamplesPerSec * m_audioFormat->nBlockAlign; m_audioFormat->wBitsPerSample = 16; @@ -193,6 +195,12 @@ } } +void VCRComp_notifyNewRate(long rate) +{ +} +void VCRComp_notifyNewRes(long width, long height) +{ +} // codec stuff diff -NaHudr a/main/vcr_compress.h b/main/vcr_compress.h --- a/main/vcr_compress.h 2006-08-14 02:09:27.000000000 +0300 +++ b/main/vcr_compress.h 2006-08-13 23:50:30.000000000 +0300 @@ -14,13 +14,34 @@ #define ATTRIB_SELECT 3 #define ATTRIB_FLOAT 4 -void VCRComp_init(); - -void VCRComp_startFile( const char *filename, long width, long height, int fps ); +/* Starts recording a new AVI file. + * width,height = video dimensions + * rate = audio rate (16-bit stereo assumed) + * fps = video rate (60 for NTSC) + * + * Passed in are current width,height. The user may override those, + * and if they do, the video will be scaled into the desired size. + * 0,0 means the compressor can cope changing video res. + * + * Passed in is the current audio rate. The compressor may change + * it into 0 to indicate they can handle varying audio rates, or + * into their desired sampling rate (48000 for example). + */ +void VCRComp_startFile( const char *filename, long* width, long* height, + long* rate, int fps ); void VCRComp_finishFile(); BOOL VCRComp_addVideoFrame( const unsigned char *data ); BOOL VCRComp_addAudioData( const unsigned char *data, int len ); +/* Notifies the compressor of new settings. + * Does not necessarily mean anything changed! + */ +void VCRComp_notifyNewRate(long rate); +void VCRComp_notifyNewRes(long width, long height); + + +/* These functions are called by UI code, not vcr.cpp */ +void VCRComp_init(); int VCRComp_numVideoCodecs(); const char *VCRComp_videoCodecName( int index ); int VCRComp_numVideoCodecAttribs( int index ); diff -NaHudr a/main/vcr.cpp b/main/vcr.cpp --- a/main/vcr.cpp 1970-01-01 02:00:00.000000000 +0200 +++ b/main/vcr.cpp 2006-08-14 12:12:44.000000000 +0300 @@ -0,0 +1,2134 @@ +#include "../config.h" +#ifdef VCR_SUPPORT + +extern "C" { + +#include "vcr.h" +#include "vcr_compress.h" + +#include "plugin.h" +#include "rom.h" +#include "savestates.h" +#include "../memory/memory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +} + +#ifndef __WIN32__ +#include // for getting callback_startEmulation and callback_stopEmulation +#include // for truncate +#include +#include +#define stricmp strcasecmp +#else +#include // for SendMessage, SB_SETTEXT +#include // for truncate functions +#include <../../winproject/resource.h> // for EMU_RESET +#endif + +//void ShowInfo(char*, ...); +//#define printf ShowInfo // temporary debuggification + +#define MUP_MAGIC (0x1a34364d) // M64\0x1a +#define MUP_VERSION (3) +#define MUP_HEADER_SIZE_OLD (512) // bytes +#define MUP_HEADER_SIZE (sizeof(SMovieHeader)) +#define MUP_HEADER_SIZE_CUR (m_header.version <= 2 ? MUP_HEADER_SIZE_OLD : MUP_HEADER_SIZE) + + + +#define BUFFER_GROWTH_SIZE (4096) + +static const char *m_errCodeName[] = +{ + "Success", + "Wrong Format", + "Wrong Version", + "File Not Found", + "Not From This Movie", + "Not From A Movie", + "Invalid Frame", + "Unknown Error" +}; + + +enum ETask +{ + Idle = 0, + StartRecording, + StartRecordingFromSnapshot, + Recording, + StartPlayback, + StartPlaybackFromSnapshot, + Playback +}; +/* +static const char *m_taskName[] = +{ + "Idle", + "StartRecording", + "StartRecordingFromSnapshot", + "Recording", + "StartPlayback", + "StartPlaybackFromSnapshot", + "Playback" +}; +*/ + +static char m_filename[PATH_MAX]; +static FILE* m_file = 0; +static int m_task = Idle; + +static SMovieHeader m_header; +static BOOL m_readOnly = FALSE; + +long m_currentSample = -1; // should = length_samples when recording, and be < length_samples when playing +long m_currentVI = -1; +static char* m_inputBuffer = NULL; +static unsigned long m_inputBufferSize = 0; +static char* m_inputBufferPtr = NULL; +static unsigned long m_lastController1Keys = 0; // for input display + +static int visByCountrycode(); + +#ifdef __WIN32__ +extern "C" { +void EnableEmulationMenuItems(BOOL flag); +void init_readScreen(); +extern BOOL emu_paused; +void pauseEmu(BOOL quiet); +void EnableToolbar(); +void resumeEmu(BOOL quiet); +extern HWND hStatus/*, hStatusProgress*/; +extern HWND mainHWND; +extern BOOL continue_vcr_on_restart_mode; +extern BOOL just_restarted_flag; +extern BOOL continue_vcr_on_restart_mode; +extern BOOL cmdlineNoGui; +extern void resetEmu(); +extern BOOL clear_sram_on_restart_mode; +extern BOOL savestates_job_success; +extern BOOL continue_vcr_on_restart_mode; +extern HWND mainHWND; +extern rom_header *ROM_HEADER; +extern char gfx_name[255]; +extern char input_name[255]; +extern char sound_name[255]; +extern char rsp_name[255]; +extern char *get_savespath(); // defined in either win\guifuncs.c or gui_gtk/main_gtk.c +extern unsigned char sram[0x8000]; +extern unsigned char eeprom[0x8000]; +extern unsigned char mempack[4][0x8000]; +extern int externalReadScreen; +extern BOOL manualFPSLimit; +} +#endif + +static struct +{ + bool capturing; + + int audioFreq; + int audioBitrate; + + long desiredAudioFreq; + long desiredXres; + long desiredYres; + + double videopos; + double videoratio; + int n_videoframes_lastcheck; + + double audiolead; + double audioperframe; + + void BeginNewMovie() + { + videopos = 0.0; + videoratio = 1.0; + n_videoframes_lastcheck = 0; + audiolead = 0.0; + audioperframe = desiredAudioFreq / visByCountrycode(); + capturing = true; + } +} m_vcrsets = +{ + false, + 33000, // 0x30018 + 16, // 16 bits + 48000, // good guess + 0,0,0, // initial situation + 0,800 // initial situation +}; // 0x30018, 16 bits + +/***** VIDEO RESAMPLE CODE ************/ +#include +#include +static inline double dblmin(const double a, const double b) { return a < b ? a : b; } +static inline double dblmax(const double a, const double b) { return a > b ? a : b; } +static inline double dblabs(const double a) { return a < 0 ? -a : a; } +static inline double Lanczos(double x) +{ + if(x == 0.0) return 1.0; + if(x <= -3.0 || x >= 3.0)return 0.0; + double tmp = x * M_PI, tmp2 = tmp / 3.0; + return sin(tmp) * sin(tmp2) / (tmp * tmp2); +} + +template +static inline void LanczosResample + (InIt & source, unsigned src_len, + OutIt& result, unsigned dest_len) +{ + const double filter_support = 3.0; + const double blur = 1.0; + const double factor = dest_len / (double)src_len; + + double scale = dblmin(factor, 1.0) / blur; + double support = filter_support / scale; + if(support <= 0.5) { support = 0.5 + 1E-12; scale = 1.0; } + + double contribution[(unsigned)(support*2+2)]; + + for(unsigned x=0; x data; + unsigned W, wid,hei; +}; +struct LanczosProxy2 // final +{ + inline LanczosProxy2(unsigned _W,unsigned _H) : W(_W) + { + data.resize(W*_H*3); + result.resize(W*_H*3); + } + inline void Zero(unsigned pos) + { + /* + for(unsigned x=0; x data; + std::vector result; + unsigned W; +}; +/************ END VIDEO RESAMPLE CODE *******************/ +/************* AUDIO RESAMPLE CODE ****************/ +struct ResampleItem +{ + short l, r; + ResampleItem() : l(0),r(0) { } + ResampleItem(short ll,short rr):l(ll),r(rr){} +}; +struct ContiguousResampleBuf +{ +public: + double center; +public: + ContiguousResampleBuf() : center(0.5), firstpos(0) { } + + inline void NotNeedOlderThan(int pos) + { + const int n_discard_at_once = 4096; + int discardable = pos-firstpos; + if(discardable >= n_discard_at_once) + { + int n_discard = (discardable / n_discard_at_once) * n_discard_at_once; + AudioData.erase(AudioData.begin(), AudioData.begin()+n_discard); + firstpos += n_discard; + } + } + inline bool AddMul(double& l, double& r, int pos, double coeff) + { + if(pos >= firstpos) + { + if(pos >= (int)(firstpos + AudioData.size())) + return false; + l += AudioData[pos - firstpos].l * coeff; + r += AudioData[pos - firstpos].r * coeff; + } + return true; + } + inline void Feed(const unsigned char* input, unsigned bits, unsigned nbytes) + { + switch(bits) + { + case 4: + { + unsigned prev_size = AudioData.size(); + unsigned nsamples = nbytes; + AudioData.resize(prev_size + nsamples); + for(unsigned a=0; a> 4); s |= (s << 8); + AudioData[prev_size + a].r = s;} + } + break; + } + case 8: + { + unsigned prev_size = AudioData.size(); + unsigned nsamples = nbytes / 2; + AudioData.resize(prev_size + nsamples); + for(unsigned a=0; a AudioData; + int firstpos; +}; +const std::vector + ContiguousResample(double factor, + const unsigned char* input, + unsigned bits, unsigned nbytes) +{ + static ContiguousResampleBuf status; + + status.Feed(input, bits, nbytes); + + const double filter_support = 3.0; + double scale = dblmin(factor, 1.0); + double support = filter_support / scale; + if(support <= 0.5) { support = 0.5 + 1E-12; scale = 1.0; } + + const double factor_rev = 1.0 / factor; + double contribution[(unsigned)(support*2 + 2)]; + + std::vector result; + for(;;) + { + const int start = (int)(status.center-support+0.5); + const int stop = (int)(status.center+support+0.5); + double density = 0.0; + + unsigned nmax = stop-start; + + double s = start - status.center + 0.5; + for(unsigned n=0; n32767)res_l=32767; + int res_r = (int)result_r; if(res_r<-32768)res_r=-32768; if(res_r>32767)res_r=32767; + result.push_back( ResampleItem(res_l,res_r)); + } +NoMoreData: + status.center -= status.DropExcess(); + return result; +} +/************ END AUDIO RESAMPLE CODE *******************/ + + + + +static void printWarning (char* str) +{ +#ifdef __WIN32__ + if(cmdlineNoGui) + printf( "Warning: %s\n", str ); + else + MessageBox(NULL, str, "Warning", MB_OK | MB_ICONWARNING); +#else + extern int g_GuiEnabled; + if (!g_GuiEnabled) + printf( "Warning: %s\n", str ); + else + messagebox(tr("Warning"), MB_OK, str ); +#endif +} + +static void printError (char* str) +{ +#ifdef __WIN32__ + if(cmdlineNoGui) + fprintf(stderr, "Error: %s\n", str ); + else + MessageBox(NULL, str, "Error", MB_OK | MB_ICONERROR); +#else + extern int g_GuiEnabled; + if (!g_GuiEnabled) + fprintf(stderr, "Error: %s\n", str ); + else + messagebox(tr("Error"), MB_OK, str ); +#endif +} + +static void hardResetAndClearAllSaveData () +{ +#ifdef __WIN32__ + clear_sram_on_restart_mode = TRUE; + continue_vcr_on_restart_mode = TRUE; +// resetEmu(); + SendMessage(mainHWND, WM_COMMAND, EMU_RESET, 0); +#else + extern void callback_startEmulation( GtkWidget *widget, gpointer data ); + extern void callback_stopEmulation( GtkWidget *widget, gpointer data ); + callback_stopEmulation( NULL, NULL ); + VCR_clearAllSaveData(); + callback_startEmulation( NULL, NULL ); +#endif +} + +static int visByCountrycode() +{ + switch(ROM_HEADER ? (ROM_HEADER->Country_code&0xFF) : -1) + { + case 0x44: + case 0x46: + case 0x49: + case 0x50: + case 0x53: + case 0x55: + case 0x58: + case 0x59: + return 50; + break; + + case 0x37: + case 0x41: + case 0x45: + case 0x4a: + return 60; + break; + } + printWarning("[VCR]: Warning - unknown country code, using 60 FPS for video.\n"); + return 60; +} + +static void setROMInfo (SMovieHeader* header) +{ + + // FIXME + switch(ROM_HEADER ? (ROM_HEADER->Country_code&0xFF) : -1) + { + case 0x37: + case 0x41: + case 0x45: + case 0x4a: + default: + header->vis_per_second = 60; // NTSC + break; + case 0x44: + case 0x46: + case 0x49: + case 0x50: + case 0x53: + case 0x55: + case 0x58: + case 0x59: + header->vis_per_second = 50; // PAL + break; + } + + header->controllerFlags = 0; + header->num_controllers = 0; + if(Controls[0].Present) + header->controllerFlags |= CONTROLLER_1_PRESENT, header->num_controllers++; + if(Controls[1].Present) + header->controllerFlags |= CONTROLLER_2_PRESENT, header->num_controllers++; + if(Controls[2].Present) + header->controllerFlags |= CONTROLLER_3_PRESENT, header->num_controllers++; + if(Controls[3].Present) + header->controllerFlags |= CONTROLLER_4_PRESENT, header->num_controllers++; + if(Controls[0].Plugin == PLUGIN_MEMPAK) + header->controllerFlags |= CONTROLLER_1_MEMPAK; + if(Controls[1].Plugin == PLUGIN_MEMPAK) + header->controllerFlags |= CONTROLLER_2_MEMPAK; + if(Controls[2].Plugin == PLUGIN_MEMPAK) + header->controllerFlags |= CONTROLLER_3_MEMPAK; + if(Controls[3].Plugin == PLUGIN_MEMPAK) + header->controllerFlags |= CONTROLLER_4_MEMPAK; + if(Controls[0].Plugin == PLUGIN_RUMBLE_PAK) + header->controllerFlags |= CONTROLLER_1_RUMBLE; + if(Controls[1].Plugin == PLUGIN_RUMBLE_PAK) + header->controllerFlags |= CONTROLLER_2_RUMBLE; + if(Controls[2].Plugin == PLUGIN_RUMBLE_PAK) + header->controllerFlags |= CONTROLLER_3_RUMBLE; + if(Controls[3].Plugin == PLUGIN_RUMBLE_PAK) + header->controllerFlags |= CONTROLLER_4_RUMBLE; + + if(ROM_HEADER) + strncpy(header->romNom, (const char*)ROM_HEADER->nom, 32); + else + strncpy(header->romNom, "(Unknown)", 32); + header->romCRC = ROM_HEADER ? ROM_HEADER->CRC1 : 0; + header->romCountry = ROM_HEADER ? ROM_HEADER->Country_code : -1; + + header->inputPluginName[0] = '\0'; + header->videoPluginName[0] = '\0'; + header->soundPluginName[0] = '\0'; + header->rspPluginName[0] = '\0'; + +#ifdef __WIN32__ +/* ROM_INFO* pRomInfo = NULL;//getSelectedRom(); // FIXME - what if the user selected one ROM and File->Opened a different one? + if(pRomInfo) + { + DEFAULT_ROM_SETTINGS TempRomSettings = GetDefaultRomSettings( pRomInfo->InternalName); + strncpy(header->inputPluginName, TempRomSettings.InputPluginName, 64); + strncpy(header->videoPluginName, TempRomSettings.GfxPluginName, 64); + strncpy(header->soundPluginName, TempRomSettings.SoundPluginName, 64); + strncpy(header->rspPluginName, TempRomSettings.RspPluginName, 64); + }*/ + +// if(!header->videoPluginName[0]) + strncpy(header->videoPluginName, gfx_name, 64); +// if(!header->inputPluginName[0]) + strncpy(header->inputPluginName, input_name, 64); +// if(!header->soundPluginName[0]) + strncpy(header->soundPluginName, sound_name, 64); +// if(!header->rspPluginName[0]) + strncpy(header->rspPluginName, rsp_name, 64); +#else + { + char *name; + extern char *plugin_name_by_filename(const char *filename); // from main_gtk.c + extern const char * config_get_string( const char *key, const char *def ); // from config.c + + name = plugin_name_by_filename( config_get_string( "Gfx Plugin", "" ) ); + if(name) + strncpy(header->videoPluginName, name, 64); + + name = plugin_name_by_filename( config_get_string( "Input Plugin", "" ) ); + if(name) + strncpy(header->inputPluginName, name, 64); + + name = plugin_name_by_filename( config_get_string( "Audio Plugin", "" ) ); + if(name) + strncpy(header->soundPluginName, name, 64); + + name = plugin_name_by_filename( config_get_string( "RSP Plugin", "" ) ); + if(name) + strncpy(header->rspPluginName, name, 64); + } +#endif +} + +static void reserve_buffer_space(unsigned long space_needed) +{ + if(space_needed > m_inputBufferSize) + { + unsigned long ptr_offset = m_inputBufferPtr - m_inputBuffer; + unsigned long alloc_chunks = space_needed / BUFFER_GROWTH_SIZE; + m_inputBufferSize = BUFFER_GROWTH_SIZE * (alloc_chunks+1); + m_inputBuffer = (char*)realloc(m_inputBuffer, m_inputBufferSize); + m_inputBufferPtr = m_inputBuffer + ptr_offset; + } +} + +static void truncateMovie() +{ + // truncate movie controller data to header.length_samples length + + long truncLen = MUP_HEADER_SIZE + sizeof(BUTTONS)*(m_header.length_samples+1); + +#ifdef __WIN32__ + HANDLE fileHandle = CreateFile(m_filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + if(fileHandle != NULL) + { + SetFilePointer(fileHandle, truncLen, 0, FILE_BEGIN); + SetEndOfFile(fileHandle); + CloseHandle(fileHandle); + } +#else + truncate(m_filename, truncLen); +#endif +} + +static int read_movie_header(FILE * file, SMovieHeader * header) +{ +// assert(file != NULL); +// assert(MUP_HEADER_SIZE == sizeof(SMovieHeader)); // sanity check on the header type definition + +// ShowInfo("SIZE = %d",sizeof(SMovieHeader)); + + fseek(file, 0L, SEEK_SET); + + SMovieHeader newHeader; + memset(&newHeader, 0, sizeof(SMovieHeader)); + + if(fread(&newHeader, 1, MUP_HEADER_SIZE_OLD, file) != MUP_HEADER_SIZE_OLD) + return WRONG_FORMAT; + + if(newHeader.magic != MUP_MAGIC) + return WRONG_FORMAT; + + if(newHeader.version <= 0 || newHeader.version > MUP_VERSION) + return WRONG_VERSION; + + if(newHeader.version == 1 || newHeader.version == 2) + { + // attempt to recover screwed-up plugin data caused by + // version mishandling and format problems of first versions + + #define isAlpha(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= 'a' && (x) <= 'z') || ((x) == '1')) + int i; + for(i = 0 ; i < 56+64 ; i++) + if(isAlpha(newHeader.reservedBytes[i]) + && isAlpha(newHeader.reservedBytes[i+64]) + && isAlpha(newHeader.reservedBytes[i+64+64]) + && isAlpha(newHeader.reservedBytes[i+64+64+64])) + break; + if(i != 56+64) + { + memmove(newHeader.videoPluginName, newHeader.reservedBytes + i, 256); + } + else + { + for(i = 0 ; i < 56+64 ; i++) + if(isAlpha(newHeader.reservedBytes[i]) + && isAlpha(newHeader.reservedBytes[i+64]) + && isAlpha(newHeader.reservedBytes[i+64+64])) + break; + if(i != 56+64) + memmove(newHeader.soundPluginName, newHeader.reservedBytes + i, 256-64); + else + { + for(i = 0 ; i < 56+64 ; i++) + if(isAlpha(newHeader.reservedBytes[i]) + && isAlpha(newHeader.reservedBytes[i+64])) + break; + if(i != 56+64) + memmove(newHeader.inputPluginName, newHeader.reservedBytes + i, 256-64-64); + else + { + for(i = 0 ; i < 56+64 ; i++) + if(isAlpha(newHeader.reservedBytes[i])) + break; + if(i != 56+64) + memmove(newHeader.rspPluginName, newHeader.reservedBytes + i, 256-64-64-64); + else + strncpy(newHeader.rspPluginName, "(unknown)", 64); + + strncpy(newHeader.inputPluginName, "(unknown)", 64); + } + strncpy(newHeader.soundPluginName, "(unknown)", 64); + } + strncpy(newHeader.videoPluginName, "(unknown)", 64); + } + // attempt to convert old author and description to utf8 + strncpy(newHeader.authorInfo, newHeader.oldAuthorInfo, 48); + strncpy(newHeader.description, newHeader.oldDescription, 80); + } + if(newHeader.version >= 3 && newHeader.version <= MUP_VERSION) + { + // read rest of header + if(fread((char*)(&newHeader) + MUP_HEADER_SIZE_OLD, 1, MUP_HEADER_SIZE-MUP_HEADER_SIZE_OLD, file) != MUP_HEADER_SIZE-MUP_HEADER_SIZE_OLD) + return WRONG_FORMAT; + } + + *header = newHeader; + + return SUCCESS; +} + + +static void write_movie_header(FILE * file, int numBytes) +{ +// assert(ftell(file) == 0); // we assume file points to beginning of movie file + fseek(file, 0L, SEEK_SET); + + m_header.version = MUP_VERSION; // make sure to update the version! +/// m_header.length_vis = m_header.length_samples / m_header.num_controllers; // wrong + + fwrite(&m_header, 1, MUP_HEADER_SIZE, file); + + fseek(file, 0L, SEEK_END); +} + + +void flush_movie() +{ + if(m_file && (m_task == Recording || m_task == StartRecording || m_task == StartRecordingFromSnapshot)) + { + // (over-)write the header + write_movie_header(m_file, MUP_HEADER_SIZE); + + // (over-)write the controller data + fseek(m_file, MUP_HEADER_SIZE, SEEK_SET); + fwrite(m_inputBuffer, 1, sizeof(BUTTONS)*(m_header.length_samples+1), m_file); + + fflush(m_file); + } +} + +SMovieHeader VCR_getHeaderInfo(const char* filename) +{ + char buf [PATH_MAX]; + char temp_filename [PATH_MAX]; + FILE* tempFile = NULL; + SMovieHeader tempHeader; + memset(&tempHeader, 0, sizeof(SMovieHeader)); + tempHeader.romCountry = -1; + strcpy(tempHeader.romNom, "(no ROM)"); + + flush_movie(); + + strncpy( temp_filename, filename, PATH_MAX ); + char *p = strrchr( temp_filename, '.' ); + if (p) + { + if (!strcasecmp( p, ".m64" ) || !strcasecmp( p, ".st" )) + *p = '\0'; + } + // open record file + strncpy( buf, temp_filename, PATH_MAX ); + tempFile = fopen( buf, "rb+" ); + if (tempFile == 0 && (tempFile = fopen( buf, "rb" )) == 0) + { + strncat( buf, ".m64", PATH_MAX ); + tempFile = fopen( buf, "rb+" ); + if (tempFile == 0 && (tempFile = fopen( buf, "rb" )) == 0) + { + fprintf( stderr, "[VCR]: Could not get header info of .m64 file\n\"%s\": %s\n", filename, strerror( errno ) ); + return tempHeader; + } + } + + read_movie_header(tempFile, &tempHeader); + return tempHeader; +} + +// clear all SRAM, EEPROM, and mempaks +#include +void VCR_clearAllSaveData () +{ + // clear SRAM + { + std::string filename = get_savespath(); + filename += ROM_SETTINGS.goodname; + filename += ".sra"; + FILE* f = fopen(filename.c_str(), "rb"); + if(f) + { + fclose(f); + f = fopen(filename.c_str(), "wb"); + if(f) + { + for (int i=0; i<0x8000; i++) sram[i] = 0; + fwrite(sram, 1, 0x8000, f); + fclose(f); + } + } + } + // clear EEPROM + { + std::string filename; + filename = get_savespath(); + filename += ROM_SETTINGS.goodname; + filename += ".eep"; + FILE* f = fopen(filename.c_str(), "rb"); + if (f) + { + fclose(f); + f = fopen(filename.c_str(), "wb"); + if(f) + { + for (int i=0; i<0x800; i++) eeprom[i] = 0; + fwrite(eeprom, 1, 0x800, f); + fclose(f); + } + } + } + // clear mempaks + { + std::string filename; + filename = get_savespath(); + filename += ROM_SETTINGS.goodname; + filename += ".mpk"; + FILE* f = fopen(filename.c_str(), "rb"); + if (f) + { + fclose(f); + f = fopen(filename.c_str(), "wb"); + if(f) + { + for (int j=0; j<4; j++) + { + for (int i=0; i<0x800; i++) mempack[j][i] = 0; + fwrite(mempack[j], 1, 0x800, f); + } + fclose(f); + } + } + } + +} + + + +BOOL +VCR_isActive( ) +{ + return (m_task == Recording || m_task == Playback) ? TRUE : FALSE; +} + +BOOL +VCR_isIdle( ) +{ + return (m_task == Idle) ? TRUE : FALSE; +} + +BOOL +VCR_isPlaying( ) +{ + return (m_task == Playback) ? TRUE : FALSE; +} + +BOOL +VCR_isRecording( ) +{ + return (m_task == Recording) ? TRUE : FALSE; +} + +BOOL +VCR_isCapturing( ) +{ + return m_vcrsets.capturing; +} + +BOOL +VCR_getReadOnly( ) +{ + return m_readOnly; +} +void +VCR_setReadOnly(BOOL val) +{ +#ifdef __WIN32__ + if(m_readOnly != val) + CheckMenuItem( GetMenu(mainHWND), EMU_VCRTOGGLEREADONLY, MF_BYCOMMAND | (val ? MFS_CHECKED : MFS_UNCHECKED)); +#endif + m_readOnly = val; +} + +unsigned long VCR_getLengthVIs() +{ + return VCR_isActive() ? m_header.length_vis : 0; +} +unsigned long VCR_getLengthSamples() +{ + return VCR_isActive() ? m_header.length_samples : 0; +} +void VCR_setLengthVIs(unsigned long val) +{ + m_header.length_vis = val; +} +void VCR_setLengthSamples(unsigned long val) +{ + m_header.length_samples = val; +} + +void +VCR_movieFreeze (char** buf, unsigned long* size) +{ + // sanity check + if(!VCR_isActive()) + { + return; + } + + *buf = NULL; + *size = 0; + + // compute size needed for the buffer + unsigned long size_needed = sizeof(m_header.uid) + sizeof(m_currentSample) + sizeof(m_currentVI) + sizeof(m_header.length_samples); // room for header.uid, currentFrame, and header.length_samples + size_needed += (unsigned long)(sizeof(BUTTONS) * (m_header.length_samples+1)); + *buf=(char*)malloc(size_needed); + *size=size_needed; + + char* ptr = *buf; + if(!ptr) + { + return; + } + + *((unsigned long*)ptr) = m_header.uid; + ptr += sizeof(m_header.uid); + *((unsigned long*)ptr) = m_currentSample; + ptr += sizeof(m_currentSample); + *((unsigned long*)ptr) = m_currentVI; + ptr += sizeof(m_currentVI); + *((unsigned long*)ptr) = m_header.length_samples; + ptr += sizeof(m_header.length_samples); + +/// // temp debugging check +///char str [1024]; +///sprintf(str, "size_needed=%d, ptr=0x%x, m_inputBuffer=0x%x, m_header.uid=%d, m_currentSample=%d, m_header.length_samples=%d\n", size_needed, ptr, m_inputBuffer, m_header.uid, m_currentSample, m_header.length_samples); +///ShowInfo(str); + + memcpy(ptr, m_inputBuffer, sizeof(BUTTONS) * (m_header.length_samples+1)); +} + +int VCR_movieUnfreeze (const char* buf, unsigned long size) +{ + // sanity check + if(VCR_isIdle()) + { + return NOT_FROM_A_MOVIE; // probably wrong error code + } + + const char* ptr = buf; + if(size < sizeof(m_header.uid) + sizeof(m_currentSample) + sizeof(m_currentVI) + sizeof(m_header.length_samples)) + { + return WRONG_FORMAT; + } + + unsigned long movie_id = *((unsigned long*)ptr); + ptr += sizeof(unsigned long); + unsigned long current_sample = *((unsigned long*)ptr); + ptr += sizeof(unsigned long); + unsigned long current_vi = *((unsigned long*)ptr); + ptr += sizeof(unsigned long); + unsigned long max_sample = *((unsigned long*)ptr); + ptr += sizeof(unsigned long); + + unsigned long space_needed = (sizeof(BUTTONS) * (max_sample+1)); + + if(movie_id != m_header.uid) + return NOT_FROM_THIS_MOVIE; + + if(current_sample > max_sample) + return INVALID_FRAME; + + if(space_needed > size) + return WRONG_FORMAT; + + int lastTask = m_task; + if(!m_readOnly) + { + // here, we are going to take the input data from the savestate + // and make it the input data for the current movie, then continue + // writing new input data at the currentFrame pointer +// change_state(MOVIE_STATE_RECORD); + m_task = Recording; + flush_movie(); +/// systemScreenMessage("Movie re-record"); + +#ifdef __WIN32__ + if(lastTask == Playback) + EnableEmulationMenuItems(TRUE); +#else + // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? +#endif + // update header with new ROM info + if(lastTask == Playback) + setROMInfo(&m_header); + + m_currentSample = current_sample; + m_header.length_samples = current_sample; + m_currentVI = current_vi; + + m_header.rerecord_count++; + + reserve_buffer_space(space_needed); + memcpy(m_inputBuffer, ptr, space_needed); + flush_movie(); + fseek(m_file, MUP_HEADER_SIZE_CUR+(sizeof(BUTTONS) * (m_currentSample+1)), SEEK_SET); + } + else + { + // here, we are going to keep the input data from the movie file + // and simply rewind to the currentFrame pointer + // this will cause a desync if the savestate is not in sync + // with the on-disk recording data, but it's easily solved + // by loading another savestate or playing the movie from the beginning + + // and older savestate might have a currentFrame pointer past + // the end of the input data, so check for that here + if(current_sample > m_header.length_samples) + return INVALID_FRAME; + + m_task = Playback; + flush_movie(); +// change_state(MOVIE_STATE_PLAY); +/// systemScreenMessage("Movie rewind"); + +#ifdef __WIN32__ + if(lastTask == Recording) + EnableEmulationMenuItems(TRUE); +#else + // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? +#endif + + m_currentSample = current_sample; + m_currentVI = current_vi; + } + + m_inputBufferPtr = m_inputBuffer + (sizeof(BUTTONS) * m_currentSample); + +/// for(int controller = 0 ; controller < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS ; controller++) +/// if((m_header.controllerFlags & MOVIE_CONTROLLER(controller)) != 0) +/// read_frame_controller_data(controller); +/// read_frame_controller_data(0); // correct if we can assume the first controller is active, which we can on all GBx/xGB systems + + return SUCCESS; +} + + +void +VCR_getKeys( int Control, BUTTONS *Keys ) +{ + if (m_task != Playback && m_task != StartPlayback && m_task != StartPlaybackFromSnapshot) + getKeys( Control, Keys ); + + if(Control == 0) + memcpy(&m_lastController1Keys, Keys, sizeof(unsigned long)); + + if (m_task == Idle) + return; + + if (m_task == StartRecording) + { + if(!continue_vcr_on_restart_mode) + { + if(just_restarted_flag) + { + just_restarted_flag = FALSE; + m_currentSample = 0; + m_currentVI = 0; + m_task = Recording; + memset(Keys, 0, sizeof(BUTTONS)); + } + else + { + printf( "[VCR]: Starting recording...\n" ); + hardResetAndClearAllSaveData(); + } + } +/// return; + } + + if (m_task == StartRecordingFromSnapshot) + { + // wait until state is saved, then record + if ((savestates_job & SAVESTATE) == 0) + { + printf( "[VCR]: Starting recording from Snapshot...\n" ); + m_task = Recording; + memset(Keys, 0, sizeof(BUTTONS)); + } +/// return; + } + + if (m_task == StartPlayback) + { +#ifdef __WIN32__ + if(!continue_vcr_on_restart_mode) + { + if(just_restarted_flag) + { + just_restarted_flag = FALSE; + m_currentSample = 0; + m_currentVI = 0; + m_task = Playback; + } + else + { + printf( "[VCR]: Starting playback...\n" ); + hardResetAndClearAllSaveData(); + } + } +#else + printf( "[VCR]: Starting playback...\n" ); + m_currentSample = 0; + m_currentVI = 0; + m_task = Playback; + hardResetAndClearAllSaveData(); +#endif +/// return; + } + + if (m_task == StartPlaybackFromSnapshot) + { + // wait until state is loaded, then playback + if ((savestates_job & LOADSTATE) == 0) + { + if(!savestates_job_success) + { + char str [2048]; + sprintf(str, "Couldn't find or load this movie's snapshot,\n\"%s\".\nMake sure that file is where Mupen64 can find it.", savestates_get_selected_filename()); + printError(str); + m_task = Idle; + getKeys( Control, Keys ); + return; + } + printf( "[VCR]: Starting playback...\n" ); + m_task = Playback; + } +/// return; + } + + if (m_task == Recording) + { +// long cont = Control; +// fwrite( &cont, 1, sizeof (long), m_file ); // write the controller # + + reserve_buffer_space((unsigned long)((m_inputBufferPtr+sizeof(BUTTONS))-m_inputBuffer)); + + *((BUTTONS*)m_inputBufferPtr) = *Keys; + m_inputBufferPtr += sizeof(BUTTONS); + +// fwrite( Keys, 1, sizeof (BUTTONS), m_file ); // write the data for this controller (sizeof(BUTTONS) == 4 the last time I checked) + m_header.length_samples++; + m_currentSample++; + + // flush data every 5 seconds or so + if((m_header.length_samples % (m_header.num_controllers * 150)) == 0) + { + flush_movie(); + } + + return; + } + + if (m_task == Playback) + { +// long cont; +// fread( &cont, 1, sizeof (long), m_file ); +// if (cont == -1) // end + + if(m_currentSample >= m_header.length_samples + || m_currentVI >= m_header.length_vis) + { +// if (VCR_isCapturing()) +// VCR_stopCapture(); +// else + VCR_stopPlayback(); + return; + } +// if (cont != Control) +// { +// printf( "[VCR]: Warning - controller num from file doesn't match requested number\n" ); +// // ... +// } + + if(m_header.controllerFlags & CONTROLLER_X_PRESENT(Control)) + { + *Keys = *((BUTTONS*)m_inputBufferPtr); + m_inputBufferPtr += sizeof(BUTTONS); + + // fread( Keys, 1, sizeof (BUTTONS), m_file ); + m_currentSample++; + } + else + { + memset(Keys, 0, sizeof(BUTTONS)); + } + + if(Control == 0) + memcpy(&m_lastController1Keys, Keys, sizeof(unsigned long)); + + return; + } +} + + + + +int +VCR_startRecord( const char *filename, BOOL fromSnapshot, const char *authorUTF8, const char *descriptionUTF8 ) +{ + VCR_coreStopped(); + + char buf[PATH_MAX]; +/* + if (m_task != Idle) + { + fprintf( stderr, "[VCR]: Cannot start recording, current task is \"%s\"\n", m_taskName[m_task] ); + return -1; + } +*/ + strncpy( m_filename, filename, PATH_MAX ); + + // open record file + strcpy( buf, m_filename ); + { + char* dot = strrchr(buf, '.'); + char* s1 = strrchr(buf, '\\'); + char* s2 = strrchr(buf, '/'); + if (!dot || ((s1 && s1 > dot) || (s2 && s2 > dot)) ) { + strncat( buf, ".m64", PATH_MAX ); + } + } + m_file = fopen( buf, "wb" ); + if (m_file == 0) + { + fprintf( stderr, "[VCR]: Cannot start recording, could not open file '%s': %s\n", filename, strerror( errno ) ); + return -1; + } + + VCR_setReadOnly(FALSE); + + memset(&m_header, 0, MUP_HEADER_SIZE); + + m_header.magic = MUP_MAGIC; + m_header.version = MUP_VERSION; + m_header.uid = (unsigned long)time(NULL); + m_header.length_vis = 0; + m_header.length_samples = 0; + m_header.rerecord_count = 0; + m_header.startFlags = fromSnapshot ? MOVIE_START_FROM_SNAPSHOT : MOVIE_START_FROM_NOTHING; + + reserve_buffer_space(4096); + + if(fromSnapshot) + { + // save state + printf( "[VCR]: Saving state...\n" ); + strcpy( buf, m_filename ); + + // remove extension + for(;;) + { + char* dot = strrchr(buf, '.'); + if(dot && (dot > strrchr(buf, '\\') && dot > strrchr(buf, '/'))) + *dot = '\0'; + else + break; + } + + strncat( buf, ".st", PATH_MAX ); + savestates_select_filename( buf ); + savestates_job |= SAVESTATE; + m_task = StartRecordingFromSnapshot; + } else{ + m_task = StartRecording; + } + + setROMInfo(&m_header); + + // utf8 strings are also null-terminated so this method still works + if(authorUTF8) + strncpy(m_header.authorInfo, authorUTF8, MOVIE_AUTHOR_DATA_SIZE); + m_header.authorInfo[MOVIE_AUTHOR_DATA_SIZE-1] = '\0'; + if(descriptionUTF8) + strncpy(m_header.description, descriptionUTF8, MOVIE_DESCRIPTION_DATA_SIZE); + m_header.description[MOVIE_DESCRIPTION_DATA_SIZE-1] = '\0'; + +//int i; +//for(i = 0 ; i < MOVIE_AUTHOR_DATA_SIZE*4 ; i++) +// ShowInfo("authorUTF8[%d] = %c", i, authorUTF8[i]); +//for(i = 0 ; i < MOVIE_AUTHOR_DATA_SIZE ; i++) +// ShowInfo("authorWC[%d] = %lc", i, authorWC[i]); + + write_movie_header(m_file, MUP_HEADER_SIZE); + + m_currentSample = 0; + m_currentVI = 0; + + return 0; + +} + + +int +VCR_stopRecord() +{ + int retVal = -1; + + if (m_task == StartRecording) + { + char buf[PATH_MAX]; + + m_task = Idle; + if (m_file) + { + fclose( m_file ); + m_file = 0; + } + printf( "[VCR]: Removing files (nothing recorded)\n" ); + + strcpy( buf, m_filename ); + strncat( m_filename, ".st", PATH_MAX ); + if (unlink( buf ) < 0) + fprintf( stderr, "[VCR]: Couldn't remove save state: %s\n", strerror( errno ) ); + + strcpy( buf, m_filename ); + strncat( m_filename, ".m64", PATH_MAX ); + if (unlink( buf ) < 0) + fprintf( stderr, "[VCR]: Couldn't remove recorded file: %s\n", strerror( errno ) ); + + retVal = 0; + } + + if (m_task == Recording) + { +// long end = -1; + + m_task = Idle; + + setROMInfo(&m_header); + + flush_movie(); + +// fwrite( &end, 1, sizeof (long), m_file ); +// fwrite( &m_header.length_samples, 1, sizeof (long), m_file ); + fclose( m_file ); + m_file = NULL; + + truncateMovie(); + + printf( "[VCR]: Record stopped. Recorded %ld input samples\n", m_header.length_samples ); + +#ifdef __WIN32__ + EnableEmulationMenuItems(TRUE); +#else + // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? +#endif + +#ifdef __WIN32__ + SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Stopped recording."); +#endif + + retVal = 0; + } + + if(m_inputBuffer) + { + free(m_inputBuffer); + m_inputBuffer = NULL; + m_inputBufferPtr = NULL; + m_inputBufferSize = 0; + } + + return retVal; +} + + +int +VCR_startPlayback( const char *filename, const char *authorUTF8, const char *descriptionUTF8 ) +{ + VCR_coreStopped(); + + char buf[PATH_MAX]; +/* + if (m_task != Idle) + { + fprintf( stderr, "[VCR]: Cannot start playback, current task is \"%s\"\n", m_taskName[m_task] ); + return -1; + } +*/ + strncpy( m_filename, filename, PATH_MAX ); + char *p = strrchr( m_filename, '.' ); + if (p) + { + if (!strcasecmp( p, ".m64" ) || !strcasecmp( p, ".st" )) + *p = '\0'; + } + // open record file + strcpy( buf, m_filename ); + m_file = fopen( buf, "rb+" ); + if (m_file == 0 && (m_file = fopen( buf, "rb" )) == 0) + { + strncat( buf, ".m64", PATH_MAX ); + m_file = fopen( buf, "rb+" ); + if (m_file == 0 && (m_file = fopen( buf, "rb" )) == 0) + { + fprintf( stderr, "[VCR]: Cannot start playback, could not open .m64 file '%s': %s\n", filename, strerror( errno ) ); + return -1; + } + } + + { + int code = read_movie_header(m_file, &m_header); + + switch(code) + { + case SUCCESS: + { + char warningStr [8092]; + warningStr[0] = '\0'; + + BOOL dontPlay = FALSE; + + if(!Controls[0].Present && (m_header.controllerFlags & CONTROLLER_1_PRESENT)) + { + strcat(warningStr, "Error: You have controller 1 disabled, but it is enabled in the movie file.\nIt cannot play back correctly unless you fix this first (in your input settings).\n"); + dontPlay = TRUE; + } + if(Controls[0].Present && !(m_header.controllerFlags & CONTROLLER_1_PRESENT)) + strcat(warningStr, "Warning: You have controller 1 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you change this first (in your input settings).\n"); + else + { + if(Controls[0].Present && (Controls[0].Plugin != PLUGIN_MEMPAK) && (m_header.controllerFlags & CONTROLLER_1_MEMPAK)) + strcat(warningStr, "Warning: Controller 1 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[0].Present && (Controls[0].Plugin != PLUGIN_RUMBLE_PAK) && (m_header.controllerFlags & CONTROLLER_1_RUMBLE)) + strcat(warningStr, "Warning: Controller 1 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[0].Present && (Controls[0].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_1_MEMPAK|CONTROLLER_1_RUMBLE))) + strcat(warningStr, "Warning: Controller 1 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + } + + if(!Controls[1].Present && (m_header.controllerFlags & CONTROLLER_2_PRESENT)) + { + strcat(warningStr, "Error: You have controller 2 disabled, but it is enabled in the movie file.\nIt cannot back correctly unless you change this first (in your input settings).\n"); + dontPlay = TRUE; + } + if(Controls[1].Present && !(m_header.controllerFlags & CONTROLLER_2_PRESENT)) + strcat(warningStr, "Warning: You have controller 2 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you fix this first (in your input settings).\n"); + else + { + if(Controls[1].Present && (Controls[1].Plugin != PLUGIN_MEMPAK) && (m_header.controllerFlags & CONTROLLER_2_MEMPAK)) + strcat(warningStr, "Warning: Controller 2 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[1].Present && (Controls[1].Plugin != PLUGIN_RUMBLE_PAK) && (m_header.controllerFlags & CONTROLLER_2_RUMBLE)) + strcat(warningStr, "Warning: Controller 2 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[1].Present && (Controls[1].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_2_MEMPAK|CONTROLLER_2_RUMBLE))) + strcat(warningStr, "Warning: Controller 2 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + } + + if(!Controls[2].Present && (m_header.controllerFlags & CONTROLLER_3_PRESENT)) + { + strcat(warningStr, "Error: You have controller 3 disabled, but it is enabled in the movie file.\nIt cannot play back correctly unless you change this first (in your input settings).\n"); + dontPlay = TRUE; + } + if(Controls[2].Present && !(m_header.controllerFlags & CONTROLLER_3_PRESENT)) + strcat(warningStr, "Warning: You have controller 3 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you fix this first (in your input settings).\n"); + else + { + if(Controls[2].Present && (Controls[2].Plugin != PLUGIN_MEMPAK) && !(m_header.controllerFlags & CONTROLLER_3_MEMPAK)) + strcat(warningStr, "Warning: Controller 3 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[2].Present && (Controls[2].Plugin != PLUGIN_RUMBLE_PAK) && !(m_header.controllerFlags & CONTROLLER_3_RUMBLE)) + strcat(warningStr, "Warning: Controller 3 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[2].Present && (Controls[2].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_3_MEMPAK|CONTROLLER_3_RUMBLE))) + strcat(warningStr, "Warning: Controller 3 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + } + + if(!Controls[3].Present && (m_header.controllerFlags & CONTROLLER_4_PRESENT)) + { + strcat(warningStr, "Error: You have controller 4 disabled, but it is enabled in the movie file.\nIt cannot play back correctly unless you change this first (in your input settings).\n"); + dontPlay = TRUE; + } + if(Controls[3].Present && !(m_header.controllerFlags & CONTROLLER_4_PRESENT)) + strcat(warningStr, "Error: You have controller 4 enabled, but it is disabled in the movie file.\nIt might not play back correctly unless you fix this first (in your input settings).\n"); + else + { + if(Controls[3].Present && (Controls[3].Plugin != PLUGIN_MEMPAK) && !(m_header.controllerFlags & CONTROLLER_4_MEMPAK)) + strcat(warningStr, "Warning: Controller 4 has a rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[3].Present && (Controls[3].Plugin != PLUGIN_RUMBLE_PAK) && !(m_header.controllerFlags & CONTROLLER_4_RUMBLE)) + strcat(warningStr, "Warning: Controller 4 has a memory pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + if(Controls[3].Present && (Controls[3].Plugin != PLUGIN_NONE) && !(m_header.controllerFlags & (CONTROLLER_4_MEMPAK|CONTROLLER_4_RUMBLE))) + strcat(warningStr, "Warning: Controller 4 does not have a mempak or rumble pack in the movie.\nYou may need to change your input plugin settings accordingly for this movie to play back correctly.\n"); + } + + char str [512], name [512]; + if(ROM_HEADER && stricmp(m_header.romNom, (const char*)ROM_HEADER->nom) != 0) + { + sprintf(str, "The movie was recorded with the ROM \"%s\",\nbut you are using the ROM \"%s\",\nso the movie probably won't play properly.\n", m_header.romNom, ROM_HEADER->nom); + strcat(warningStr, str); + } + else + { + if(ROM_HEADER && m_header.romCountry != ROM_HEADER->Country_code) + { + sprintf(str, "The movie was recorded with a ROM with country code \"%d\",\nbut you are using a ROM with country code \"%d\",\nso the movie may not play properly.\n", m_header.romCountry, ROM_HEADER->Country_code); + strcat(warningStr, str); + } + else if(ROM_HEADER && m_header.romCRC != ROM_HEADER->CRC1) + { + sprintf(str, "The movie was recorded with a ROM that has CRC \"0x%x\",\nbut you are using a ROM with CRC \"0x%x\",\nso the movie may not play properly.\n", (unsigned int)m_header.romCRC, (unsigned int)ROM_HEADER->CRC1); + strcat(warningStr, str); + } + } + + if(strlen(warningStr) > 0) + { + if(dontPlay) + printError(warningStr); + else + printWarning(warningStr); + } + +// ROM_INFO* pRomInfo = getSelectedRom(); // FIXME +// DEFAULT_ROM_SETTINGS TempRomSettings = GetDefaultRomSettings( pRomInfo->InternalName); +// if(TempRomSettings.InputPluginName[0]) +// strncpy(name, TempRomSettings.InputPluginName, 64); +// else + strncpy(name, input_name, 64); + if(name[0] && m_header.inputPluginName[0] && stricmp(m_header.inputPluginName, name) != 0) + { + printf("Warning: The movie was recorded with the input plugin \"%s\",\nbut you are using the input plugin \"%s\",\nso the movie may not play properly.", m_header.inputPluginName, name); + } +// if(TempRomSettings.GfxPluginName[0]) +// strncpy(name, TempRomSettings.GfxPluginName, 64); +// else + strncpy(name, gfx_name, 64); + if(name[0] && m_header.videoPluginName[0] && stricmp(m_header.videoPluginName, name) != 0) + { + printf("Warning: The movie was recorded with the graphics plugin \"%s\",\nbut you are using the graphics plugin \"%s\",\nso the movie might not play properly.", m_header.videoPluginName, name); + } +// if(TempRomSettings.SoundPluginName[0]) +// strncpy(name, TempRomSettings.SoundPluginName, 64); +// else + strncpy(name, sound_name, 64); + if(name[0] && m_header.soundPluginName[0] && stricmp(m_header.soundPluginName, name) != 0) + { + printf("Warning: The movie was recorded with the sound plugin \"%s\",\nbut you are using the sound plugin \"%s\",\nso the movie might not play properly.", m_header.soundPluginName, name); + } +// if(TempRomSettings.RspPluginName[0]) +// strncpy(name, TempRomSettings.RspPluginName, 64); +// else + strncpy(name, rsp_name, 64); + if(name[0] && m_header.rspPluginName[0] && stricmp(m_header.rspPluginName, name) != 0) + { + printf("Warning: The movie was recorded with the RSP plugin \"%s\",\nbut you are using the RSP plugin \"%s\",\nso the movie probably won't play properly.", m_header.rspPluginName, name); + } + + + + if(dontPlay) + return -1; + + + // recalculate length of movie from the file size +// fseek(m_file, 0, SEEK_END); +// int fileSize = ftell(m_file); +// m_header.length_samples = (fileSize - MUP_HEADER_SIZE) / sizeof(BUTTONS) - 1; + + fseek(m_file, MUP_HEADER_SIZE_CUR, SEEK_SET); + + // read controller data + m_inputBufferPtr = m_inputBuffer; + unsigned long to_read = sizeof(BUTTONS) * (m_header.length_samples+1); + reserve_buffer_space(to_read); + fread(m_inputBufferPtr, 1, to_read, m_file); + + // read "baseline" controller data +/// read_frame_controller_data(0); // correct if we can assume the first controller is active, which we can on all GBx/xGB systems +// m_currentSample = 0; + + fseek(m_file, 0, SEEK_END); + + + } break; + default: + fprintf( stderr, "[VCR]: Error playing movie: %s.\n", m_errCodeName[code]); + break; + } + + m_currentSample = 0; + m_currentVI = 0; + + if(m_header.startFlags & MOVIE_START_FROM_SNAPSHOT) + { + // load state + printf( "[VCR]: Loading state...\n" ); + strcpy( buf, m_filename ); + + // remove extension + for(;;) + { + char* dot = strrchr(buf, '.'); + if(dot && (dot > strrchr(buf, '\\') && dot > strrchr(buf, '/'))) + *dot = '\0'; + else + break; + } + + strncat( buf, ".st", PATH_MAX ); + savestates_select_filename( buf ); + savestates_job |= LOADSTATE; + m_task = StartPlaybackFromSnapshot; + } else { + m_task = StartPlayback; + } + + // utf8 strings are also null-terminated so this method still works + if(authorUTF8) + strncpy(m_header.authorInfo, authorUTF8, MOVIE_AUTHOR_DATA_SIZE); + m_header.authorInfo[MOVIE_AUTHOR_DATA_SIZE-1] = '\0'; + if(descriptionUTF8) + strncpy(m_header.description, descriptionUTF8, MOVIE_DESCRIPTION_DATA_SIZE); + m_header.description[MOVIE_DESCRIPTION_DATA_SIZE-1] = '\0'; + + return code; + } +} + + +int +VCR_stopPlayback() +{ + if(m_inputBuffer) + { + free(m_inputBuffer); + m_inputBuffer = NULL; + m_inputBufferPtr = NULL; + m_inputBufferSize = 0; + } + + if (m_file) + { + fclose( m_file ); + m_file = 0; + } + + if (m_task == StartPlayback) + { + m_task = Idle; + return 0; + } + + if (m_task == Playback) + { + m_task = Idle; + printf( "[VCR]: Playback stopped (%ld samples played)\n", m_currentSample ); + +#ifdef __WIN32__ + EnableEmulationMenuItems(TRUE); +#else + // FIXME: how to update enable/disable state of StopPlayback and StopRecord with gtk GUI? +#endif + +#ifdef __WIN32__ + SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Stopped playback."); +#endif + + return 0; + } + + return -1; +} + + + + + +static void SendVideoFrame(void* image) +{ + ++m_vcrsets.n_videoframes_lastcheck; + + m_vcrsets.videopos += m_vcrsets.videoratio; + + int n_to_do = (int)m_vcrsets.videopos; + if(n_to_do < 0) n_to_do = 0; + m_vcrsets.videopos -= n_to_do; + + for(; n_to_do > 0; --n_to_do) + { + if(!VCRComp_addVideoFrame((const unsigned char*)image)) + { + printError("Video codec failure!\nA call to addVideoFrame() (AVIStreamWrite) failed.\nPerhaps you ran out of memory?"); + VCR_stopCapture(); + break; + } + m_vcrsets.audiolead -= m_vcrsets.audioperframe; + } +} + +void +VCR_updateScreen() +{ +// ShowInfo("VCR_updateScreen()"); + static int frame = 0; + + if (!VCR_isCapturing() || readScreen == 0) + { +#ifdef __WIN32__ + if(!manualFPSLimit) + { + // skip 7/8 frames if fast-forwarding and not capturing to AVI + frame++; + if((frame % 8) != 0) + return; + } +#endif + + updateScreen(); + return; + } + + updateScreen(); + + void *image; + long width, height; + readScreen( &image, &width, &height ); + if (image == 0) + { + fprintf( stderr, "[VCR]: Couldn't read screen (out of memory?)\n" ); + return; + } + + if(m_vcrsets.desiredXres == 0 || m_vcrsets.desiredYres == 0) + { + VCRComp_notifyNewRes(width, height); + SendVideoFrame(image); + } + else if(m_vcrsets.desiredXres != width || m_vcrsets.desiredYres != height) + { + LanczosProxy1 proxy1(m_vcrsets.desiredXres, width,height); + const unsigned char* imgptr = (const unsigned char*)image; + LanczosResample(imgptr, width, + proxy1, m_vcrsets.desiredXres); + LanczosProxy2 proxy2(m_vcrsets.desiredXres, m_vcrsets.desiredYres); + LanczosResample(proxy1, height, proxy2, m_vcrsets.desiredYres); + SendVideoFrame((void*)&proxy2.result[0]); + } + else + { + SendVideoFrame(image); + } + if(externalReadScreen) + { + if(image) + free(image); + } +} + + +void +VCR_aiDacrateChanged( int SystemType ) +{ + aiDacrateChanged( SystemType ); + + m_vcrsets.audioBitrate = ai_register.ai_bitrate+1; + + long old_freq = m_vcrsets.audioFreq; + + switch (SystemType) + { + case SYSTEM_NTSC: + m_vcrsets.audioFreq = 48681812 / (ai_register.ai_dacrate + 1); + break; + case SYSTEM_PAL: + m_vcrsets.audioFreq = 49656530 / (ai_register.ai_dacrate + 1); + break; + case SYSTEM_MPAL: + m_vcrsets.audioFreq = 48628316 / (ai_register.ai_dacrate + 1); + break; + } + + if(m_vcrsets.audioFreq != old_freq + && m_vcrsets.desiredAudioFreq == 0) + { + /* If audio freq changed and codec says they can cope with varying rates, + * then announce the new rate. + */ + VCRComp_notifyNewRate(m_vcrsets.audioFreq); + } +} + +// assumes: len <= writeSize +static void writeSound(const unsigned char* buf, int size) +{ + VCRComp_addAudioData(buf, size); + + if(!buf) return; + + bool nearly_ok = (m_vcrsets.n_videoframes_lastcheck == 1 + && dblabs(m_vcrsets.audiolead) < m_vcrsets.audioperframe + && dblabs(size/2/2 - m_vcrsets.audioperframe) <= 16); + + if(m_vcrsets.n_videoframes_lastcheck == 0 + || nearly_ok + ) + { + m_vcrsets.videoratio = 1.0; + } + else + { + double h = size/2/2; + + double number_got + = m_vcrsets.n_videoframes_lastcheck; + double number_shouldhavegot + = h / m_vcrsets.audioperframe; + + m_vcrsets.videoratio = number_shouldhavegot / number_got; + if(m_vcrsets.videoratio < 0.2) m_vcrsets.videoratio = 0.2; + } + + if(m_vcrsets.audiolead != 0 && !nearly_ok) + { + double amount = dblabs(m_vcrsets.audiolead) / m_vcrsets.audioperframe; + + double ratio = 1.1; + if(amount > 10) ratio = 1.3; + else if(ratio < 0.3) ratio = 1.02; + + if(m_vcrsets.audiolead > 0) + m_vcrsets.videoratio *= ratio; + else + m_vcrsets.videoratio /= ratio; + } + + fprintf(stderr, "AudioAdd: adding %d(%+d), had %d frames, lead=%g, ratio=%g\n", + size/2/2, + (int)(size/2/2 - m_vcrsets.audioperframe), + m_vcrsets.n_videoframes_lastcheck, + m_vcrsets.audiolead, m_vcrsets.videoratio); + fflush(stderr); + + m_vcrsets.audiolead += (double)size/2/2; + m_vcrsets.n_videoframes_lastcheck = 0; +} + +void VCR_aiLenChanged() +{ + const short *p = (short *)((char*)rdram + (ai_register.ai_dram_addr & 0xFFFFFF)); + const unsigned char* buf = (const unsigned char*)p; + int aiLen = ai_register.ai_len; + + aiLenChanged(); + if (!VCR_isCapturing()) + return; + + // hack - mupen64 updates bitrate after calling aiDacrateChanged + m_vcrsets.audioBitrate = ai_register.ai_bitrate+1; + + int target_rate = m_vcrsets.desiredAudioFreq; + if(!target_rate) target_rate = m_vcrsets.audioFreq; + + if(target_rate == m_vcrsets.audioFreq + && m_vcrsets.audioBitrate == 16) + { + writeSound(buf, aiLen); + } + else + { + /* Else the sound needs to be resampled. */ + std::vector audio + = ContiguousResample(target_rate / (double)m_vcrsets.audioFreq, + buf, + m_vcrsets.audioBitrate, + aiLen); + writeSound((const unsigned char*)&audio[0], + audio.size() * sizeof(audio[0])); + } +} + + +int +VCR_startCapture( const char *recFilename, const char *aviFilename ) +{ +#ifdef __WIN32__ + BOOL wasPaused = emu_paused; + if(!emu_paused) + { + pauseEmu(TRUE); + } + init_readScreen(); +#endif + if (readScreen == 0) + { + printError("AVI capture failed because the active video plugin does not support ReadScreen()!"); + return -1; + } + + void *dest; + long width, height; + long rate = m_vcrsets.audioFreq; + readScreen( &dest, &width, &height ); + if (dest) free( dest ); + + m_vcrsets.desiredAudioFreq = rate; + m_vcrsets.desiredXres = width; + m_vcrsets.desiredYres = height; + + VCRComp_startFile( aviFilename, + &m_vcrsets.desiredXres, + &m_vcrsets.desiredYres, + &m_vcrsets.desiredAudioFreq, + visByCountrycode()); + + m_vcrsets.BeginNewMovie(); + if(m_vcrsets.desiredAudioFreq != 0) + { + VCRComp_notifyNewRate(rate); + } + if((m_vcrsets.desiredXres != width || m_vcrsets.desiredYres != height) + && (m_vcrsets.desiredXres != 0 || m_vcrsets.desiredYres != 0)) + { + VCRComp_notifyNewRes(width, height); + } + + + +#ifdef __WIN32__ + // disable the toolbar (VCR_isCapturing() causes this call to do that) + // because a bug means part of it could get captured into the AVI + EnableToolbar(); + + if(!wasPaused || (m_task == Playback || m_task == StartPlayback || m_task == StartPlaybackFromSnapshot)) + { + resumeEmu(TRUE); + } +#endif + + printf( "[VCR]: Starting capture...\n" ); + + return 0; +} + +void +VCR_toggleReadOnly () +{ + VCR_setReadOnly(!m_readOnly); + +#ifdef __WIN32__ + SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)(m_readOnly ? "read-only" : "read+write")); +#else + printf("%s\n", m_readOnly ? "read-only" : "read+write"); +#endif +} + + +int +VCR_stopCapture() +{ +// ShowInfo("VCR_stopCapture()"); + m_vcrsets.capturing = false; + writeSound(NULL, 0); + +#ifdef __WIN32__ + // re-enable the toolbar (m_vcrsets.capturing==false causes this call to do that) + EnableToolbar(); +#else + usleep( 100000 ); // HACK - is this really necessary? +#endif + VCRComp_finishFile(); + printf( "[VCR]: Capture finished.\n" ); + return 0; +} + + + + +void +VCR_coreStopped() +{ + if(continue_vcr_on_restart_mode) + return; + + switch (m_task) + { + case StartRecording: + case StartRecordingFromSnapshot: + case Recording: + VCR_stopRecord(); + break; + case StartPlayback: + case StartPlaybackFromSnapshot: + case Playback: + VCR_stopPlayback(); + break; + } + + if (VCR_isCapturing()) + VCR_stopCapture(); +} + +// update frame counter +void VCR_updateFrameCounter () +{ + // input display + char inputDisplay [64]; + inputDisplay[0] = '\0'; + { + BOOL a, b, z, l, r, s, cl, cu, cr, cd, dl, du, dr, dd; + signed char x, y; + dr = (m_lastController1Keys & (0x0001)) != 0; + dl = (m_lastController1Keys & (0x0002)) != 0; + dd = (m_lastController1Keys & (0x0004)) != 0; + du = (m_lastController1Keys & (0x0008)) != 0; + s = (m_lastController1Keys & (0x0010)) != 0; // start button + z = (m_lastController1Keys & (0x0020)) != 0; + b = (m_lastController1Keys & (0x0040)) != 0; + a = (m_lastController1Keys & (0x0080)) != 0; + cr = (m_lastController1Keys & (0x0100)) != 0; + cl = (m_lastController1Keys & (0x0200)) != 0; + cd = (m_lastController1Keys & (0x0400)) != 0; + cu = (m_lastController1Keys & (0x0800)) != 0; + r = (m_lastController1Keys & (0x1000)) != 0; + l = (m_lastController1Keys & (0x2000)) != 0; + x = ((m_lastController1Keys & (0x00FF0000)) >> 16); + y = ((m_lastController1Keys & (0xFF000000)) >> 24); + + if(!x && !y) + strcpy(inputDisplay, ""); + else + { + int xamt = (x<0?-x:x) * 99/127; if(!xamt && x) xamt = 1; + int yamt = (y<0?-y:y) * 99/127; if(!yamt && y) yamt = 1; + if(x && y) + sprintf(inputDisplay, "%c%d %c%d ", x<0?'<':'>', xamt, y<0?'v':'^', yamt); + else if(x) + sprintf(inputDisplay, "%c%d ", x<0?'<':'>', xamt); + else //if(y) + sprintf(inputDisplay, "%c%d ", y<0?'v':'^', yamt); + } + + if(s) strcat(inputDisplay, "S"); + if(z) strcat(inputDisplay, "Z"); + if(a) strcat(inputDisplay, "A"); + if(b) strcat(inputDisplay, "B"); + if(l) strcat(inputDisplay, "L"); + if(r) strcat(inputDisplay, "R"); + if(cu||cd||cl||cr) + { + strcat(inputDisplay, " C"); + if(cu) strcat(inputDisplay, "^"); + if(cd) strcat(inputDisplay, "v"); + if(cl) strcat(inputDisplay, "<"); + if(cr) strcat(inputDisplay, ">"); + } + if(du||dd||dl||dr) + { + strcat(inputDisplay, " D"); + if(du) strcat(inputDisplay, "^"); + if(dd) strcat(inputDisplay, "v"); + if(dl) strcat(inputDisplay, "<"); + if(dr) strcat(inputDisplay, ">"); + } + } + + char str [128]; + if(VCR_isRecording()) + sprintf(str, "%d (%d) %s", (int)m_currentVI, (int)m_currentSample, inputDisplay); + else if(VCR_isPlaying()) + sprintf(str, "%d/%d (%d/%d) %s", (int)m_currentVI, (int)VCR_getLengthVIs(), (int)m_currentSample, (int)VCR_getLengthSamples(), inputDisplay); + else + strcpy(str, inputDisplay); + +#ifdef __WIN32__ + +// // oops, this control isn't even visible during emulation... +// if(VCR_isPlaying()) +// SendMessage( hStatusProgress, PBM_SETPOS, (int)(100.0f * (float)m_currentSample / (float)VCR_getLengthFrames() + 0.5f), 0 ); + + SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)str); + +#else + fprintf(stderr, "%s\r", str); +#endif +} + + + +#endif // VCR_SUPPORT diff -NaHudr a/main/vcr.h b/main/vcr.h --- a/main/vcr.h 2006-08-14 02:09:27.000000000 +0300 +++ b/main/vcr.h 2006-08-14 11:05:01.000000000 +0300 @@ -13,6 +13,10 @@ #include "plugin.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SUCCESS (0) #define WRONG_FORMAT (1) #define WRONG_VERSION (2) @@ -72,7 +76,6 @@ extern BOOL VCR_isPlaying(); extern BOOL VCR_isRecording(); extern BOOL VCR_isCapturing(); -extern void VCR_invalidatedCaptureFrame(); extern BOOL VCR_getReadOnly(); extern void VCR_setReadOnly(BOOL val); extern unsigned long VCR_getLengthVIs(); @@ -135,6 +138,10 @@ extern SMovieHeader VCR_getHeaderInfo(const char* filename); +#ifdef __cplusplus +} +#endif + #endif // VCR_SUPPORT #endif // __VCR_H__ diff -NaHudr a/main/vcr_resample.c b/main/vcr_resample.c --- a/main/vcr_resample.c 2006-08-14 02:09:26.000000000 +0300 +++ b/main/vcr_resample.c 1970-01-01 02:00:00.000000000 +0200 @@ -1,177 +0,0 @@ -#include "../config.h" -#ifdef VCR_SUPPORT - -#include "vcr_resample.h" - -#include -#include -#include -#include - -static const volatile unsigned char Four2Eight[16] = -{ - 0, // 0000 = 00000000 - 17, // 0001 = 00010001 - 34, // 0010 = 00100010 - 51, // 0011 = 00110011 - 68, // 0100 = 01000100 - 85, // 0101 = 01010101 - 102, // 0110 = 01100110 - 119, // 0111 = 01110111 - 136, // 1000 = 10001000 - 153, // 1001 = 10011001 - 170, // 1010 = 10101010 - 187, // 1011 = 10111011 - 204, // 1100 = 11001100 - 221, // 1101 = 11011101 - 238, // 1110 = 11101110 - 255 // 1111 = 11111111 -}; - -int -VCR_getResampleLen(int dst_freq, int src_freq, int src_bitrate, int src_len) -{ - int dst_len; - float ratio; - - // convert bitrate to 16 bits - if (src_bitrate != 16) - { - if (src_bitrate != 4 && src_bitrate != 8) - return -1; // unknown result - - src_len = src_len * (16 / src_bitrate); - } - - ratio = src_freq / (float)dst_freq; - dst_len = src_len / ratio; - - return dst_len; -} - -static void staticMalloc(short** buf, int size, int* prevSize) -{ - if(size <= *prevSize) - return; - if(*buf) - free(*buf); - *buf = malloc(size); - *prevSize = size; -} - -int -VCR_resample( short **dst, int dst_freq, - const short *src, int src_freq, int src_bitrate, int src_len ) -{ - int dst_len, i; - float ratio; - int buf_len; - static short *buf = 0, *left = 0, *right = 0; - static int bufSize=0, leftSize=0, rightSize=0, dstSize=0; - - // convert bitrate to 16 bits - if (src_bitrate != 16) - { - buf_len = src_len * (16 / src_bitrate); - staticMalloc(&buf, buf_len, &bufSize); - if (src_bitrate == 4) - { - for (i = 0; i < (src_len*2); i++) - { - short s = ((char *)src)[i>>1]; - if (i & 1) - { - s &= 0xF0; - s |= (s >> 4); - s |= (s << 8); - } - else - { - s &= 0x0F; - s |= (s << 4); - s |= (s << 8); - } - ((short *)buf)[i] = s; - } - } - else if (src_bitrate == 8) - { - for (i = 0; i < src_len; i++) - { - short s = ((char *)src)[i]; - s |= (s << 8); - ((short *)buf)[i] = s; - } - } - else - { - printf( "[VCR]: resample: Cannot convert sample size from %d to 16 bits\n", src_bitrate ); -// free( buf ); - return -1; // unknown result - } - src = buf; - src_len = buf_len; - } - - ratio = src_freq / (float)dst_freq; - dst_len = src_len / ratio; - - // de-interlace - staticMalloc(&left, dst_len>>1, &leftSize); - staticMalloc(&right, dst_len>>1, &rightSize); -// left = malloc( dst_len>>1 ); -// right = malloc( dst_len>>1 ); - for (i = 0; i < (src_len/2); i += 2) - { - left[i>>1] = src[i]; - right[i>>1] = src[i+1]; - } -// if (buf) -// free( buf ); - -// *dst = malloc( dst_len ); - staticMalloc(dst, dst_len, &dstSize); - - // convert sample rate/re-interlace -/* // very simple algorithm (nearest sample/sample duplication) - for (i = 0; i < (dst_len/2); i += 2) - { - short l, r; - int pos = i*ratio; - l = left[pos]; - r = right[pos]; - (*dst)[i ] = l; - (*dst)[i+1] = r; - }*/ - - // linear interpolation - for (i = 0; i < (dst_len/2); i += 2) - { - short l1, l2, r1, r2, l, r; - float pos = (i/2.0)*ratio; - l1 = left[(int)pos+0]; - r1 = right[(int)pos+0]; - if (pos+1 < (src_len/2)) - { - l2 = left[(int)pos+1]; - r2 = right[(int)pos+1]; - } - else - { - l2 = l1; - r2 = r1; - } - pos = pos-((float)(int)pos); - l = (l1 * (1.0-pos)) + (l2 * pos); - r = (r1 * (1.0-pos)) + (r2 * pos); - (*dst)[i ] = l; - (*dst)[i+1] = r; - } - -// free( left ); -// free( right ); - - return dst_len; -} - -#endif // VCR_SUPPORT diff -NaHudr a/main/vcr_resample.h b/main/vcr_resample.h --- a/main/vcr_resample.h 2006-08-14 02:09:27.000000000 +0300 +++ b/main/vcr_resample.h 1970-01-01 02:00:00.000000000 +0200 @@ -1,16 +0,0 @@ -#include "../config.h" - -#ifdef VCR_SUPPORT - -#ifndef __VCR_RESAMPLE__ -#define __VCR_RESAMPLE__ - -int VCR_resample( short **dst, int dst_freq, - const short *src, int src_freq, int src_bitrate, int src_len ); - - -int VCR_getResampleLen(int dst_freq, int src_freq, int src_bitrate, int src_len); - -#endif // __VCR_RESAMPLE__ - -#endif // VCR_SUPPORT diff -NaHudr a/main/win/main_win.c b/main/win/main_win.c --- a/main/win/main_win.c 2006-08-14 02:09:26.000000000 +0300 +++ b/main/win/main_win.c 2006-08-13 23:39:35.000000000 +0300 @@ -2572,23 +2572,13 @@ if(VCR_isCapturing()) { InvalidateRect(hwnd,NULL,TRUE); - VCR_invalidatedCaptureFrame(); } }*/ -// if(VCR_isCapturing()) -// VCR_invalidatedCaptureFrame(); - BeginPaint(hwnd, &ps); -// if(VCR_isCapturing()) -// VCR_invalidatedCaptureFrame(); - EndPaint(hwnd, &ps); -// if(VCR_isCapturing()) -// VCR_invalidatedCaptureFrame(); - return 0; // case WM_SETCURSOR: diff -NaHudr a/main/win/vcr_compress.c b/main/win/vcr_compress.c --- a/main/win/vcr_compress.c 2006-08-14 02:09:26.000000000 +0300 +++ b/main/win/vcr_compress.c 2006-08-14 01:51:32.000000000 +0300 @@ -151,17 +151,18 @@ return ok; } -void VCRComp_startFile( const char *filename, long width, long height, int fps ) +void VCRComp_startFile( const char *filename, long* width, long* height, + long* rate, int fps ) { avi_opened = 1; frame = 0; infoHeader.biSize = sizeof( BITMAPINFOHEADER ); - infoHeader.biWidth = width; - infoHeader.biHeight = height; + infoHeader.biWidth = *width; + infoHeader.biHeight = *height; infoHeader.biPlanes = 1; infoHeader.biBitCount = 24; infoHeader.biCompression = BI_RGB; - infoHeader.biSizeImage = width * height * 3; + infoHeader.biSizeImage = *width * *height * 3; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = 0; @@ -183,13 +184,14 @@ AVIMakeCompressedStream(&compressed_video_stream, video_stream, &video_options, NULL); AVIStreamSetFormat(compressed_video_stream, 0, &infoHeader, infoHeader.biSize + infoHeader.biClrUsed * sizeof(RGBQUAD)); - + + *rate = 48000; // sound sample = 0; sound_format.wFormatTag = WAVE_FORMAT_PCM; sound_format.nChannels = 2; - sound_format.nSamplesPerSec = 44100; - sound_format.nAvgBytesPerSec = 44100 * (2 * 16 / 8); + sound_format.nSamplesPerSec = *rate; + sound_format.nAvgBytesPerSec = *rate * (2 * 16 / 8); sound_format.nBlockAlign = 2 * 16 / 8; sound_format.wBitsPerSample = 16; sound_format.cbSize = 0; @@ -233,6 +235,14 @@ printf("[VCR]: Finished AVI capture.\n"); } +void VCRComp_notifyNewRate(long rate) +{ +} +void VCRComp_notifyNewRes(long width, long height) +{ +} + + void init_readScreen() { #ifdef __WIN32__ diff -NaHudr a/Makefile b/Makefile --- a/Makefile 2005-08-26 22:52:14.000000000 +0300 +++ b/Makefile 2006-08-14 02:35:38.000000000 +0300 @@ -10,7 +10,7 @@ #CFLAGS =-DX86 -Wall -pipe -g -DEMU64_DEBUG -DCOMPARE_CORE #CFLAGS =-DX86 -Wall -pipe -g -CXXFLAGS =$(CFLAGS) +CXXFLAGS =$(CFLAGS) -Imain GL_PATH =-I/usr/X11R6/include @@ -63,7 +63,6 @@ OBJ_VCR =main/vcr.o \ main/vcr_compress.o \ - main/vcr_resample.o \ main/gui_gtk/vcrcomp_dialog.o OBJ_GTK_GUI =main/gui_gtk/main_gtk.o \ @@ -217,6 +216,9 @@ main/vcr_compress.o: main/vcr_compress.cpp $(CXX) $(CXXFLAGS) -c -o $@ $< `avifile-config --cflags` +main/vcr.o: main/vcr.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< $(GTK_FLAGS) + mupen64_input/main.o: mupen64_input/main.c $(CC) $(CFLAGS) -DUSE_GTK -c -o $@ $< $(GTK_FLAGS) `sdl-config --cflags` diff -NaHudr a/winproject/Makefile.win b/winproject/Makefile.win --- a/winproject/Makefile.win 2005-08-26 22:52:16.000000000 +0300 +++ b/winproject/Makefile.win 2006-08-14 01:52:35.000000000 +0300 @@ -5,8 +5,8 @@ CC = gcc.exe WINDRES = windres.exe RES = mupen64_private.res -OBJ = ../main/rom.o ../memory/memory.o ../r4300/x86/debug.o ../main/win/configdialog.o ../r4300/r4300.o ../main/unzip.o ../r4300/interupt.o ../memory/tlb.o ../memory/dma.o ../memory/pif.o ../r4300/exception.o ../r4300/recomp.o ../r4300/pure_interp.o ../r4300/x86/rjump.o ../main/ioapi.o ../r4300/x86/assemble.o ../r4300/x86/gr4300.o ../r4300/special.o ../r4300/x86/gspecial.o ../r4300/regimm.o ../r4300/x86/gregimm.o ../r4300/tlb.o ../r4300/x86/gtlb.o ../r4300/cop0.o ../r4300/x86/gcop0.o ../r4300/bc.o ../r4300/x86/gbc.o ../r4300/cop1_s.o ../r4300/x86/gcop1_s.o ../r4300/cop1_d.o ../r4300/x86/gcop1_d.o ../r4300/cop1_w.o ../r4300/x86/gcop1_w.o ../r4300/cop1_l.o ../r4300/x86/gcop1_l.o ../r4300/cop1.o ../r4300/x86/gcop1.o ../memory/flashram.o ../main/md5.o ../main/mupenIniApi.o ../main/win/dumplist.o ../main/win/rombrowser.o ../main/win/timers.o ../main/win/translation.o ../main/win/main_win.o ../main/win/inifunctions.o ../main/savestates.o ../main/win/Config.o ../main/win/guifuncs.o ../main/win/RomSettings.o ../main/win/GUI_LogWindow.o ../main/win/kaillera.o ../main/win/commandline.o ../main/vcr.o ../r4300/x86/regcache.o ../main/win/vcr_compress.o ../main/vcr_resample.o ../main/adler32.o $(RES) -LINKOBJ = ../main/rom.o ../memory/memory.o ../r4300/x86/debug.o ../main/win/configdialog.o ../r4300/r4300.o ../main/unzip.o ../r4300/interupt.o ../memory/tlb.o ../memory/dma.o ../memory/pif.o ../r4300/exception.o ../r4300/recomp.o ../r4300/pure_interp.o ../r4300/x86/rjump.o ../main/ioapi.o ../r4300/x86/assemble.o ../r4300/x86/gr4300.o ../r4300/special.o ../r4300/x86/gspecial.o ../r4300/regimm.o ../r4300/x86/gregimm.o ../r4300/tlb.o ../r4300/x86/gtlb.o ../r4300/cop0.o ../r4300/x86/gcop0.o ../r4300/bc.o ../r4300/x86/gbc.o ../r4300/cop1_s.o ../r4300/x86/gcop1_s.o ../r4300/cop1_d.o ../r4300/x86/gcop1_d.o ../r4300/cop1_w.o ../r4300/x86/gcop1_w.o ../r4300/cop1_l.o ../r4300/x86/gcop1_l.o ../r4300/cop1.o ../r4300/x86/gcop1.o ../memory/flashram.o ../main/md5.o ../main/mupenIniApi.o ../main/win/dumplist.o ../main/win/rombrowser.o ../main/win/timers.o ../main/win/translation.o ../main/win/main_win.o ../main/win/inifunctions.o ../main/savestates.o ../main/win/Config.o ../main/win/guifuncs.o ../main/win/RomSettings.o ../main/win/GUI_LogWindow.o ../main/win/kaillera.o ../main/win/commandline.o ../main/vcr.o ../r4300/x86/regcache.o ../main/win/vcr_compress.o ../main/vcr_resample.o ../main/adler32.o $(RES) +OBJ = ../main/rom.o ../memory/memory.o ../r4300/x86/debug.o ../main/win/configdialog.o ../r4300/r4300.o ../main/unzip.o ../r4300/interupt.o ../memory/tlb.o ../memory/dma.o ../memory/pif.o ../r4300/exception.o ../r4300/recomp.o ../r4300/pure_interp.o ../r4300/x86/rjump.o ../main/ioapi.o ../r4300/x86/assemble.o ../r4300/x86/gr4300.o ../r4300/special.o ../r4300/x86/gspecial.o ../r4300/regimm.o ../r4300/x86/gregimm.o ../r4300/tlb.o ../r4300/x86/gtlb.o ../r4300/cop0.o ../r4300/x86/gcop0.o ../r4300/bc.o ../r4300/x86/gbc.o ../r4300/cop1_s.o ../r4300/x86/gcop1_s.o ../r4300/cop1_d.o ../r4300/x86/gcop1_d.o ../r4300/cop1_w.o ../r4300/x86/gcop1_w.o ../r4300/cop1_l.o ../r4300/x86/gcop1_l.o ../r4300/cop1.o ../r4300/x86/gcop1.o ../memory/flashram.o ../main/md5.o ../main/mupenIniApi.o ../main/win/dumplist.o ../main/win/rombrowser.o ../main/win/timers.o ../main/win/translation.o ../main/win/main_win.o ../main/win/inifunctions.o ../main/savestates.o ../main/win/Config.o ../main/win/guifuncs.o ../main/win/RomSettings.o ../main/win/GUI_LogWindow.o ../main/win/kaillera.o ../main/win/commandline.o ../main/vcr.o ../r4300/x86/regcache.o ../main/win/vcr_compress.o ../main/adler32.o $(RES) +LINKOBJ = ../main/rom.o ../memory/memory.o ../r4300/x86/debug.o ../main/win/configdialog.o ../r4300/r4300.o ../main/unzip.o ../r4300/interupt.o ../memory/tlb.o ../memory/dma.o ../memory/pif.o ../r4300/exception.o ../r4300/recomp.o ../r4300/pure_interp.o ../r4300/x86/rjump.o ../main/ioapi.o ../r4300/x86/assemble.o ../r4300/x86/gr4300.o ../r4300/special.o ../r4300/x86/gspecial.o ../r4300/regimm.o ../r4300/x86/gregimm.o ../r4300/tlb.o ../r4300/x86/gtlb.o ../r4300/cop0.o ../r4300/x86/gcop0.o ../r4300/bc.o ../r4300/x86/gbc.o ../r4300/cop1_s.o ../r4300/x86/gcop1_s.o ../r4300/cop1_d.o ../r4300/x86/gcop1_d.o ../r4300/cop1_w.o ../r4300/x86/gcop1_w.o ../r4300/cop1_l.o ../r4300/x86/gcop1_l.o ../r4300/cop1.o ../r4300/x86/gcop1.o ../memory/flashram.o ../main/md5.o ../main/mupenIniApi.o ../main/win/dumplist.o ../main/win/rombrowser.o ../main/win/timers.o ../main/win/translation.o ../main/win/main_win.o ../main/win/inifunctions.o ../main/savestates.o ../main/win/Config.o ../main/win/guifuncs.o ../main/win/RomSettings.o ../main/win/GUI_LogWindow.o ../main/win/kaillera.o ../main/win/commandline.o ../main/vcr.o ../r4300/x86/regcache.o ../main/win/vcr_compress.o ../main/adler32.o $(RES) LIBS = -L"lib" -L"zlib" -mwindows -L. -lz -lcomctl32 -lwinmm -lvfw_avi32 -lvfw_ms32 -s -march=pentium2 -mmmx INCS = -I"include" -I"zlib" CXXINCS = -I"lib/gcc/mingw32/3.4.2/include" -I"include/c++/3.4.2/backward" -I"include/c++/3.4.2/mingw32" -I"include/c++/3.4.2" -I"include" -I"zlib" @@ -185,8 +185,8 @@ ../main/win/commandline.o: ../main/win/commandline.c $(CC) -c ../main/win/commandline.c -o ../main/win/commandline.o $(CFLAGS) -../main/vcr.o: ../main/vcr.c - $(CC) -c ../main/vcr.c -o ../main/vcr.o $(CFLAGS) +../main/vcr.o: ../main/vcr.cpp + $(CC) -c ../main/vcr.cpp -o ../main/vcr.o $(CFLAGS) ../r4300/x86/regcache.o: ../r4300/x86/regcache.c $(CC) -c ../r4300/x86/regcache.c -o ../r4300/x86/regcache.o $(CFLAGS) @@ -194,9 +194,6 @@ ../main/win/vcr_compress.o: ../main/win/vcr_compress.c $(CC) -c ../main/win/vcr_compress.c -o ../main/win/vcr_compress.o $(CFLAGS) -../main/vcr_resample.o: ../main/vcr_resample.c - $(CC) -c ../main/vcr_resample.c -o ../main/vcr_resample.o $(CFLAGS) - ../main/adler32.o: ../main/adler32.c $(CC) -c ../main/adler32.c -o ../main/adler32.o $(CFLAGS) diff -NaHudr a/winproject/mupen64.dev b/winproject/mupen64.dev --- a/winproject/mupen64.dev 2005-10-30 10:36:37.000000000 +0200 +++ b/winproject/mupen64.dev 2006-08-13 23:13:25.000000000 +0300 @@ -1250,16 +1250,6 @@ OverrideBuildCmd=0 BuildCmd= -[Unit121] -FileName=..\main\nesvideos-piece.h -CompileCpp=0 -Folder= -Compile=1 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - [Unit122] FileName=..\main\vcr_resample.h CompileCpp=0