diff --git a/tools/synch/README b/tools/synch/README new file mode 100644 index 000000000..450bebcd1 --- /dev/null +++ b/tools/synch/README @@ -0,0 +1,22 @@ +Ur-Quan Masters Voice-over synchronization tool + +For Windows: + Unpack into any directory. + From a DOS prompt, execute Synchronizer.exx from within the UQM content + directory it will write out files into content/timestamp/race + When you are done, archive them, and send to: + tcpaiqgvnmbf28f001@sneakemail.com + +To use, select the files you want to play, and hit start. +hitting 'n' is the same as 'Next Screen', and 'p' will pause/unpause. + +Hitting 'space' or 'enter' may have adverse effects, so don't + +For Linux: + The code can be compiled with: + gcc synch.cpp synchronizer.cpp audioSDL.cpp audio.cpp -o synch -DUSE_SDLAUDIO=1 -lfltk -lvorbisfile -lvorbis `sdl-config --cflags --libs` + + You'll need fltk (1.1.x), oggvorbis, and SDL development libraries +installed. + +If you have any questions or issues, please send them to the e-mail above diff --git a/tools/synch/audio.cpp b/tools/synch/audio.cpp new file mode 100644 index 000000000..2b8bde2c3 --- /dev/null +++ b/tools/synch/audio.cpp @@ -0,0 +1,102 @@ +// +// +// Ur-Quan Masters Voice-over / Subtitle Synchronization tool +// Copyright 2003 by Geoffrey Hausheer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// contact tcpaiqgvnmbf28f001@sneakemail.com for bugs/issues +// +#if (USE_SDLAUDIO != 1) +char AUDIO_TYPE[] = "Native"; + +#include +#include +#include +#include +#include +#include "audio.h" + +typedef struct { + HWAVEOUT hWaveOut; + WAVEFORMATEX wfx; + WAVEHDR header; + int paused; + unsigned long time; + +} WAVESTRUCT; + +unsigned long clocks_per_sec = CLOCKS_PER_SEC; +unsigned long get_clock() +{ + return (clock()); +} + +void init_sound () +{ +} + +void reset_sound (WAVESTRUCT *WaveData) +{ + if (WaveData) + { + waveOutReset (WaveData->hWaveOut); + waveOutUnprepareHeader(WaveData->hWaveOut, &WaveData->header, sizeof(WAVEHDR)); + waveOutClose(WaveData->hWaveOut); + delete WaveData->header.lpData; + delete WaveData; + } +} + +void pause_sound (WAVESTRUCT *WaveData) +{ + if (WaveData) + waveOutPause (WaveData->hWaveOut); +} + +void unpause_sound (WAVESTRUCT *WaveData) +{ + if (WaveData) + waveOutRestart (WaveData->hWaveOut); +} + +WAVESTRUCT *play_sound(AUDIOHDR *audiohdr) + + + { + WAVESTRUCT *WaveData = new WAVESTRUCT; + WaveData->hWaveOut = 0; + WaveData->wfx.nSamplesPerSec = audiohdr->samp_freq; + WaveData->wfx.wBitsPerSample = audiohdr->bits_per_sample; + WaveData->wfx.nChannels = audiohdr->channels; + WaveData->wfx.cbSize = 0; + WaveData->wfx.wFormatTag = WAVE_FORMAT_PCM; + WaveData->wfx.nBlockAlign = (WaveData->wfx.wBitsPerSample >> 3) * WaveData->wfx.nChannels; + WaveData->wfx.nAvgBytesPerSec = WaveData->wfx.nBlockAlign * WaveData->wfx.nSamplesPerSec; + + if(waveOutOpen(&WaveData->hWaveOut, WAVE_MAPPER, &WaveData->wfx, + 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) { + fprintf(stderr, "unable to open WAVE_MAPPER device\n"); + return(0); + } + ZeroMemory(&WaveData->header, sizeof(WAVEHDR)); + WaveData->header.dwBufferLength = audiohdr->data_len; + WaveData->header.lpData = audiohdr->data; + waveOutPrepareHeader(WaveData->hWaveOut, &WaveData->header, sizeof(WAVEHDR)); + waveOutWrite(WaveData->hWaveOut, &WaveData->header, sizeof(WAVEHDR)); + return (WaveData); +} +#endif diff --git a/tools/synch/audio.h b/tools/synch/audio.h new file mode 100644 index 000000000..7001a7837 --- /dev/null +++ b/tools/synch/audio.h @@ -0,0 +1,29 @@ +// +// +// Ur-Quan Masters Voice-over / Subtitle Synchronization tool +// Copyright 2003 by Geoffrey Hausheer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// contact tcpaiqgvnmbf28f001@sneakemail.com for bugs/issues +// +typedef struct { + unsigned long samp_freq; + unsigned long bits_per_sample; + unsigned long channels; + char *data; + unsigned long data_len; +} AUDIOHDR; diff --git a/tools/synch/audioSDL.cpp b/tools/synch/audioSDL.cpp new file mode 100644 index 000000000..668b56b25 --- /dev/null +++ b/tools/synch/audioSDL.cpp @@ -0,0 +1,142 @@ +// +// +// Ur-Quan Masters Voice-over / Subtitle Synchronization tool +// Copyright 2003 by Geoffrey Hausheer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// contact tcpaiqgvnmbf28f001@sneakemail.com for bugs/issues +// +#if (USE_SDLAUDIO == 1) +char AUDIO_TYPE[] = "SDL"; + +#include +#include +#include +#include + +#include "audio.h" + +/* doesn't Win32 have M_PI? */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +typedef struct { + SDL_AudioSpec spec; + char *data; + unsigned long data_len; + unsigned long data_pos; +} WAVESTRUCT; + + +void fill_audio(void *u, Uint8 *stream, int len); + +unsigned long clocks_per_sec = 1000; +unsigned long get_clock() +{ + return (SDL_GetTicks()); +} + +void init_sound () +{ + if(SDL_Init(SDL_INIT_AUDIO) < 0) { + fprintf(stderr,"could not initialize SDL audio\n"); + exit(-1); + } +} +WAVESTRUCT *play_sound(AUDIOHDR *audiohdr) +{ + WAVESTRUCT *WaveData = new WAVESTRUCT; +/* + WaveData->spec.freq = 22050; + WaveData->spec.format = AUDIO_S16; + WaveData->spec.channels = 2; + WaveData->spec.samples = 1024; + WaveData->spec.callback = fill_audio; +*/ + WaveData->spec.freq = audiohdr->samp_freq; + WaveData->spec.format = AUDIO_S16; + WaveData->spec.channels = audiohdr->channels; + WaveData->spec.samples = 1024; + WaveData->spec.callback = fill_audio; + WaveData->spec.userdata = WaveData; + WaveData->data = audiohdr->data; + WaveData->data_len = audiohdr->data_len; + WaveData->data_pos = 0; + if(SDL_OpenAudio(&WaveData->spec, NULL) < 0) { + fprintf(stderr,"could not open SDL audio\n"); + exit(-1); + } + SDL_PauseAudio(0); + return (WaveData); +} + +void pause_sound(WAVESTRUCT *WaveData) +{ + if (WaveData) + SDL_PauseAudio(1); +} + +void unpause_sound (WAVESTRUCT *WaveData) +{ + if (WaveData) + SDL_PauseAudio(0); +} + +void reset_sound (WAVESTRUCT *WaveData) +{ + if (WaveData) { + SDL_CloseAudio(); + delete WaveData->data; + delete WaveData; + } +} +/* +void fill_audio (void *u, Uint8 *stream, int len) +{ + Sint16 *b; + int l, i; + double factor; + + printf("%p is %d\n", u, *(int*)u); + factor = Frequency / 22050.0 * 2.0 * M_PI; + l = len * sizeof *stream / sizeof *b; // yuck + b = (Sint16 *)malloc(l * sizeof *b); + for(i = 0; i < l / 2; i++, Offset++) { + double v = cos(Offset * factor); + b[i * 2] = b[i * 2 + 1] = (int)(v * 32767); + } + memcpy(stream, b, len); + free(b); +} +*/ + +void fill_audio (void *u, Uint8 *stream, int len) +{ + Sint16 *b; + int l, i; + long amt_left; + WAVESTRUCT *WaveData = (WAVESTRUCT *)u; + + amt_left = WaveData->data_len - WaveData->data_pos; + if (amt_left > len) + amt_left = len; + memcpy(stream, WaveData->data + WaveData->data_pos, amt_left); + WaveData->data_pos += amt_left; +} + +#endif \ No newline at end of file diff --git a/tools/synch/merge_ts_files.pl b/tools/synch/merge_ts_files.pl new file mode 100755 index 000000000..d7b08f4c4 --- /dev/null +++ b/tools/synch/merge_ts_files.pl @@ -0,0 +1,82 @@ +#!/usr/bin/perl -w +@txtlist = (); +@tsdir = (); +if (! scalar (@ARGV)) { + if (! -d "./comm") { + print "Didn't find 'comm' directory\n"; + exit(1); + } + if (! -d "./timestamp") { + print "Didn't find 'timestamp' directory\n"; + exit(1); + } + foreach $dir (glob "./comm/*") { + ($root) = ($dir =~ /([^\/\\]+)$/); + ($txt) = glob "$dir/*.txt"; + if (! defined $txt) { + printf "Couldn't find $dir/*.txt\n"; + } elsif (-d $dir && -f $txt && -d "./timestamp/$root") { + print "Found $dir\n"; + push @txtlist, $txt; + push @tsdir, "./timestamp/$root"; + } + } +} else { + if ($ARGV[0] =~ /^(.*).txt$/ && -e $ARGV[0]) { + push @txtlist, $ARGV[0]; + } else { + print "Didn't find file: $ARGV[0]\n"; + exit (1); + } + if (! -d $ARGV[1]) { + print "Couldn't find timestamp directory: $ts_dir\n"; + exit (1); + } else { + push @tsdir, $ARGV[1]; + } +} +while (@txtlist) { + $txt_file = pop @txtlist; + $ts_dir = pop @tsdir; + $ts_merge_file = $txt_file; + $ts_merge_file =~ s/\.txt$/.ts/; + print "building $ts_merge_file from $txt_file and $ts_dir\n"; +open (FH, $txt_file); +open (tsFH, ">$ts_merge_file"); +while () { + if (/^#\((\S+)\)/) { + $name = $1; + $str = ""; + if (/\s+(\S+)\s*$/) { + $voice_file = $1; + ($ts_file) = ($voice_file =~ /^(.*).ogg/); + $ts_file = "$ts_dir/$ts_file.ts"; + if (-f $ts_file) { + open (ts1FH, $ts_file); + @data=(); + $chksum = 0; + print "$ts_file\n"; + while () { + chomp; + if (/Checksum:\s+(\d+)/) { + $chksum = $1; + } + if (/^\s+(\S+)/) { + $value = int ($1 *1000); + if ($value != 0) { + push @data, $value - $last_val; + } + $last_val = $value; + } + } + close (ts1FH); + $str = join ",", @data; +# print "$chksum: $str\n"; + } + } + print tsFH "#($name) $str\n"; + } +} +close (FH); +close tsFH; +} diff --git a/tools/synch/synch.cpp b/tools/synch/synch.cpp new file mode 100644 index 000000000..17bf61218 --- /dev/null +++ b/tools/synch/synch.cpp @@ -0,0 +1,480 @@ +// +// +// Ur-Quan Masters Voice-over / Subtitle Synchronization tool +// Copyright 2003 by Geoffrey Hausheer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// contact tcpaiqgvnmbf28f001@sneakemail.com for bugs/issues +// +#define SYNC_VER "0.12" +#define SKIP_SINGLE_LINES +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#define MKDIR mkdir +#else +#include +#define MKDIR(dir) mkdir((dir), 0777) +#endif + +#ifdef __linux__ + #define SYNC_EXTRA_VER "Linux" +#elif defined WIN32 + #define SYNC_EXTRA_VER "Windows" +#else + #define SYNC_EXTRA_VER "Unknown" +#endif +#include +#include +#include + +#include +#include +#include "synchronizer.h" + +#include "synch.h" + +#define WRAP_LEN 50 + +const char races[][13] = { + "arilou", + "blackur", + "chmmr", + "comandr", + "druuge", + "ilwrath", + "melnorm", + "mycon", + "orz", + "pkunk", + "rebel", + "shofixt", + "slyhome", + "slyland", + "spahome", + "spathi", + "starbas", + "supox", + "syreen", + "talkpet", + "thradd", + "umgah", + "urquan", + "utwig", + "vux", + "yehat", + "zoqfot", + "" +}; + +FILEDATA *curtrack, *racedata[MAX_TRACKS]; +CLIPTXTDATA *playing_clip; +XTRATRACKDATA *trackxtra; +Synchronizer *synch; +WAVESTRUCT *WaveData; + +char path[80]; +char savepath[80] = "."; + + +int +main(int argc, char **argv) { + int i = 0; + synch = new Synchronizer; + trackxtra = new XTRATRACKDATA; + init_sound (); +//Initial global objects. + while (strlen(races[i])) + { + synch->RaceChooser->add (races[i], (void *)i); + i++; + } + + synch->show(argc, argv); + + return Fl::run(); +} + +void CleanUp() +{ + int i; + int max = synch->TrackSelector->nitems(); + + for (i=0;iTrackSelector->deactivate(); + synch->RaceChooser->deactivate(); + synch->ChooseAllButton->deactivate(); + synch->ClearAllButton->deactivate(); +} +void ActivateOptions() +{ + synch->TrackSelector->activate(); + synch->RaceChooser->activate(); + synch->ChooseAllButton->activate(); + synch->ClearAllButton->activate(); +} + +void PrintFrameNum () +{ + char buf[20]; + sprintf(buf,"%d of %d",playing_clip->frame_num, curtrack->num_lines); + synch->CurrentFrame->value(buf); +} + +void UpdatePlayTime (int start) +{ + int i, max, mins, secs; + unsigned long tracktime = 0; + char buf[20]; + max = synch->TrackSelector->nitems(); + for (i= start; i <= max; i++) + if (synch->TrackSelector->checked(i)) + tracktime += racedata[i-1]->tracktime; + mins = tracktime / 60; + secs = tracktime - 60 * mins; + sprintf (buf,"%d:%02d",mins,secs); + synch->PlayTime->value(buf); +} + +void StopPlayback () +{ + reset_sound (WaveData); + WaveData=NULL; + trackxtra->tracknum = 0; + ActivateOptions(); +} + +void StartPlayback () +{ + int i, start, max; + max = synch->TrackSelector->nitems(); + if (! trackxtra->tracknum) + { + start = 1; + } else { + start = trackxtra->tracknum + 1; + } + trackxtra->tracknum = 0; + for (i=start; i<= max; i++) { + if (synch->TrackSelector->checked(i)) + { + trackxtra->tracknum = i; + break; + } + } + if (trackxtra->tracknum) + { + char *block;/* pointer to the block */ + unsigned long blockSize;/* holds the size of the block */ + char buf[80]; + AUDIOHDR audiohdr; + trackxtra->paused = 0; + reset_sound (WaveData); + WaveData = NULL; + DeactivateOptions(); + curtrack = racedata[trackxtra->tracknum-1]; + playing_clip = curtrack->clip; + if (! playing_clip) { + fprintf (stderr, "Couldn't find track text for %s\n",curtrack->filename); + return; + } + synch->CurrentTrack->value(curtrack->filename); + UpdatePlayTime(trackxtra->tracknum); + PrintFrameNum(); + synch->TextScreen->value(playing_clip->str); + sprintf (buf, "%s/%s",path, curtrack->filename); + if (read_ogg (buf, &audiohdr)) { + fprintf (stderr, "Ogg Read failed!\n"); + playing_clip = 0; + return; + } + curtrack->chksum = checksum(buf); + WaveData = play_sound(&audiohdr); + trackxtra->time=get_clock(); + } else { + StopPlayback(); + } +} + + +void RestartFrame () +{ + if (trackxtra->tracknum) { + trackxtra->tracknum--; + } + StartPlayback(); +} + +void SaveTimestamps() +{ + char buf[80], buf1[80]; + CLIPTXTDATA *curclip; + FILE *fh; + strcpy (buf1, curtrack->filename); + buf1[strlen(buf1)-4]=0; + sprintf (buf, "%s/%s.ts",savepath, buf1); + fh = fopen(buf,"w"); + fprintf(fh,"Version: %s-%s-%s\n",SYNC_VER, SYNC_EXTRA_VER, AUDIO_TYPE); + fprintf(fh,"Checksum: %lu\n",curtrack->chksum); + curclip = curtrack->clip; + while (curclip != NULL) { + fprintf(fh,"%8.3f\n",(double)(curclip->time)/clocks_per_sec); + curclip = curclip->Next; + } + fclose (fh); +} + + +void NextFrame () +{ + unsigned long curtime; + if (! trackxtra->tracknum || trackxtra->paused) + return; + if (playing_clip->Next == NULL) + StartPlayback(); + else { + curtime = get_clock(); + printf ("Frame time: %d\n",curtime-trackxtra->time); + playing_clip = playing_clip->Next; + playing_clip->time = curtime-trackxtra->time; + synch->TextScreen->value(playing_clip->str); + PrintFrameNum(); + if (playing_clip->Next == NULL) + SaveTimestamps(); + } + +} + +void wrapstr (char *dst, char *src) +{ + int i,j,last=0; + for (i = 0; i < strlen (src); i++) { + *dst++ = src[i]; + if (i == last) { + if (i != 0) { + *dst++ = '\n'; + } + last = strlen(src); + for (j=i+1; j < strlen (src); j++) { + if (j -i > WRAP_LEN) + break; + if (src[j] == ' ') { + last = j; + } + } + if (j == strlen (src)) + last = j; + } + } + *dst = 0; +} + +void PauseFrame () +{ + unsigned long curtime; + if(trackxtra->paused) + unpause_sound(WaveData); + else + pause_sound(WaveData); + curtime = get_clock(); + trackxtra->time = curtime - trackxtra->time; + trackxtra->paused = ! trackxtra->paused; +} + +void GetTracks (int value) +{ + const char *race; + char buf[80]; + char str[MAX_LEN]; + int i = 0, read_data = 0; + CLIPTXTDATA *curclip; + FILE *fh; + + race = races[value - 1]; + CleanUp(); + sprintf (path, "comm/%s",race); + sprintf (buf, "%s/%s.txt",path, race); + fh = fopen (buf, "r"); + if (!fh) { + char buf1[100]; + sprintf (buf1, "Could not find %s!",buf); + fl_alert (buf1); + return; + } + char tmp[80]; + MKDIR ("timestamp"); + sprintf(savepath,"timestamp/%s",race); + MKDIR (savepath); + synch->TrackSelector->clear (); + while (fgets(str,512,fh)) + { + str[strlen (str) - 1] = 0; + if(str[0] == '#') + { + char *tmp; + read_data = 0; + tmp = strtok (str, "\t "); + if ((tmp = strtok (NULL, "\t ")) != NULL) + { +#ifdef SKIP_SINGLE_LINES + if (i && racedata[i-1]->num_lines < 2) { + delete racedata[i-1]; + i--; + } +#endif + if (i && ! racedata[i-1]->tracktime) { + char buf[80]; + sprintf(buf,"%s/%s",path, racedata[i-1]->filename); + racedata[i-1]->tracktime = get_ogg_runtime(buf); + synch->TrackSelector->add (racedata[i-1]->filename); + if (! racedata[i-1]->tracktime) { + fprintf(stderr, "couldn't read %s\n", racedata[i-1]->filename); + racedata[i-1]->tracktime = 1; + } + } + i++; + racedata[i-1] = new FILEDATA; + strcpy (racedata[i-1]->filename, tmp); + curclip = NULL; + read_data = 1; + } + } + else if (read_data && strlen (str)) + { + if (racedata[i-1]->clip == NULL) { + racedata[i-1]->clip = new CLIPTXTDATA; + curclip = racedata[i-1]->clip; + } else { + curclip->Next = new CLIPTXTDATA; + curclip = curclip->Next; + } + wrapstr (curclip->str, str); + racedata[i-1]->num_lines++; + curclip->frame_num = racedata[i-1]->num_lines; + } + if (feof (fh)) + break; + + } +#ifdef SKIP_SINGLE_LINES + if (i && racedata[i-1]->num_lines < 2) { + delete racedata[i-1]; + i--; + } +#endif + if (i && ! racedata[i-1]->tracktime) { + char buf[80]; + sprintf(buf,"%s/%s",path, racedata[i-1]->filename); + racedata[i-1]->tracktime = get_ogg_runtime(buf); + synch->TrackSelector->add (racedata[i-1]->filename); + } + synch->TrackSelector->position (1); +} + +unsigned long +get_ogg_runtime (char *filename) { + OggVorbis_File vf; + vorbis_info *vi; + FILE *fh; + unsigned long runtime; + double rt; + fh = fopen(filename, "rb"); + if (fh == NULL) + return (0); + if(ov_open(fh, &vf, NULL, 0) < 0) + return (0); + rt = ov_time_total(&vf, -1); + runtime = (unsigned long)(rt + 0.5); + ov_clear(&vf); + fclose(fh); + printf("%s : %lu (%f)\n",filename, runtime, rt); + return(runtime); +} +int +read_ogg (char *filename, AUDIOHDR *audiohdr) { + OggVorbis_File vf; + vorbis_info *vi; + FILE *fh; + char *wav; + int current_section; + + fh = fopen(filename, "rb"); + if (fh == NULL) { + fprintf (stderr, "Couldn't find file: %s\n", filename); + return (1); + } + if(ov_open(fh, &vf, NULL, 0) < 0) { + fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n"); + return (1); + } + vi=ov_info(&vf,-1); + audiohdr->samp_freq = vi->rate; + audiohdr->channels = vi->channels; + audiohdr->bits_per_sample = 16; + { + const unsigned int extra=10000; + unsigned int numsamples = extra+(unsigned int)ov_pcm_total(&vf,0); + unsigned int numbytes = numsamples*vi->channels*2; // 16bit output wav + char *wavptr; + int eof = 0; + unsigned long readbytes = 0; + audiohdr->data = new char[numbytes]; + wavptr = audiohdr->data; + while(!eof){ + long ret=ov_read(&vf,wavptr,numbytes-readbytes,0,2,1,¤t_section); + if (ret == 0) { + eof=1; + } else if (ret > 0) { + readbytes += ret; + wavptr += ret; + } + } + audiohdr->data_len = readbytes; + } + ov_clear(&vf); + fclose(fh); + return (0); +} + +unsigned long checksum(char *filename) +{ + int fh; + unsigned long chk= 0, buf = 0; + fh = open(filename,O_RDONLY); + if (fh == -1) + return 0; + while (read (fh,&buf,sizeof(buf)) > 0 ) + chk = ((chk << 1) | (chk >> 31)) ^ buf; + close(fh); + return (chk); +} diff --git a/tools/synch/synch.h b/tools/synch/synch.h new file mode 100644 index 000000000..ba97b2f7e --- /dev/null +++ b/tools/synch/synch.h @@ -0,0 +1,94 @@ +// +// +// Ur-Quan Masters Voice-over / Subtitle Synchronization tool +// Copyright 2003 by Geoffrey Hausheer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// contact tcpaiqgvnmbf28f001@sneakemail.com for bugs/issues +// +#include "audio.h" + +#define MAX_LEN 200 +#define MAX_TRACKS 300 +typedef struct CLIPTXTDATA { + char str[MAX_LEN]; + unsigned long time; + int frame_num; + CLIPTXTDATA *Next; + CLIPTXTDATA () + { + str[0] = 0; + time = 0; + frame_num = 0; + Next = NULL; + } + ~CLIPTXTDATA () + { + if(Next !=NULL) + delete Next; + } +} CLIPTXTDATA; + +typedef struct FILEDATA { + char filename[20]; + int num_lines; + long chksum; + unsigned long tracktime; + CLIPTXTDATA *clip; + FILEDATA () + { + num_lines = 0; + clip = NULL; + chksum = 0; + tracktime = 0; + filename[0] = 0; + } + ~FILEDATA() + { + if (clip != NULL) + delete clip; + clip = NULL; + } +} FILEDATA; + +typedef struct XTRATRACKDATA { + unsigned long time; + int tracknum; + int paused; + XTRATRACKDATA () { + time = 0; + tracknum = 0; + paused = 0; + } +} XTRATRACKDATA; + +int read_ogg (char *filename, AUDIOHDR *audiohdr); +unsigned long get_ogg_runtime (char *filename); +unsigned long checksum(char *filename); + + +unsigned long get_clock(); +extern unsigned long clocks_per_sec; +extern char AUDIO_TYPE[]; + +typedef struct {int bogus;} WAVESTRUCT; +void init_sound (); +void reset_sound (WAVESTRUCT *WaveData); +void pause_sound (WAVESTRUCT *WaveData); +void unpause_sound (WAVESTRUCT *WaveData); +WAVESTRUCT *play_sound(AUDIOHDR *audiohdr); + diff --git a/tools/synch/synchronizer.cpp b/tools/synch/synchronizer.cpp new file mode 100644 index 000000000..bbcd83941 --- /dev/null +++ b/tools/synch/synchronizer.cpp @@ -0,0 +1,158 @@ +// generated by Fast Light User Interface Designer (fluid) version 1.0102 + +#include "synchronizer.h" + +inline void Synchronizer::cb_Exit_i(Fl_Menu_*, void*) { + DoExit(); +} +void Synchronizer::cb_Exit(Fl_Menu_* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_Exit_i(o,v); +} + +Fl_Menu_Item Synchronizer::menu_MainMenu[] = { + {"File", 0, 0, 0, 64, 0, 0, 14, 56}, + {"Exit", 0, (Fl_Callback*)Synchronizer::cb_Exit, 0, 0, 0, 0, 14, 56}, + {0}, + {0} +}; +Fl_Menu_Item* Synchronizer::File = Synchronizer::menu_MainMenu + 0; +Fl_Menu_Item* Synchronizer::Exit = Synchronizer::menu_MainMenu + 1; + +inline void Synchronizer::cb_RaceChooser_i(Fl_Browser*, void*) { + GetTracks (RaceChooser->value()); +} +void Synchronizer::cb_RaceChooser(Fl_Browser* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_RaceChooser_i(o,v); +} + +inline void Synchronizer::cb_TrackSelector_i(Fl_Check_Browser*, void*) { + UpdatePlayTime(1); +} +void Synchronizer::cb_TrackSelector(Fl_Check_Browser* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_TrackSelector_i(o,v); +} + +inline void Synchronizer::cb_ChooseAllButton_i(Fl_Button*, void*) { + TrackSelector->check_all();UpdatePlayTime(1); +} +void Synchronizer::cb_ChooseAllButton(Fl_Button* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_ChooseAllButton_i(o,v); +} + +inline void Synchronizer::cb_ClearAllButton_i(Fl_Button*, void*) { + TrackSelector->check_none();UpdatePlayTime(1); +} +void Synchronizer::cb_ClearAllButton(Fl_Button* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_ClearAllButton_i(o,v); +} + +inline void Synchronizer::cb_PauseButton_i(Fl_Button*, void*) { + PauseFrame (); +} +void Synchronizer::cb_PauseButton(Fl_Button* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_PauseButton_i(o,v); +} + +inline void Synchronizer::cb_NextButton_i(Fl_Button*, void*) { + NextFrame(); +} +void Synchronizer::cb_NextButton(Fl_Button* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_NextButton_i(o,v); +} + +inline void Synchronizer::cb_StartButton_i(Fl_Button*, void*) { + StartPlayback (); +} +void Synchronizer::cb_StartButton(Fl_Button* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_StartButton_i(o,v); +} + +inline void Synchronizer::cb_RestartButton_i(Fl_Button*, void*) { + RestartFrame (); +} +void Synchronizer::cb_RestartButton(Fl_Button* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_RestartButton_i(o,v); +} + +inline void Synchronizer::cb_StopButton_i(Fl_Button*, void*) { + StopPlayback(); +} +void Synchronizer::cb_StopButton(Fl_Button* o, void* v) { + ((Synchronizer*)(o->parent()->user_data()))->cb_StopButton_i(o,v); +} + +Synchronizer::Synchronizer() { + Fl_Window* w; + { Fl_Window* o = MainWindow = new Fl_Window(597, 356); + w = o; + o->user_data((void*)(this)); + { Fl_Menu_Bar* o = MainMenu = new Fl_Menu_Bar(0, 0, 475, 25); + o->menu(menu_MainMenu); + } + { Fl_Output* o = CurrentTrack = new Fl_Output(245, 25, 135, 25, "Playing track:"); + CurrentTrack->deactivate(); + } + { Fl_Output* o = CurrentFrame = new Fl_Output(455, 25, 135, 25, "Frame:"); + CurrentFrame->deactivate(); + } + { Fl_Output* o = PlayTime = new Fl_Output(475, 0, 115, 25, "Time left:"); + PlayTime->deactivate(); + } + { Fl_Output* o = TextScreen = new Fl_Output(155, 50, 435, 180); + o->type(12); + o->textsize(16); + TextScreen->deactivate(); + } + { Fl_Slider* o = Slider = new Fl_Slider(155, 235, 435, 30); + o->type(5); + Slider->deactivate(); + } + { Fl_Browser* o = RaceChooser = new Fl_Browser(0, 50, 145, 105); + o->type(2); + o->callback((Fl_Callback*)cb_RaceChooser); + RaceChooser->has_scrollbar(Fl_Browser_::VERTICAL); + } + { Fl_Check_Browser* o = TrackSelector = new Fl_Check_Browser(0, 180, 145, 120); + o->callback((Fl_Callback*)cb_TrackSelector); + o->when(FL_WHEN_RELEASE); + TrackSelector->has_scrollbar(Fl_Browser_::VERTICAL); + } + { Fl_Button* o = ChooseAllButton = new Fl_Button(10, 305, 120, 20, "Choose All"); + o->callback((Fl_Callback*)cb_ChooseAllButton); + } + { Fl_Button* o = ClearAllButton = new Fl_Button(10, 330, 120, 20, "Clear All"); + o->callback((Fl_Callback*)cb_ClearAllButton); + } + new Fl_Box(0, 30, 130, 20, "Race"); + new Fl_Box(5, 160, 120, 20, "Track"); + { Fl_Button* o = PauseButton = new Fl_Button(335, 280, 105, 45, " Pause"); + o->shortcut(0x70); + o->labelfont(1); + o->labelsize(16); + o->callback((Fl_Callback*)cb_PauseButton); + } + { Fl_Button* o = NextButton = new Fl_Button(155, 280, 135, 45, "Next Screen"); + o->shortcut(0x6e); + o->labelfont(1); + o->labelsize(16); + o->callback((Fl_Callback*)cb_NextButton); + } + { Fl_Button* o = StartButton = new Fl_Button(490, 305, 100, 20, "Start"); + o->labelfont(1); + o->callback((Fl_Callback*)cb_StartButton); + } + { Fl_Button* o = RestartButton = new Fl_Button(490, 280, 100, 20, "Restart"); + o->labelfont(1); + o->callback((Fl_Callback*)cb_RestartButton); + } + { Fl_Button* o = StopButton = new Fl_Button(490, 330, 100, 20, "Stop"); + o->labelfont(1); + o->callback((Fl_Callback*)cb_StopButton); + } + o->end(); + } +} + +void Synchronizer::show(int argc, char **argv) { + MainWindow->show(argc, argv); +} diff --git a/tools/synch/synchronizer.fl b/tools/synch/synchronizer.fl new file mode 100644 index 000000000..6916fbf04 --- /dev/null +++ b/tools/synch/synchronizer.fl @@ -0,0 +1,132 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0102 +header_name {.h} +code_name {.cpp} +decl {extern void NextFrame ();} {public +} + +decl {extern void PauseFrame ();} {public +} + +decl {extern void GetTracks(int value);} {public +} + +decl {extern void StartPlayback();} {public +} + +decl {extern void StopPlayback();} {public +} + +decl {extern void RestartFrame();} {public +} + +decl {extern void DoExit();} {public +} + +decl {extern void UpdatePlayTime(int);} {selected public +} + +class Synchronizer {open +} { + Function {Synchronizer()} {open + } { + Fl_Window MainWindow {open + xywh {366 309 597 356} visible + } { + Fl_Menu_Bar MainMenu {open + xywh {0 0 475 25} + } { + submenu File { + label File open + xywh {0 0 100 20} + } { + menuitem Exit { + label Exit + callback {DoExit();} + xywh {5 5 100 20} + } + } + } + Fl_Output CurrentTrack { + label {Playing track:} + xywh {245 25 135 25} + code0 {CurrentTrack->deactivate();} + } + Fl_Output CurrentFrame { + label {Frame:} + xywh {455 25 135 25} + code0 {CurrentFrame->deactivate();} + } + Fl_Output PlayTime { + label {Time left:} + xywh {475 0 115 25} + code0 {PlayTime->deactivate();} + } + Fl_Output TextScreen { + xywh {155 50 435 180} type Multiline textsize 16 + code0 {TextScreen->deactivate();} + } + Fl_Slider Slider { + xywh {155 235 435 30} type {Horz Knob} + code0 {Slider->deactivate();} + } + Fl_Browser RaceChooser { + callback {GetTracks (RaceChooser->value());} + xywh {0 50 145 105} type Hold + code0 {RaceChooser->has_scrollbar(Fl_Browser_::VERTICAL);} + } + Fl_Check_Browser TrackSelector { + callback {UpdatePlayTime(1);} + xywh {0 180 145 120} when 4 + code0 {TrackSelector->has_scrollbar(Fl_Browser_::VERTICAL);} + } + Fl_Button ChooseAllButton { + label {Choose All} + callback {TrackSelector->check_all();UpdatePlayTime(1);} + xywh {10 305 120 20} + } + Fl_Button ClearAllButton { + label {Clear All} + callback {TrackSelector->check_none();UpdatePlayTime(1);} + xywh {10 330 120 20} + } + Fl_Box {} { + label Race + xywh {0 30 130 20} + } + Fl_Box {} { + label Track + xywh {5 160 120 20} + } + Fl_Button PauseButton { + label { Pause} + callback {PauseFrame ();} + xywh {335 280 105 45} shortcut 0x70 labelfont 1 labelsize 16 + } + Fl_Button NextButton { + label {Next Screen} + callback {NextFrame();} + xywh {155 280 135 45} shortcut 0x6e labelfont 1 labelsize 16 + } + Fl_Button StartButton { + label Start + callback {StartPlayback ();} + xywh {490 305 100 20} labelfont 1 + } + Fl_Button RestartButton { + label Restart + callback {RestartFrame ();} + xywh {490 280 100 20} labelfont 1 + } + Fl_Button StopButton { + label Stop + callback {StopPlayback();} + xywh {490 330 100 20} labelfont 1 + } + } + } + Function {show(int argc, char **argv)} {open + } { + code {MainWindow->show(argc, argv);} {} + } +} diff --git a/tools/synch/synchronizer.h b/tools/synch/synchronizer.h new file mode 100644 index 000000000..29242c974 --- /dev/null +++ b/tools/synch/synchronizer.h @@ -0,0 +1,87 @@ +// generated by Fast Light User Interface Designer (fluid) version 1.0102 + +#ifndef synchronizer_h +#define synchronizer_h +#include +extern void NextFrame (); +extern void PauseFrame (); +extern void GetTracks(int value); +extern void StartPlayback(); +extern void StopPlayback(); +extern void RestartFrame(); +extern void DoExit(); +extern void UpdatePlayTime(int); +#include +#include +#include +#include +#include +#include +#include +#include + +class Synchronizer { +public: + Synchronizer(); + Fl_Window *MainWindow; + Fl_Menu_Bar *MainMenu; + static Fl_Menu_Item menu_MainMenu[]; + static Fl_Menu_Item *File; + static Fl_Menu_Item *Exit; +private: + inline void cb_Exit_i(Fl_Menu_*, void*); + static void cb_Exit(Fl_Menu_*, void*); +public: + Fl_Output *CurrentTrack; + Fl_Output *CurrentFrame; + Fl_Output *PlayTime; + Fl_Output *TextScreen; + Fl_Slider *Slider; + Fl_Browser *RaceChooser; +private: + inline void cb_RaceChooser_i(Fl_Browser*, void*); + static void cb_RaceChooser(Fl_Browser*, void*); +public: + Fl_Check_Browser *TrackSelector; +private: + inline void cb_TrackSelector_i(Fl_Check_Browser*, void*); + static void cb_TrackSelector(Fl_Check_Browser*, void*); +public: + Fl_Button *ChooseAllButton; +private: + inline void cb_ChooseAllButton_i(Fl_Button*, void*); + static void cb_ChooseAllButton(Fl_Button*, void*); +public: + Fl_Button *ClearAllButton; +private: + inline void cb_ClearAllButton_i(Fl_Button*, void*); + static void cb_ClearAllButton(Fl_Button*, void*); +public: + Fl_Button *PauseButton; +private: + inline void cb_PauseButton_i(Fl_Button*, void*); + static void cb_PauseButton(Fl_Button*, void*); +public: + Fl_Button *NextButton; +private: + inline void cb_NextButton_i(Fl_Button*, void*); + static void cb_NextButton(Fl_Button*, void*); +public: + Fl_Button *StartButton; +private: + inline void cb_StartButton_i(Fl_Button*, void*); + static void cb_StartButton(Fl_Button*, void*); +public: + Fl_Button *RestartButton; +private: + inline void cb_RestartButton_i(Fl_Button*, void*); + static void cb_RestartButton(Fl_Button*, void*); +public: + Fl_Button *StopButton; +private: + inline void cb_StopButton_i(Fl_Button*, void*); + static void cb_StopButton(Fl_Button*, void*); +public: + void show(int argc, char **argv); +}; +#endif