int EOF_EXPORT_TO_LC(EOF_VOCAL_TRACK * tp, char *outputfilename, char *string2, int format) { unsigned long linectr = 0, lyrctr = 0, lastlyrtime = 0, linestart = 0, lineend = 0; unsigned char pitch = 0; FILE *outf = NULL; //Used to open output file FILE *pitchedlyrics = NULL; //Used to open output pitched lyric fle char *vrhythmid = NULL; EOF_PHRASE_SECTION temp; //Used to store the first lyric line in the project, which gets overridden with one covering all lyrics during RS1 export unsigned long original_lines; char *tempoutputfilename = "lyrics.temp"; eof_log("EOF_EXPORT_TO_LC() entered", 1); if((tp == NULL) || (outputfilename == NULL) || (tp->lyrics == 0)) return -1; //Return failure //Initialize variables InitLyrics(); //Initialize all variables in the Lyrics structure InitMIDI(); //Initialize all variables in the MIDI structure qsort(tp->line, (size_t)tp->lines, sizeof(EOF_PHRASE_SECTION), eof_song_qsort_phrase_sections); //Sort the lyric lines temp = tp->line[0]; //Preserve the original lyric line information original_lines = tp->lines; //Set export-specific settings if(format == SCRIPT_FORMAT) { Lyrics.grouping = 2; //Enable line grouping for script.txt export Lyrics.nohyphens = 3; //Disable hyphen output Lyrics.noplus = 1; //Disable plus output Lyrics.filter = DuplicateString("^=%#/"); //Use default filter list Lyrics.defaultfilter = 1; //Track that the above string will need to be freed } else if((format == RS_FORMAT) || (format == RS2_FORMAT)) { Lyrics.noplus = 1; //Disable plus output Lyrics.filter = DuplicateString("^=%#/"); //Use default filter list Lyrics.defaultfilter = 1; //Track that the above string will need to be freed if((format == RS_FORMAT) || (!tp->lines)) { //If exporting to Rocksmith 1 format or if the lyrics don't have any lines defined tp->lines = 0; //Temporarily disregard any existing lyric lines (void) eof_vocal_track_add_line(tp, 0, tp->lyric[tp->lyrics - 1]->pos + 1, 0xFF); //Create a single line encompassing all lyrics } } else if(format == PLAIN_FORMAT) { //This format option is meant to invoke script export with the plain flag set and filtering enabled Lyrics.nohyphens = 3; //Disable hyphen output Lyrics.noplus = 1; //Disable plus output Lyrics.filter = DuplicateString("^=%#/"); //Use default filter list Lyrics.defaultfilter = 1; //Track that the above string will need to be freed format = SCRIPT_FORMAT; Lyrics.plain = 1; Lyrics.grouping = 2; //Enable line grouping for script.txt export } //Import lyrics from EOF structure lyrctr = 0; //Begin indexing into lyrics from the very first lastlyrtime = 0; //First lyric is expected to be greater than or equal to this timestamp for(linectr = 0; linectr < (unsigned long)tp->lines; linectr++) { //For each line of lyrics in the EOF structure linestart = (tp->line[linectr]).start_pos; lineend = (tp->line[linectr]).end_pos; if(linestart > lineend) //If the line starts after it ends { ReleaseMemory(1); return -1; //Return failure } if(lyrctr < tp->lyrics) //If there are lyrics remaining CreateLyricLine(); //Initialize new line of lyrics if((tp->line[linectr]).flags & EOF_LYRIC_LINE_FLAG_OVERDRIVE) //If this line is overdrive Lyrics.overdrive_on = 1; else Lyrics.overdrive_on = 0; while(lyrctr < tp->lyrics) { //For each lyric if((tp->lyric[lyrctr])->text[0] != '\0') { //If this lyric's text isn't an empty string if((tp->lyric[lyrctr])->pos < lastlyrtime) //If this lyric precedes the previous lyric { (void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tLogic error while preparing lyrics for export to file \"%s\"", tempoutputfilename); eof_log(eof_log_string, 1); ReleaseMemory(1); return -1; //Return failure } if((tp->lyric[lyrctr])->pos < linestart) //If this lyric precedes the beginning of the line { (void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tWarning: Lyric \"%s\" at %lums is outside of defined lyric lines", tp->lyric[lyrctr]->text, tp->lyric[lyrctr]->pos); eof_log(eof_log_string, 1); CreateLyricLine(); //Initialize new line of lyrics } if((tp->lyric[lyrctr])->pos > lineend) //If this lyric is placed beyond the end of this line { break; //Break from this while loop to have another line created } pitch = (tp->lyric[lyrctr])->note; //Store the lyric's pitch if((tp->lyric[lyrctr])->note == 0) //Remap EOF's pitchless value to FLC's pitchless value pitch = PITCHLESS; if(!Lyrics.line_on) //If a lyric line is not in progress CreateLyricLine(); //Force one to be before adding the next lyric AddLyricPiece((tp->lyric[lyrctr])->text, (tp->lyric[lyrctr])->pos, (tp->lyric[lyrctr])->pos+(tp->lyric[lyrctr])->length, pitch, 0); //Add the lyric to the Lyrics structure if((Lyrics.lastpiece != NULL) && (Lyrics.lastpiece->lyric[strlen(Lyrics.lastpiece->lyric)-1] == '-')) //If the piece that was just added ended in a hyphen Lyrics.lastpiece->groupswithnext = 1; //Set its grouping status }//If this lyric's text isn't an empty string lyrctr++; //Advance to next lyric } ForceEndLyricLine(); //End the current line of lyrics } if(Lyrics.piececount == 0) //No lyrics imported { ReleaseMemory(1); return 0; //Return no lyrics found } //Load chart tags if(eof_song->tags->artist[0] != '\0') Lyrics.Artist = DuplicateString(eof_song->tags->artist); if(eof_song->tags->title[0] != '\0') Lyrics.Title = DuplicateString(eof_song->tags->title); if(eof_song->tags->frettist[0] != '\0') Lyrics.Editor = DuplicateString(eof_song->tags->frettist); if(eof_song->tags->album[0] != '\0') Lyrics.Album = DuplicateString(eof_song->tags->album); PostProcessLyrics(); //Perform hyphen and grouping validation/handling Lyrics.outfilename = tempoutputfilename; Lyrics.out_format = format; //If the export format is MIDI-based, write a MIDI file header and a MIDI track (track 0) specifying a tempo of 120BPM if((Lyrics.out_format == MIDI_FORMAT) || (Lyrics.out_format == VRHYTHM_FORMAT) || (Lyrics.out_format == SKAR_FORMAT) || (Lyrics.out_format == KAR_FORMAT)) { outf = fopen_err(Lyrics.outfilename,"wb"); //These are binary formats Write_Default_Track_Zero(outf); } //Export lyrics switch(Lyrics.out_format) { case SCRIPT_FORMAT: //Export as script.txt format file outf = fopen_err(Lyrics.outfilename,"wt"); //Script.txt is a text format Export_Script(outf); break; case VL_FORMAT: //Export as VL format file outf = fopen_err(Lyrics.outfilename,"wb"); //VL is a binary format Export_VL(outf); break; case MIDI_FORMAT: //Export as MIDI format file. Default export track is "PART VOCALS" if(string2 == NULL) //If a destination track name wasn't given Lyrics.outputtrack = DuplicateString("PART VOCALS"); //Write track name as PART VOCALS by default else Lyrics.outputtrack = DuplicateString(string2); Export_MIDI(outf); break; case USTAR_FORMAT: //Export as UltraStar format file outf = fopen_err(Lyrics.outfilename,"wt"); //UltraStar is a text format Export_UStar(outf); break; case LRC_FORMAT: //Export as simple LRC case ELRC_FORMAT: //Export as extended LRC outf = fopen_err(Lyrics.outfilename,"wt"); //LRC is a text format Export_LRC(outf); break; case VRHYTHM_FORMAT: //Export as Vocal Rhythm (MIDI and text file) if(string2 == NULL) //If a pitched lyric file wasn't given { fclose_err(outf); return -1; //Return failure } pitchedlyrics = fopen_err(string2,"wt"); //Pitched lyrics is a text format vrhythmid = DuplicateString("G4"); Export_Vrhythm(outf, pitchedlyrics, vrhythmid); fflush_err(pitchedlyrics); //Commit any pending pitched lyric writes to file fclose_err(pitchedlyrics); //Close pitched lyric file free(vrhythmid); break; case SKAR_FORMAT: //Export as Soft Karaoke. Default export track is "Words" if(string2 == NULL) //If a destination track name wasn't given Lyrics.outputtrack = DuplicateString("Words"); //Write track name as "Words" by default else Lyrics.outputtrack = DuplicateString(string2); Export_SKAR(outf); break; case KAR_FORMAT: //Export as unofficial KAR. Default export track is "Melody" if(Lyrics.outputtrack == NULL) { (void) puts("\aNo ouput track name for KAR file was given. A track named \"Melody\" will be used by default"); Lyrics.outputtrack = DuplicateString("Melody"); } Export_MIDI(outf); break; case RS_FORMAT: //Export as Rocksmith XML outf = fopen_err(Lyrics.outfilename,"wt"); //XML is a text format Lyrics.rocksmithver = 1; Export_RS(outf); break; case RS2_FORMAT: //Export as Rocksmith 2 XML outf = fopen_err(Lyrics.outfilename,"wt"); //XML is a text format Lyrics.rocksmithver = 2; Export_RS(outf); break; default: (void) puts("Unexpected error in export switch\nAborting"); exit_wrapper(4); break; } if((Lyrics.out_format == MIDI_FORMAT) || (Lyrics.out_format == VRHYTHM_FORMAT) || (Lyrics.out_format == SKAR_FORMAT) || (Lyrics.out_format == KAR_FORMAT)) { //Update the MIDI header to reflect the number of MIDI tracks written to file for all applicable export formats fseek_err(outf, 10, SEEK_SET); //The number of tracks is 10 bytes in from the start of the file header fputc_err(MIDIstruct.trackswritten>>8, outf); fputc_err(MIDIstruct.trackswritten&0xFF, outf); }
void JB_Load(FILE *inf) { size_t maxlinelength; //I will count the length of the longest line (including NULL char/newline) in the //input file so I can create a buffer large enough to read any line into char *buffer; //Will be an array large enough to hold the largest line of text from input file unsigned long index=0; //Used to index within a line of input text unsigned long index2=0; //Used to index within an output buffer char textbuffer[101]={0}; //Allow for a 100 character lyric text unsigned long processedctr=0; //The current line number being processed in the text file unsigned long bufferctr=0; //Ensure textbuffer[] isn't overflowed char notename=0; //Used for parsing note names double timestamp=0.0; //Used to read timestamp char linetype=0; //Is set to one of the following: 1 = lyric, 2 = line break, 3 = end of file unsigned char pitch=0; //Stores the lyric pitch transposed to middle octave int readerrordetected = 0; assert_wrapper(inf != NULL); //This must not be NULL //Find the length of the longest line maxlinelength=FindLongestLineLength(inf,1); //Allocate memory buffer large enough to hold any line in this file buffer=(char *)malloc_err(maxlinelength); (void) fgets_err(buffer,(int)maxlinelength,inf); //Read first line of text, capping it to prevent buffer overflow if(Lyrics.verbose) printf("\nImporting C9C lyrics from file \"%s\"\n\n",Lyrics.infilename); processedctr=0; //This will be set to 1 at the beginning of the main while loop while(!feof(inf) && !readerrordetected) //Until end of file is reached or fgets() returns an I/O error { processedctr++; if(Lyrics.verbose) printf("\tProcessing line %lu\n",processedctr); index = 0; //Read end of file if(strcasestr_spec(buffer,"ENDFILE")) { //A line starting with "ENDFILE" denotes the end of the lyric entries linetype = 3; } //Read the lyric pitch else if(isalpha(buffer[index])) { //A line starting with an alphabetical letter is a normal lyric entry linetype = 1; notename = toupper(buffer[index++]); if(isalpha(buffer[index])) index++; //The first lyric entry seems to repeat the note name pitch=60; //The pitches will be interpreted as ranging from C4 to B4 switch(notename) //Add value of note in current octave { case 'B': pitch+=11; break; case 'A': pitch+=9; break; case 'G': pitch+=7; break; case 'F': pitch+=5; break; case 'E': pitch+=4; break; case 'D': pitch+=2; break; default: break; } if(buffer[index] == '#') { //If the note name is followed by a sharp character, pitch++; //increase the pitch by one half step index++; //Seek past the sharp character } while(buffer[index] != ':') { //Seek to the expected colon character if(buffer[index] == '\0') { //The line ends unexpectedly printf("Error: Invalid lyric entry in line %lu during C9C lyric import (colon missing)\nAborting\n",processedctr); exit_wrapper(1); } index++; } index++; //Seek beyond the colon //Read the lyric text index2=bufferctr=0; while(!isspace(buffer[index])) { //Until whitespace is reached if(buffer[index] == '\0') { //The line ends unexpectedly printf("Error: Invalid lyric entry in line %lu during C9C lyric import (whitespace missing)\nAborting\n",processedctr); exit_wrapper(2); } textbuffer[index2++] = buffer[index++]; //Copy the character to a buffer bufferctr++; if(bufferctr == 100) { //Unexpectedly long lyric reached printf("Error: Invalid lyric entry in line %lu during C9C lyric import (lyric is too long)\nAborting\n",processedctr); exit_wrapper(3); } } textbuffer[index2++] = '\0'; //Terminate the string }//A line starting with an alphabetical letter is a normal lyric entry //Read line break else if(buffer[index] == '-') { //A line starting with "--:S" is the start of a period of silence between lyrics (will be treated as a line break) linetype = 2; } else { //Invalid input printf("Error: Invalid input \"%s\" in line %lu during C9C import\nAborting\n",&(buffer[index]),processedctr); exit_wrapper(4); } //Seek to timestamp while(!isdigit(buffer[index])) { //Until a number (the timestamp) is reached if(buffer[index] == '\0') { //The line ends unexpectedly printf("Error: Invalid line break entry in line %lu during C9C lyric import (timestamp missing)\nAborting\n",processedctr); exit_wrapper(5); } index++; } //Read timestamp if(sscanf(&(buffer[index]), "%20lf", ×tamp) != 1) { //Double floating point value didn't parse printf("Error: Invalid lyric entry in line %lu during C9C lyric import (error parsing timestamp)\nAborting\n",processedctr); exit_wrapper(6); } timestamp *= 1000.0; //Convert to milliseconds //Adjust previous lyric's end position if(Lyrics.lastpiece) { //If there was a previous lyric unsigned long length; assert_wrapper(Lyrics.lastpiece->lyric != NULL); length = (unsigned long)strlen(Lyrics.lastpiece->lyric); Lyrics.lastpiece->duration = timestamp + 0.5 - Lyrics.realoffset - Lyrics.lastpiece->start; //Remember to offset start by realoffset, otherwise Lyrics.lastpiece->start could be the larger operand, causing an overflow if(Lyrics.lastpiece->lyric[length - 1] == '-') { //If the previous lyric ended in a hyphen, the previous lyric lasts all the way up to the start of this one Lyrics.lastpiece->groupswithnext=1; //The previous lyric piece will group with this one } else { //Otherwise space out the lyrics a bit, 1/32 second was suggested if(Lyrics.lastpiece->duration > 31) Lyrics.lastpiece->duration -= 31; //31ms ~= 1 sec/32 } } //Add lyric if(linetype == 1) //If this line defined a new lyric { //Track for pitch changes, enabling Lyrics.pitch_tracking if applicable if((Lyrics.last_pitch != 0) && (Lyrics.last_pitch != pitch)) //There's a pitch change Lyrics.pitch_tracking=1; Lyrics.last_pitch=pitch; //Consider this the last defined pitch if(Lyrics.line_on != 1) //If we're at this point, there should be a line of lyrics in progress CreateLyricLine(); AddLyricPiece(textbuffer,timestamp + 0.5,timestamp + 0.5,pitch,0); //Add lyric with no defined duration } //Add line break else if(linetype == 2) { //If this line defined a line break EndLyricLine(); Lyrics.lastpiece = NULL; //Prevent the first lyric from the new line from altering the previous lyric's duration, which was set by the line break position } //End processing else break; if(fgets(buffer, (int)maxlinelength,inf) == NULL) //Read next line of text, so the EOF condition can be checked, don't exit on EOF readerrordetected = 1; }//while(!feof(inf) && !readerrordetected) free(buffer); //No longer needed, release the memory before exiting function ForceEndLyricLine(); RecountLineVars(Lyrics.lines); //Rebuild line durations since this lyric format required adjusting timestamps after lines were parsed if(Lyrics.verbose) printf("C9C import complete. %lu lyrics loaded\n\n",Lyrics.piececount); }
void VL_Load(FILE *inf) { unsigned long ctr=0; //Generic counter unsigned long start_off=0; //Starting offset of a lyric piece in milliseconds unsigned long end_off=0; //Ending offset of a lyric piece in milliseconds char *temp=NULL; //Pointer for string manipulation struct VL_Text_entry *curtext=NULL; //Conductor for text chunk linked list struct VL_Sync_entry *cursync=NULL; //Conductor for sync chunk linked list unsigned short cur_line_len=0; //The length of the currently line of lyrics unsigned short start_char=0; //The starting character offset for the current sync entry unsigned short end_char=0; //The ending character offset for the current sync entry char groupswithnext=0; //Tracks grouping, passed to AddLyricPiece() assert_wrapper(inf != NULL); //This must not be NULL Lyrics.freestyle_on=1; //VL is a pitch-less format, so import it as freestyle if(Lyrics.verbose) printf("Importing VL lyrics from file \"%s\"\n\n",Lyrics.infilename); //Build the VL storage structure (void) VL_PreLoad(inf,0); //Process offset if(Lyrics.offsetoverride == 0) { if(Lyrics.Offset == NULL) { if(Lyrics.verbose) (void) puts("No offset defined in VL file, applying offset of 0"); Lyrics.realoffset=0; } else if(strcmp(Lyrics.Offset,"0") != 0) { //If the VL file's offset is not zero and the command line offset is not specified assert_wrapper(Lyrics.Offset != NULL); //atol() crashes if NULL is passed to it Lyrics.realoffset=atol(Lyrics.Offset); //convert to number if(Lyrics.realoffset == 0) //atol returns 0 on error { printf("Error converting \"%s\" to integer value\nAborting\n",Lyrics.Offset); exit_wrapper(1); } if(Lyrics.verbose) printf("Applying offset defined in VL file: %ldms\n",Lyrics.realoffset); } //if the VL file's offset is defined as 0, that's what Lyrics.realoffset is initialized to already } if(Lyrics.verbose) (void) puts("Processing lyrics and sync entries"); //Process sync points, adding lyrics to Lyrics structure cursync=VL.Syncs; //Begin with first sync entry while(cursync != NULL) //For each sync point { groupswithnext=0; //Reset this condition start_off=cursync->start_time*10; //VL stores offsets as increments of 10 milliseconds each end_off=cursync->end_time*10; //Validate the lyric line number if(cursync->lyric_number >= VL.numlines) //lyric_number count starts w/ 0 instead of 1 and should never meet/exceed numlines { (void) puts("Error: Invalid line number detected during VL load\nAborting"); exit_wrapper(2); } //Validate the start and end character numbers in the sync entry start_char=cursync->start_char; end_char=cursync->end_char; if(start_char == 0xFFFF) { (void) puts("Error: Sync entry has no valid lyric during VL load\nAborting"); exit_wrapper(3); } //Seek to the correct lyric entry curtext=VL.Lyrics; //Point conductor to first text entry for(ctr=0; ctr<cursync->lyric_number; ctr++) if(curtext->next == NULL) { (void) puts("Error: Unexpected end of text piece linked list\nAborting"); exit_wrapper(4); } else curtext=curtext->next; //Seek forward to next piece cur_line_len = (unsigned short) strlen(curtext->text); //This value will be used several times in the rest of the loop if(start_char >= cur_line_len) //The starting offset cannot be past the end of the line of lyrics { (void) puts("Error: Sync entry has invalid starting offset during VL load\nAborting"); exit_wrapper(5); } if((end_char!=0xFFFF) && (end_char >= cur_line_len)) { //The ending offset cannot be past the end of the line of lyrics (void) puts("Error: Sync entry has invalid ending offset during VL load\nAborting"); exit_wrapper(6); } //Build the lyric based on the start and end character offsets temp=DuplicateString(curtext->text+start_char); //Copy the current text piece into a new string, starting from the character indexed by the sync entry if(Lyrics.verbose>=2) printf("\tProcessing sync entry #%lu: \"%s\"\tstart char=%u\tend char=%u\t\n",ctr,curtext->text,start_char,end_char); if(end_char != 0xFFFF) //If the sync entry ends before the end of the text piece { //"abcdef" strlen=6 st=2,en=4->"cde" if((isspace((unsigned char)temp[end_char-start_char-1])==0) && (isspace((unsigned char)temp[end_char-start_char])==0)) //if this sync entry's text doesn't end in whitespace and the next entry's doesn't begin in whitespace groupswithnext=1; //Allow AddLyricPiece to handle grouping and optional hyphen insertion //I've had to go back and forth on this line, but currently, end_char-start_char seems to mark the location at which to truncate, not the last character to keep before truncating temp[end_char-start_char]='\0'; //Truncate the string as indicated by the sync entry's end index (after the end_char) } //Add lyric to Lyric structure if(cursync->start_char == 0) //If this piece is the beginning of a line of lyrics { //Ensure a line of lyrics isn't already in progress if(Lyrics.line_on == 1) { (void) puts("Error: Lyric lines overlap during VL load\nAborting"); exit_wrapper(7); } if(Lyrics.verbose>=2) (void) puts("New line of lyrics:"); CreateLyricLine(); //Initialize the line } //Add lyric to Lyrics structure. AddLyricPiece(temp,start_off,end_off,PITCHLESS,groupswithnext); //Add the lyric piece to the Lyric structure, no defined pitch free(temp); //Release memory for this temporary string if((end_char == 0xFFFF) || (end_char == cur_line_len)) //If this piece ends a line of lyrics { //Ensure a line of lyrics is in progress if(Lyrics.line_on == 0) { (void) puts("Error: End of lyric line detected when none is started during VL load\nAborting"); exit_wrapper(8); } if(Lyrics.verbose>=2) (void) puts("End line of lyrics"); EndLyricLine(); //End the line } cursync=cursync->next; }//end while(cursync != NULL) ForceEndLyricLine(); if(Lyrics.verbose) printf("VL import complete. %lu lyrics loaded\n",Lyrics.piececount); ReleaseVL(); //Release memory used to build the VL structure }
void SRT_Load(FILE *inf) { char *buffer; //Buffer used to read from input file char *temp=NULL; //Used for string processing unsigned long processedctr=0; //The current line number being processed in the text file size_t maxlinelength; //I will count the length of the longest line (including NULL char/newline) in the //input file so I can create a buffer large enough to read any line into unsigned long startstamp=0,endstamp=0; unsigned long ctr=0; assert_wrapper(inf != NULL); //This must not be NULL //Find the length of the longest line maxlinelength=FindLongestLineLength(inf,1); //Allocate buffers to read file line by line buffer=malloc_err(maxlinelength); //Process each line of input file if(Lyrics.verbose) printf("\nImporting SRT subtitles from file \"%s\"\n\n",Lyrics.infilename); processedctr=0; //This will be set to 1 at the beginning of the main while loop while(fgets(buffer,(int)maxlinelength,inf) != NULL) //Read lines until end of file is reached, don't exit on EOF { processedctr++; //Find first timestamp in this line temp=SeekNextSRTTimestamp(buffer); //Point temp to first timestamp if(temp == NULL) //If there is none, skip this line continue; //Skip processing and read next line startstamp=ConvertSRTTimestamp(&temp,NULL); //Find second timestamp in this line temp=SeekNextSRTTimestamp(temp); //Point temp to second timestamp if(temp == NULL) { if(Lyrics.verbose) printf("Warning: Line #%lu does not contain the ending timestamp. Ignoring\n",processedctr); continue; //Skip processing and read next line } endstamp=ConvertSRTTimestamp(&temp,NULL); //Read next line, which is expected to be the subtitle entry if(fgets(buffer,(int)maxlinelength,inf) == NULL) break; //If another line couldn't be read, exit loop ctr = (unsigned long)strlen(buffer); //Find index of the string's NULL terminator while((ctr > 0) && ((buffer[ctr-1] == '\n') || (buffer[ctr-1] == '\r'))) { //If the string isn't empty and the last character is a newline or carriage return buffer[ctr-1] = '\0'; //Truncate it from the string ctr--; //Track the position of the end of the string } //Add lyric piece as a lyric line CreateLyricLine(); AddLyricPiece(buffer,startstamp,endstamp,PITCHLESS,0); //Write lyric with no defined pitch EndLyricLine(); }//end while(fgets(buffer,maxlinelength,inf) != NULL) ForceEndLyricLine(); //Release memory buffers and return free(buffer); if(Lyrics.verbose) printf("SRT import complete. %lu subtitles loaded\n\n",Lyrics.piececount); }
void ID3_Load(FILE *inf) { //Parses the file looking for an ID3 tag. If found, the first MP3 frame is examined to obtain the sample rate //Then an SYLT frame is searched for within the ID3 tag. If found, synchronized lyrics are imported struct ID3Tag tag={NULL,0,0,0,0,0,0.0,NULL,0,NULL,NULL,NULL,NULL}; struct ID3Frame *frameptr=NULL; struct ID3Frame *frameptr2=NULL; assert_wrapper(inf != NULL); //This must not be NULL tag.fp=inf; if(Lyrics.verbose) printf("Importing ID3 lyrics from file \"%s\"\n\nParsing input MPEG audio file\n",Lyrics.infilename); if(ID3FrameProcessor(&tag) == 0) //Build a list of the ID3 frames { DestroyID3(&tag); //Release the ID3 structure's memory return; //Return if no frames were successfully parsed } //Parse MPEG frame header fseek_err(tag.fp,tag.tagend,SEEK_SET); //Seek to the first MP3 frame (immediately after the ID3 tag) if(GetMP3FrameDuration(&tag) == 0) //Find the sample rate defined in the MP3 frame { DestroyID3(&tag); //Release the ID3 structure's memory return; //Return if the sample rate was not found or was invalid } frameptr=FindID3Frame(&tag,"SYLT"); //Search ID3 frame list for SYLT ID3 frame frameptr2=FindID3Frame(&tag,"USLT"); //Search ID3 frame list for USLT ID3 frame if(frameptr != NULL) { //Perform Synchronized ID3 Lyric import fseek_err(tag.fp,frameptr->pos,SEEK_SET); //Seek to SYLT ID3 frame SYLT_Parse(&tag); } else if(frameptr2 != NULL) { //Perform Unsynchronized ID3 Lyric import (void) puts("\aUnsynchronized ID3 lyric import currently not supported"); exit_wrapper(1); } else { DestroyID3(&tag); //Release the ID3 structure's memory return; //Return if neither lyric frame is present } //Load song tags Lyrics.Title=GrabID3TextFrame(&tag,"TIT2",NULL,0); //Return the defined song title, if it exists Lyrics.Artist=GrabID3TextFrame(&tag,"TPE1",NULL,0); //Return the defined artist, if it exists Lyrics.Album=GrabID3TextFrame(&tag,"TALB",NULL,0); //Return the defined album, if it exists Lyrics.Year=GrabID3TextFrame(&tag,"TYER",NULL,0); //Return the defined year, if it exists if(Lyrics.Title == NULL) //If there was no Title defined in the ID3v2 tag Lyrics.Title=DuplicateString(tag.id3v1title); //Use one defined in the ID3v1 tag if it exists if(Lyrics.Artist == NULL) //If there was no Artist defined in the ID3v2 tag Lyrics.Artist=DuplicateString(tag.id3v1artist); //Use one defined in the ID3v1 tag if it exists if(Lyrics.Album == NULL) //If there was no Album defined in the ID3v2 tag Lyrics.Album=DuplicateString(tag.id3v1album); //Use one defined in the ID3v1 tag if it exists if(Lyrics.Year == NULL) //If there was no Year defined in the ID3v2 tag Lyrics.Year=DuplicateString(tag.id3v1year); //Use one defined in the ID3v1 tag if it exists ForceEndLyricLine(); DestroyID3(&tag); //Release the ID3 structure's memory if(Lyrics.verbose) printf("ID3 import complete. %lu lyrics loaded\n\n",Lyrics.piececount); }