int eof_export_bandfuse(EOF_SONG * sp, char * fn, unsigned short *user_warned) { PACKFILE * fp; char buffer[600] = {0}, buffer2[600] = {0}; EOF_PRO_GUITAR_TRACK *tp; char restore_tech_view = 0; //If tech view is in effect, it is temporarily disabled so that the correct notes are exported unsigned long ctr, ctr2, ctr3, ctr4, ctr5, gemcount, bitmask, guitartracknum = 0, basstracknum = 0; eof_log("eof_export_bandfuse() entered", 1); if(!sp || !fn || !sp->beats || !user_warned) { eof_log("\tError saving: Invalid parameters", 1); return 0; //Return failure } fp = pack_fopen(fn, "w"); if(!fp) { eof_log("\tError saving: Cannot open file for writing", 1); return 0; //Return failure } //Write the song metadata (void) pack_fputs("<?xml version='1.0' encoding='UTF-8'?>\n", fp); (void) pack_fputs("<Bandfuse>\n", fp); (void) pack_fputs("<!-- " EOF_VERSION_STRING " -->\n", fp); //Write EOF's version in an XML comment expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->title, 64, 0); //Expand XML special characters into escaped sequences if necessary, and check against the maximum supported length of this field (void) snprintf(buffer, sizeof(buffer) - 1, " <title>%s</title>\n", buffer2); (void) pack_fputs(buffer, fp); expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->artist, 256, 0); //Replace any special characters in the artist song property with escape sequences if necessary (void) snprintf(buffer, sizeof(buffer) - 1, " <artistName>%s</artistName>\n", buffer2); (void) pack_fputs(buffer, fp); expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->album, 256, 0); //Replace any special characters in the album song property with escape sequences if necessary (void) snprintf(buffer, sizeof(buffer) - 1, " <albumName>%s</albumName>\n", buffer2); (void) pack_fputs(buffer, fp); expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->year, 32, 0); //Replace any special characters in the year song property with escape sequences if necessary (void) snprintf(buffer, sizeof(buffer) - 1, " <albumYear>%s</albumYear>\n", buffer2); (void) pack_fputs(buffer, fp); //Write tempo changes (void) pack_fputs(" <tempochanges>\n", fp); ctr = 0; //Begin with the first beat while(ctr < sp->beats) { //Until the last beat has been reached for(ctr2 = ctr + 1; ctr2 < sp->beats; ctr2++) { //For each beat that follows if(sp->beat[ctr]->ppqn != sp->beat[ctr2]->ppqn) { //If the following beat has a different tempo break; //Break from inner for loop } } if(ctr2 < sp->beats) { //If a beat with a different tempo was found, that beat is written as the end position of this tempo change (void) snprintf(buffer, sizeof(buffer) - 1, " <tempo start=\"%lu\" end=\"%lu\" tempo=\"%f\">\n", sp->beat[ctr]->pos, sp->beat[ctr2]->pos, 60000000.0 / (double)sp->beat[ctr]->ppqn); } else { //No remaining beats had a different tempo, the outer for loop's beat is written as the end position of this tempo change (void) snprintf(buffer, sizeof(buffer) - 1, " <tempo start=\"%lu\" end=\"%lu\" tempo=\"%f\">\n", sp->beat[ctr]->pos, sp->beat[ctr]->pos, 60000000.0 / (double)sp->beat[ctr]->ppqn); } (void) pack_fputs(buffer, fp); ctr = ctr2; //Advance the beat counter } (void) pack_fputs(" </tempochanges>\n", fp); for(ctr = 1; ctr < sp->tracks; ctr++) { //For each track if(ctr >= EOF_TRACKS_MAX) break; //Redundant bounds check to satisfy a false positive with Coverity if(sp->track[ctr]->track_format != EOF_PRO_GUITAR_TRACK_FORMAT) continue; //If this isn't a pro guitar/bass track, skip it if(ctr == EOF_TRACK_PRO_GUITAR_B) continue; //If this is the bonus Rocksmith arrangement, skip it tp = sp->pro_guitar_track[sp->track[ctr]->tracknum]; restore_tech_view = eof_menu_track_get_tech_view_state(sp, ctr); eof_menu_track_set_tech_view_state(sp, ctr, 0); //Disable tech view if applicable if(tp->notes) { //If this track is populated eof_determine_phrase_status(sp, ctr); //Update the trill and tremolo status of each note if(tp->arrangement != 4) { //If this isn't a bass track guitartracknum++; //Keep count of how many of this track type there have been (void) snprintf(buffer, sizeof(buffer) - 1, " <arrangement name=\"Guitar %lu (%s)\">\n", guitartracknum, sp->track[ctr]->name); (void) pack_fputs(buffer, fp); } else { //This is a bass track basstracknum++; //Keep count of how many of this track type there have been (void) snprintf(buffer, sizeof(buffer) - 1, " <arrangement name=\"Bass %lu (%s)\">\n", guitartracknum, sp->track[ctr]->name); (void) pack_fputs(buffer, fp); } (void) snprintf(buffer, sizeof(buffer) - 1, " <tuning string0=\"%d\" string1=\"%d\" string2=\"%d\" string3=\"%d\" string4=\"%d\" string5=\"%d\" />\n", tp->tuning[0], tp->tuning[1], tp->tuning[2], tp->tuning[3], tp->tuning[4], tp->tuning[5]); (void) pack_fputs(buffer, fp); (void) eof_detect_difficulties(sp, ctr); //Update eof_track_diff_populated_status[] to reflect all populated difficulties for this track for(ctr2 = 0; ctr2 < 6; ctr2++) { //For each of the first 6 difficulties unsigned long anchorcount; char anchorsgenerated = 0; //Is set to nonzero if fret hand positions are automatically generated for this difficulty and will have to be deleted if(!eof_track_diff_populated_status[ctr2]) continue; //If this difficulty is not populated, skip it (void) snprintf(buffer, sizeof(buffer) - 1, " <level difficulty=\"%lu\">\n", ctr2); (void) pack_fputs(buffer, fp); //Count the number of note gems in this track difficulty for(ctr3 = 0, gemcount = 0; ctr3 < tp->notes; ctr3++) { //For each note in the track if(eof_get_note_type(sp, ctr, ctr3) == ctr2) { //If the note is in this difficulty gemcount += eof_note_count_rs_lanes(sp, ctr, ctr3, 2); //Add this note's number of non-ghosted gems to a counter } } (void) snprintf(buffer, sizeof(buffer) - 1, " <notes count=\"%lu\">\n", gemcount); (void) pack_fputs(buffer, fp); //Generate fret hand positions if there are none for this difficulty for(ctr3 = 0, anchorcount = 0; ctr3 < tp->handpositions; ctr3++) { //For each hand position defined in the track if(tp->handposition[ctr3].difficulty == ctr2) { //If the hand position is in this difficulty anchorcount++; } } if(!anchorcount) { //If there are no anchors in this track difficulty, automatically generate them if((tp->arrangement != 4) || eof_warn_missing_bass_fhps) { //Don't warn about missing FHPs in bass arrangements if user disabled that preference if((*user_warned & 1) == 0) { //If the user wasn't alerted that one or more track difficulties have no fret hand positions defined allegro_message("Warning: At least one track difficulty has no fret hand positions defined. They will be created automatically."); *user_warned |= 1; } } eof_fret_hand_position_list_dialog_undo_made = 1; //Ensure no undo state is written during export eof_generate_efficient_hand_positions(sp, ctr, ctr2, 0, 0); //Generate the fret hand positions for the track difficulty being currently written anchorsgenerated = 1; } for(ctr3 = 0, anchorcount = 0; ctr3 < tp->handpositions; ctr3++) //Re-count the hand positions { //For each hand position defined in the track if(tp->handposition[ctr3].difficulty == ctr) { //If the hand position is in this difficulty anchorcount++; } } //Write the notes to XML for(ctr3 = 0; ctr3 < tp->notes; ctr3++) { //For each note in the track if(eof_get_note_type(sp, ctr, ctr3) != ctr2) continue; //If the note is not in this difficulty, skip it for(ctr4 = 0, bitmask = 1; ctr4 < tp->numstrings; ctr4++, bitmask <<= 1) { //For each string in this track EOF_RS_TECHNIQUES tech = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned long notepos; unsigned long fret, finger; //The fret and finger numbers used to play the gem on this string unsigned long trill_start, trill_stop; //The start and stop positions of the note's trill phrase int trillwith = -1; //If the note is in a trill phrase, this is set to the fret value of the next or previous gem on the string long next; unsigned long stringnum; //The converted string number (ie. low E string is string 6) char *sustainpadding; if(!(tp->note[ctr3]->note & bitmask) || (tp->note[ctr3]->ghost & bitmask)) continue; //If this string does not have a gem, or if it has one that is ghosted, skip it trill_start = trill_stop = tp->note[ctr3]->pos; //Initialize variables in order to track if the trill phrase can't be properly found if(tp->note[ctr3]->flags & EOF_NOTE_FLAG_IS_TRILL) { //If this note is in a trill phrase //Find which trill phrase it's in for(ctr5 = 0; ctr5 < tp->trills; ctr5++) { //For each trill phrase if((tp->trill[ctr5].difficulty == 0xFF) || (tp->trill[ctr5].difficulty == ctr2)) { //If this trill phrase applies to all difficulties or if it otherwise applies to this note's difficulty if((tp->trill[ctr5].start_pos <= tp->note[ctr3]->pos) && (tp->trill[ctr5].end_pos >= tp->note[ctr3]->pos)) { //If the note is inside this trill phrase trill_start = tp->trill[ctr5].start_pos; trill_stop = tp->trill[ctr5].end_pos; break; } } } //Determine if this is the first note in the trill phrase, and if so, what note it trills with if(trill_start != trill_stop) { //If a trill phrase was identified for(ctr5 = 0; ctr5 < tp->notes; ctr5++) { //For each note in the track if(eof_get_note_type(sp, ctr, ctr3) != ctr2) continue; //If the note is not in this difficulty, skip it if(tp->note[ctr5]->pos > trill_stop) break; //Stop looking at notes if the trill has already been passed if(tp->note[ctr5]->pos < trill_start) continue; //If the note is not within the trill phrase if(ctr5 != ctr3) { //If the note being written to XML is not this note break; //Don't export it with trill technique } next = eof_fixup_next_pro_guitar_note(tp, ctr5); if((next > 0) && (tp->note[next]->pos <= trill_stop)) { //If the next note in the track difficulty is also in this trill phrase if((tp->note[next]->note & bitmask) && ((tp->note[next]->frets[next] & 0x7F) > (tp->note[ctr3]->frets[ctr4] & 0x7F))) { //If the next note has a gem on the target string and its fret value is higher than that of the note being currently written to XML trillwith = tp->note[next]->frets[ctr4] & 0x7F; //This is the fret value being trilled with } } break; }//For each note in the track }//If a trill phrase was identified }//If this note is in a trill phrase (void) eof_get_rs_techniques(sp, ctr, ctr3, ctr4, &tech, 2, 1); //Determine techniques used by this note (honoring technotes where applicable) notepos = eof_get_note_pos(sp, ctr, ctr3); fret = tp->note[ctr3]->frets[ctr4] & 0x7F; //Get the fret value for this string (mask out the muting bit) finger = eof_pro_guitar_note_lookup_string_fingering(tp, ctr3, ctr4, 1); //Unless a more suitable fingering for this note can be determined, assume 1 (index) if(tech.length < 10) { //The sustain is one digit sustainpadding = " "; } else if(tech.length < 100) { //The sustain is two digits sustainpadding = " "; } else if(tech.length < 1000) { //The sustain is three digits sustainpadding = " "; } else { //It's four or more digits sustainpadding = ""; } fret += tp->capo; //Compensate for the the capo position if applicable stringnum = tp->numstrings - ctr4; //Convert to tab string numbering (low E is string 6 in a 6 string track, string 4 on a 4 string track, etc) (void) snprintf(buffer, sizeof(buffer) - 1, " <note time=\"%lu\" linkNext=\"%d\" bend=\"%lu\" fret=%s\"%lu\" hammerOn=\"%d\" harmonic=\"%d\" hopo=\"%d\" ignore=\"0\" mute=\"%d\" palmMute=\"%d\" pluck=\"%d\" pullOff=\"%d\" slap=\"%d\" slideTo=\"%ld\" string=\"%lu\" sustain=%s\"%lu\" tremolo=\"%d\" harmonicPinch=\"%d\" slideUnpitchTo=\"%ld\" trillwith=\"%d\" finger=\"%lu\" vibrato=\"%d\"/>\n", notepos, tech.linknext, tech.bendstrength_h, ((fret < 10) ? " " : ""), fret, tech.hammeron, tech.harmonic, tech.hopo, tech.stringmute, tech.palmmute, tech.pop, tech.pulloff, tech.slap, tech.slideto, stringnum, sustainpadding, tech.length, tech.tremolo, tech.pinchharmonic, tech.unpitchedslideto, trillwith, finger, tech.vibrato); (void) pack_fputs(buffer, fp); }//For each string in this track }//For each note in the track //Remove any automatically generated fret hand positions if(anchorsgenerated) { //If anchors were automatically generated for this track difficulty, remove them now for(ctr3 = tp->handpositions; ctr3 > 0; ctr3--) { //For each hand position defined in the track, in reverse order if(tp->handposition[ctr3 - 1].difficulty == ctr2) { //If the hand position is in this difficulty eof_pro_guitar_track_delete_hand_position(tp, ctr3 - 1); //Delete the hand position } } } (void) pack_fputs(" </notes>\n", fp); (void) pack_fputs(" </level>\n", fp); }//For each of the first 6 difficulties (void) pack_fputs(" </arrangement>\n", fp); }//If this track is populated eof_menu_track_set_tech_view_state(sp, ctr, restore_tech_view); //Re-enable tech view if applicable }//For each track (void) pack_fputs("</Bandfuse>\n", fp); //Cleanup (void) pack_fclose(fp); return 1; //Return success }
void eof_mix_find_claps(void) { unsigned long i; eof_mix_claps = 0; eof_mix_current_clap = 0; unsigned long tracknum; eof_log("eof_mix_find_claps() entered", 1); //Queue claps tracknum = eof_song->track[eof_selected_track]->tracknum; if(eof_vocals_selected) { for(i = 0; i < eof_song->vocal_track[tracknum]->lyrics; i++) { eof_mix_clap_pos[eof_mix_claps] = eof_mix_msec_to_sample(eof_song->vocal_track[tracknum]->lyric[i]->pos, alogg_get_wave_freq_ogg(eof_music_track)); eof_mix_claps++; } } else { //If a vocal track is not selected for(i = 0; i < eof_get_track_size(eof_song, eof_selected_track); i++) { //For each note in the track if((eof_get_note_type(eof_song, eof_selected_track, i) == eof_note_type) && (eof_get_note_note(eof_song, eof_selected_track, i) & eof_mix_claps_note)) { //If the note is in the active track difficulty and the clap sound cue applies to at least one gem used in the note if(eof_clap_for_mutes || !(eof_get_note_flags(eof_song, eof_selected_track, i) & EOF_PRO_GUITAR_NOTE_FLAG_STRING_MUTE)) { //If clap cues should trigger for fully string muted notes, or if this note isn't fully string muted eof_mix_clap_pos[eof_mix_claps] = eof_mix_msec_to_sample(eof_get_note_pos(eof_song, eof_selected_track, i), alogg_get_wave_freq_ogg(eof_music_track)); eof_mix_claps++; } } } } //Queue metronome eof_mix_metronomes = 0; eof_mix_current_metronome = 0; for(i = 0; i < eof_song->beats; i++) { eof_mix_metronome_pos[eof_mix_metronomes] = eof_mix_msec_to_sample(eof_song->beat[i]->pos, alogg_get_wave_freq_ogg(eof_music_track)); eof_mix_metronomes++; } //Queue MIDI tones for pro guitar notes eof_mix_guitar_notes = 0; eof_mix_current_guitar_note = 0; if(eof_song->track[eof_selected_track]->track_format == EOF_PRO_GUITAR_TRACK_FORMAT) { //If a pro guitar/bass track is active int tone = eof_midi_synth_instrument_guitar; EOF_PRO_GUITAR_TRACK *track = eof_song->pro_guitar_track[eof_song->track[eof_selected_track]->tracknum]; if(track->arrangement == 4) { //If this track's arrangement type is bass tone = eof_midi_synth_instrument_bass; //Use the configured bass MIDI tone instead } for(i = 0; i < eof_get_track_size(eof_song, eof_selected_track); i++) { //For each note in the track if(eof_get_note_type(eof_song, eof_selected_track, i) == eof_note_type) { //If the note is in the active track difficulty int j = 0; unsigned long pos = eof_mix_msec_to_sample(eof_get_note_pos(eof_song, eof_selected_track, i) + eof_av_delay - eof_midi_tone_delay, alogg_get_wave_freq_ogg(eof_music_track)); EOF_PRO_GUITAR_NOTE *note = track->note[i]; for(j = 0; j < 6; j++) { //For each of the 6 supported strings if((note->note & (1<<j)) && !(note->frets[j] & 0x80)) { //If the string is used (and not muted) eof_guitar_notes[eof_mix_guitar_notes].pos = pos; eof_guitar_notes[eof_mix_guitar_notes].channel = j; eof_guitar_notes[eof_mix_guitar_notes].note = track->tuning[j] + eof_lookup_default_string_tuning_absolute(track, eof_selected_track, j) + note->frets[j] + track->capo; eof_guitar_notes[eof_mix_guitar_notes].tone = tone; eof_mix_guitar_notes++; } } } } } //Queue vocal tones eof_mix_notes = 0; eof_mix_current_note = 0; eof_mix_percussions = 0; for(i = 0; i < eof_song->vocal_track[0]->lyrics; i++) { if((eof_song->vocal_track[0]->lyric[i]->note >= 36) && (eof_song->vocal_track[0]->lyric[i]->note <= 84)) { //This is a vocal pitch eof_mix_note_pos[eof_mix_notes] = eof_mix_msec_to_sample(eof_song->vocal_track[0]->lyric[i]->pos, alogg_get_wave_freq_ogg(eof_music_track)); eof_mix_note_note[eof_mix_notes] = eof_song->vocal_track[0]->lyric[i]->note; eof_mix_note_ms_pos[eof_mix_notes] = eof_song->vocal_track[0]->lyric[i]->pos; eof_mix_note_ms_end[eof_mix_notes] = eof_song->vocal_track[0]->lyric[i]->pos + eof_song->vocal_track[0]->lyric[i]->length; eof_mix_notes++; } else if(eof_song->vocal_track[0]->lyric[i]->note == EOF_LYRIC_PERCUSSION) { //This is vocal percussion eof_mix_percussion_pos[eof_mix_percussions] = eof_mix_msec_to_sample(eof_song->vocal_track[0]->lyric[i]->pos, alogg_get_wave_freq_ogg(eof_music_track)); eof_mix_percussions++; } } }