Example #1
0
void eof_redo_apply(void)
{
	char fn[1024] = {0};
	char title[256] = {0};
	unsigned long ctr;
	EOF_PRO_GUITAR_TRACK *tp = NULL;
	char tech_view_status[EOF_PRO_GUITAR_TRACKS_MAX] = {0};	//Tracks whether or not tech view was in effect for each of the pro guitar tracks, so this view's status can be restored after the redo

 	eof_log("eof_redo_apply() entered", 1);

	if(eof_redo_count > 0)
	{
		if(eof_validate_temp_folder())
		{	//Ensure the correct working directory and presence of the temporary folder
			eof_log("\tCould not validate working directory and temp folder", 1);
			return;
		}

		//Determine whether each pro guitar track was in tech view
		for(ctr = 0; ctr < EOF_PRO_GUITAR_TRACKS_MAX; ctr++)
		{	//For each pro guitar track in the project
			tp = eof_song->pro_guitar_track[ctr];
			if(tp->note == tp->technote)
			{	//If tech view was in effect for this track
				tech_view_status[ctr] = 1;
			}
		}

		strncpy(title, eof_song->tags->title, sizeof(title) - 1);	//Backup the song title field, since if it changes as part of the redo, the Rocksmith WAV file should be deleted

		(void) eof_save_song(eof_song, eof_undo_filename[eof_undo_current_index]);
		eof_undo_current_index++;
		if(eof_undo_current_index >= EOF_MAX_UNDO)
		{
			eof_undo_current_index = 0;
		}
		(void) snprintf(fn, sizeof(fn) - 1, "%seof%03u.redo", eof_temp_path_s, eof_log_id);	//Get the name of this EOF instance's redo file
		(void) eof_undo_load_state(fn);	//And load it
		if(eof_redo_type == EOF_UNDO_TYPE_SILENCE)
		{
			(void) snprintf(fn, sizeof(fn) - 1, "%seof%03u.redo.ogg", eof_temp_path_s, eof_log_id);	//Get the name of this EOF instance's redo OGG
			(void) eof_copy_file(fn, eof_loaded_ogg_name);	//And save the current audio to that filename
			(void) eof_load_ogg(eof_loaded_ogg_name, 0);
			eof_delete_rocksmith_wav();		//Delete the Rocksmith WAV file since changing silence will require a new WAV file to be written
			eof_fix_waveform_graph();
			eof_fix_spectrogram();
		}
		if(strcmp(title, eof_song->tags->title))
		{	//If the song title changed as part of the redo, delete the Rocksmith WAV file, since changing the title will cause a new WAV file to be written
			eof_delete_rocksmith_wav();
		}
		eof_undo_count++;
		if(eof_undo_count >= EOF_MAX_UNDO)
		{
			eof_undo_count = EOF_MAX_UNDO;
		}
		eof_redo_count = 0;
		eof_change_count++;
		if(eof_change_count == 0)
		{
			eof_changes = 0;
		}
		else
		{
			eof_changes = 1;
		}

		eof_init_after_load(1);	//Perform various cleanup
		(void) eof_detect_difficulties(eof_song, eof_selected_track);
		eof_select_beat(eof_selected_beat);
		eof_fix_catalog_selection();
		eof_scale_fretboard(0);	//Recalculate the 2D screen positioning based on the current track

		//Restore tech view for each pro guitar track that had it in use before the redo operation
		for(ctr = 0; ctr < EOF_PRO_GUITAR_TRACKS_MAX; ctr++)
		{	//For each pro guitar track in the project
			tp = eof_song->pro_guitar_track[ctr];
			if(tech_view_status[ctr])
			{	//If tech view was in effect for this track
				eof_menu_pro_guitar_track_enable_tech_view(tp);
			}
		}
		eof_fix_window_title();
	}
}
Example #2
0
int eof_undo_apply(void)
{
	char fn[1024] = {0};
	char title[256] = {0};
	unsigned long ctr;
	EOF_PRO_GUITAR_TRACK *tp = NULL;
	char tech_view_status[EOF_PRO_GUITAR_TRACKS_MAX] = {0};	//Tracks whether or not tech view was in effect for each of the pro guitar tracks, so this view's status can be restored after the undo

 	eof_log("eof_undo_apply() entered", 1);

	if(eof_undo_count > 0)
	{
		//Determine whether each pro guitar track was in tech view
		for(ctr = 0; ctr < EOF_PRO_GUITAR_TRACKS_MAX; ctr++)
		{	//For each pro guitar track in the project
			tp = eof_song->pro_guitar_track[ctr];
			if(tp->note == tp->technote)
			{	//If tech view was in effect for this track
				tech_view_status[ctr] = 1;
			}
		}

		strncpy(title, eof_song->tags->title, sizeof(title) - 1);	//Backup the song title field, since if it changes as part of the undo, the Rocksmith WAV file should be deleted

		(void) snprintf(fn, sizeof(fn) - 1, "%seof%03u.redo", eof_temp_path, eof_log_id);	//Include EOF's log ID in the redo name to almost guarantee it is uniquely named
		(void) eof_save_song(eof_song, fn);
		eof_redo_type = 0;
		eof_undo_current_index--;
		if(eof_undo_current_index < 0)
		{
			eof_undo_current_index = EOF_MAX_UNDO - 1;
		}
		(void) eof_undo_load_state(eof_undo_filename[eof_undo_current_index]);
		if(eof_undo_type[eof_undo_current_index] == EOF_UNDO_TYPE_NOTE_SEL)
		{
			(void) eof_menu_edit_deselect_all();
		}
		if(eof_undo_type[eof_undo_current_index] == EOF_UNDO_TYPE_SILENCE)
		{
			(void) snprintf(fn, sizeof(fn) - 1, "%seof%03u.redo.ogg", eof_temp_path, eof_log_id);	//Include EOF's log ID in the redo name to almost guarantee it is uniquely named
			(void) eof_copy_file(eof_loaded_ogg_name, fn);
			(void) snprintf(fn, sizeof(fn) - 1, "%s%s.ogg", eof_temp_path, eof_undo_filename[eof_undo_current_index]);
			(void) eof_copy_file(fn, eof_loaded_ogg_name);
			(void) eof_load_ogg(eof_loaded_ogg_name, 0);
			eof_delete_rocksmith_wav();		//Delete the Rocksmith WAV file since changing silence will require a new WAV file to be written
			eof_fix_waveform_graph();
			eof_fix_spectrogram();
			eof_redo_type = EOF_UNDO_TYPE_SILENCE;
		}
		if(strcmp(title, eof_song->tags->title))
		{	//If the song title changed as part of the undo, delete the Rocksmith WAV file, since changing the title will cause a new WAV file to be written
			eof_delete_rocksmith_wav();
		}
		eof_undo_count--;
		eof_redo_count = 1;
		eof_change_count--;
		if(eof_change_count == 0)
		{
			eof_changes = 0;
		}
		else
		{
			eof_changes = 1;
		}
		eof_undo_last_type = 0;

		eof_init_after_load(1);	//Perform various cleanup
		(void) eof_detect_difficulties(eof_song, eof_selected_track);
		eof_select_beat(eof_selected_beat);
		eof_fix_catalog_selection();
		eof_scale_fretboard(0);	//Recalculate the 2D screen positioning based on the current track

		//Restore tech view for each pro guitar track that had it in use before the undo operation
		for(ctr = 0; ctr < EOF_PRO_GUITAR_TRACKS_MAX; ctr++)
		{	//For each pro guitar track in the project
			tp = eof_song->pro_guitar_track[ctr];
			if(tech_view_status[ctr])
			{	//If tech view was in effect for this track
				eof_menu_pro_guitar_track_enable_tech_view(tp);
			}
		}

		eof_fix_window_title();
		return 1;
	}
	return 0;
}
Example #3
0
int eof_add_silence_recode(char * oggfn, unsigned long ms)
{
	char sys_command[1024] = {0};
	char backupfn[1024] = {0};
	char wavfn[1024] = {0};
	char soggfn[1024] = {0};
	ALOGG_OGG *oggfile = NULL;
	SAMPLE *decoded = NULL, *combined = NULL;
	int bits;
	int stereo;
	int freq;
	unsigned long samples;
	int channels;
	unsigned long ctr,index;
	void * oggbuffer = NULL;
	int bitrate;

 	eof_log("eof_add_silence_recode() entered", 1);

	if(!oggfn || (ms == 0) || eof_silence_loaded)
	{
		return 41;	//Return failure:  Invalid parameters
	}
	set_window_title("Adjusting Silence...");

	/* back up original file */
	(void) snprintf(backupfn, sizeof(backupfn) - 1, "%s.backup", oggfn);
	if(!exists(backupfn))
	{
		(void) eof_copy_file(oggfn, backupfn);
	}

	/* Decode the OGG file into memory */
	//Load OGG file into memory
	oggbuffer = eof_buffer_file(oggfn, 0);	//Decode the OGG from buffer instead of from file because the latter cannot support special characters in the file path due to limitations with fopen()
	if(!oggbuffer)
	{
		(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tError reading OGG:  \"%s\"", strerror(errno));	//Get the Operating System's reason for the failure
		eof_log(eof_log_string, 1);
		return 42;	//Return failure:  Could not buffer chart audio into memory
	}
	oggfile=alogg_create_ogg_from_buffer(oggbuffer, (int)file_size_ex(oggfn));
	if(oggfile == NULL)
	{
		eof_log("ALOGG failed to open input audio file", 1);
		free(oggbuffer);
		return 43;	//Return failure:  Could not process buffered chart audio
	}

	//Decode OGG into memory
	decoded=alogg_create_sample_from_ogg(oggfile);
	if(decoded == NULL)
	{
		alogg_destroy_ogg(oggfile);
		free(oggbuffer);
		return 44;	//Return failure:  Could not decode chart audio to memory
	}

	/* Create a SAMPLE array large enough for the leading silence and the decoded OGG */
	bits = alogg_get_wave_bits_ogg(oggfile);
	stereo = alogg_get_wave_is_stereo_ogg(oggfile);
	freq = alogg_get_wave_freq_ogg(oggfile);
	alogg_destroy_ogg(oggfile);	//This is no longer needed
	oggfile = NULL;
	samples = msec_to_samples(ms);
	channels = stereo ? 2 : 1;
	combined = create_sample(bits,stereo,freq,samples+decoded->len);	//Create a sample array long enough for the silence and the OGG file
	if(combined == NULL)
	{
		destroy_sample(decoded);
		return 45;	//Return failure:  Could not create a sample array for the combined audio
	}

	/* Add the PCM data for the silence */
	if(bits == 8)
	{	//Create 8 bit PCM data
		for(ctr=0,index=0;ctr < samples * channels;ctr++)
		{
			((unsigned char *)(combined->data))[index++] = 0x80;
		}
	}
	else
	{	//Create 16 bit PCM data
		for(ctr=0,index=0;ctr < samples * channels;ctr++)
		{
			((unsigned short *)(combined->data))[index++] = 0x8000;
		}
	}

	/* Add the decoded OGG PCM data*/
	if(bits == 8)
	{	//Copy 8 bit PCM data
		for(ctr=0;ctr < decoded->len * channels;ctr++)
		{
			((unsigned char *)(combined->data))[index++] = ((unsigned char *)(decoded->data))[ctr];
		}
	}
	else
	{	//Copy 16 bit PCM data
		for(ctr=0;ctr < decoded->len * channels;ctr++)
		{
			((unsigned short *)(combined->data))[index++] = ((unsigned short *)(decoded->data))[ctr];
		}
	}

	/* encode the audio */
	destroy_sample(decoded);	//This is no longer needed
	free(oggbuffer);
	(void) replace_filename(wavfn, eof_song_path, "encode.wav", 1024);
	(void) save_wav(wavfn, combined);
	destroy_sample(combined);	//This is no longer needed
	(void) replace_filename(soggfn, eof_song_path, "encode.ogg", 1024);
	bitrate = alogg_get_bitrate_ogg(eof_music_track) / 1000;
	if(!bitrate)
	{	//A user found that in an audio file with a really high sample rate (ie. 96KHz), alogg_get_bitrate_ogg() may return zero instead of an expected value
		bitrate = 256;	//In case this happens, use a bitrate of 256Kbps, which should be good enough for a very high quality file
	}
	#ifdef ALLEGRO_WINDOWS
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc2 -o \"%s\" -b %d \"%s\"", soggfn, bitrate, wavfn);
	#else
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc -o \"%s\" -b %d \"%s\"", soggfn, bitrate, wavfn);
	#endif

	(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tCalling oggenc as follows:  %s", sys_command);
	eof_log(eof_log_string, 1);
	if(eof_system(sys_command))
	{	//If oggenc failed, retry again by specifying a quality level (specifying bitrate can fail in some circumstances)
		eof_log("\t\toggenc failed.  Retrying by specifying a quality level instead of a target bitrate", 1);
		#ifdef ALLEGRO_WINDOWS
			(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc2 -o \"%s\" -q 9 \"%s\"", soggfn, wavfn);
		#else
			(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc -o \"%s\" -q 9 \"%s\"", soggfn, wavfn);
		#endif
		(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tCalling oggenc as follows:  %s", sys_command);
		eof_log(eof_log_string, 1);
		if(eof_system(sys_command))
		{	//If oggenc failed again
			char tempfname[30] = {0};
			char redirect[35] = {0};

			if(eof_validate_temp_folder())
			{	//Ensure the correct working directory and presence of the temporary folder
				eof_log("\tCould not validate working directory and temp folder", 1);
				return 46;	//Return failure:  Could not validate cwd and temp folder
			}

			(void) snprintf(tempfname, sizeof(tempfname) - 1, "%soggenc.log", eof_temp_path_s);
			(void) snprintf(redirect, sizeof(redirect) - 1, " 2> %s", tempfname);
			(void) ustrzcat(sys_command, (int) sizeof(sys_command) - 1, redirect);	//Append a redirection to the command to capture the output of oggenc
			if(eof_system(sys_command))
			{	//Run one last time to catch the error output
				(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tOggenc failed.  Please see %s for any errors it gave.", tempfname);
				eof_log(eof_log_string, 1);
				eof_fix_window_title();
				return 47;	//Return failure:  Could not encode combined audio
			}
		}
	}

	/* replace the current OGG file with the new file */
	(void) eof_copy_file(soggfn, oggfn);	//Copy encode.ogg to the filename of the original OGG

	/* clean up */
	(void) delete_file(soggfn);	//Delete encode.ogg
	(void) delete_file(wavfn);		//Delete encode.wav
	if(eof_load_ogg(oggfn, 0))
	{	//If the combined audio was loaded
		eof_fix_waveform_graph();
		eof_fix_spectrogram();
		eof_fix_window_title();
		eof_chart_length = eof_music_length;
		return 0;	//Return success
	}
	eof_fix_window_title();

	return 48;	//Return error:  Could not load new audio
}
Example #4
0
int eof_add_silence_recode_mp3(char * oggfn, unsigned long ms)
{
	char sys_command[1024] = {0};
	char backupfn[1024] = {0};
	char wavfn[1024] = {0};
	char soggfn[1024] = {0};
	char mp3fn[1024] = {0};
	SAMPLE * decoded = NULL;
	SAMPLE * combined = NULL;
	int bits;
	int stereo;
	int freq;
	unsigned long samples;
	int channels;
	unsigned long ctr,index;

 	eof_log("eof_add_silence_recode_mp3() entered", 1);

	if(!oggfn || (ms == 0) || eof_silence_loaded)
	{
		return 21;	//Return error:  Invalid parameters
	}
	set_window_title("Adjusting Silence...");

	/* back up original file */
	(void) snprintf(backupfn, sizeof(backupfn) - 1, "%s.backup", oggfn);
	if(!exists(backupfn))
	{
		(void) eof_copy_file(oggfn, backupfn);
	}

	/* decode MP3 */
	(void) replace_filename(wavfn, eof_song_path, "decode.wav", 1024);
	(void) replace_filename(mp3fn, eof_song_path, "original.mp3", 1024);
	(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "lame --decode \"%s\" \"%s\"", mp3fn, wavfn);
	(void) eof_system(sys_command);

	/* insert silence */
	decoded = load_sample(wavfn);
	if(!decoded)
	{
		allegro_message("Error opening file.\nMake sure there are no Unicode or extended ASCII characters in this chart's file path.");
		return 22;	//Return failure:  Could not load decoded MP3 file
	}
	bits = decoded->bits;
	stereo = decoded->stereo;
	freq = decoded->freq;
	samples = (decoded->freq * ms) / 1000;	//Calculate this manually instead of using msec_to_samples() because that function assumes the sample rate matches the current chart audio, and this may not be the case with the original MP3 file the user provided
	channels = stereo ? 2 : 1;
	combined = create_sample(bits,stereo,freq,samples+decoded->len);	//Create a sample array long enough for the silence and the OGG file
	if(combined == NULL)
	{
		destroy_sample(decoded);
		return 23;	//Return failure:  Could not create a sample array for the combined audio
	}
	/* Add the PCM data for the silence */
	if(bits == 8)
	{	//Create 8 bit PCM data
		for(ctr=0,index=0;ctr < samples * channels;ctr++)
		{
			((unsigned char *)(combined->data))[index++] = 0x80;
		}
	}
	else
	{	//Create 16 bit PCM data
		for(ctr=0,index=0;ctr < samples * channels;ctr++)
		{
			((unsigned short *)(combined->data))[index++] = 0x8000;
		}
	}
	/* Add the decoded OGG PCM data*/
	if(bits == 8)
	{	//Copy 8 bit PCM data
		for(ctr=0;ctr < decoded->len * channels;ctr++)
		{
			((unsigned char *)(combined->data))[index++] = ((unsigned char *)(decoded->data))[ctr];
		}
	}
	else
	{	//Copy 16 bit PCM data
		for(ctr=0;ctr < decoded->len * channels;ctr++)
		{
			((unsigned short *)(combined->data))[index++] = ((unsigned short *)(decoded->data))[ctr];
		}
	}

	/* save combined WAV */
	(void) replace_filename(wavfn, eof_song_path, "encode.wav", 1024);
	if(!save_wav(wavfn, combined))
	{
		destroy_sample(decoded);	//This is no longer needed
		destroy_sample(combined);	//This is no longer needed
		return 24;	//Return failure:  Could not create the combined audio WAV file
	}

	/* destroy samples */
	destroy_sample(decoded);	//This is no longer needed
	destroy_sample(combined);	//This is no longer needed

	/* encode the audio */
	printf("%s\n%s\n", eof_song_path, wavfn);
	(void) replace_filename(soggfn, eof_song_path, "encode.ogg", 1024);
	#ifdef ALLEGRO_WINDOWS
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc2 -o \"%s\" -b %d \"%s\"", soggfn, alogg_get_bitrate_ogg(eof_music_track) / 1000, wavfn);
	#else
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc -o \"%s\" -b %d \"%s\"", soggfn, alogg_get_bitrate_ogg(eof_music_track) / 1000, wavfn);
	#endif

	(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tCalling oggenc as follows:  %s", sys_command);
	eof_log(eof_log_string, 1);
	if(eof_system(sys_command))
	{	//If oggenc failed, retry again by specifying a quality level (specifying bitrate can fail in some circumstances)
		eof_log("\t\toggenc failed.  Retrying by specifying a quality level instead of a target bitrate", 1);
		#ifdef ALLEGRO_WINDOWS
			(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc2 -o \"%s\" -q 9 \"%s\"", soggfn, wavfn);
		#else
			(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc -o \"%s\" -q 9 \"%s\"", soggfn, wavfn);
		#endif
		(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tCalling oggenc as follows:  %s", sys_command);
		eof_log(eof_log_string, 1);
		if(eof_system(sys_command))
		{	//If oggenc failed again
			char tempfname[30] = {0};
			char redirect[35] = {0};

			if(eof_validate_temp_folder())
			{	//Ensure the correct working directory and presence of the temporary folder
				eof_log("\tCould not validate working directory and temp folder", 1);
				return 25;	//Return failure:  Could not validate cwd and temp folder
			}

			(void) snprintf(tempfname, sizeof(tempfname) - 1, "%soggenc.log", eof_temp_path_s);
			(void) snprintf(redirect, sizeof(redirect) - 1, " 2> %s", tempfname);
			(void) ustrzcat(sys_command, (int) sizeof(sys_command) - 1, redirect);	//Append a redirection to the command to capture the output of oggenc
			if(eof_system(sys_command))
			{	//Run one last time to catch the error output
				(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tOggenc failed.  Please see %s for any errors it gave.", tempfname);
				eof_log(eof_log_string, 1);
				eof_fix_window_title();
				return 26;	//Return failure:  Could not encode combined audio
			}
		}
	}

	/* replace the current OGG file with the new file */
	(void) eof_copy_file(soggfn, oggfn);	//Copy encode.ogg to the filename of the original OGG

	/* clean up */
	(void) replace_filename(wavfn, eof_song_path, "decode.wav", 1024);
	(void) delete_file(wavfn);		//Delete decode.wav
	(void) replace_filename(wavfn, eof_song_path, "encode.wav", 1024);
	(void) delete_file(wavfn);		//Delete encode.wav
	(void) delete_file(soggfn);	//Delete encode.ogg
	if(eof_load_ogg(oggfn, 0))
	{	//If the combined audio was loaded
		eof_fix_waveform_graph();
		eof_fix_spectrogram();
		eof_fix_window_title();
		eof_chart_length = eof_music_length;
		return 0;	//Return success
	}
	eof_fix_window_title();

	return 27;	//Return error:  Could not load new audio
}
Example #5
0
int eof_add_silence(char * oggfn, unsigned long ms)
{
	char sys_command[1024] = {0};
	char backupfn[1024] = {0};	//The file path of the backup of the target audio file
	char wavfn[1024] = {0};		//The file path of the silent WAV file created
	char soggfn[1024] = {0};	//The file path of the silent OGG file created
	char oggcfn[1024] = {0};	//The file path to the oggCat utility
	char old_wd[1024] = {0};	//Store working directory before changing it so we can get back
	char *rel_oggfn;			//Relative file path to the target audio file
	char *rel_backupfn;			//Relative file path to the backup of the target audio file
	SAMPLE * silence_sample;
	int retval;

	if(!oggfn || (ms == 0) || eof_silence_loaded)
	{
		return 1;	//Return error:  Invalid parameters
	}

 	eof_log("eof_add_silence() entered", 1);

	set_window_title("Adjusting Silence...");

	/* back up original file */
	(void) snprintf(backupfn, sizeof(backupfn) - 1, "%s.backup", oggfn);
	if(!exists(backupfn))
	{
		(void) eof_copy_file(oggfn, backupfn);
	}
	(void) delete_file(oggfn);

	silence_sample = create_silence_sample(ms);
	if(!silence_sample)
	{
		eof_fix_window_title();
		return 2;	//Return error:  Couldn't create silent audio
	}
	(void) replace_filename(wavfn, eof_song_path, "silence.wav", 1024);
	(void) save_wav(wavfn, silence_sample);
	destroy_sample(silence_sample);
	(void) replace_filename(soggfn, eof_song_path, "silence.ogg", 1024);
	#ifdef ALLEGRO_WINDOWS
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc2 -o \"%s\" -b %d \"%s\"", soggfn, alogg_get_bitrate_ogg(eof_music_track) / 1000, wavfn);
	#else
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "oggenc -o \"%s\" -b %d \"%s\"", soggfn, alogg_get_bitrate_ogg(eof_music_track) / 1000, wavfn);
	#endif
	if(eof_system(sys_command))
	{
		eof_fix_window_title();
		return 3;	//Return error:  Could not encode silent audio
	}

	/* stitch the original file to the silence file */
	if(!getcwd(old_wd, 1024))
	{	//If the current working directory could not be obtained
		eof_fix_window_title();
		return 4;	//Return error:  Could not obtain current working directory
	}

	(void) eof_chdir(eof_song_path);	//Change directory to the project's folder, since oggCat does not support paths that have any Unicode/extended ASCII, relative paths will be given
	#ifdef ALLEGRO_WINDOWS
		get_executable_name(oggcfn, 1024);
		(void) replace_filename(oggcfn, oggcfn, "oggCat.exe", 1024);	//Build the full path to oggCat
	#else
		ustrzcpy(oggcfn, 1024, "oggCat");
	#endif
	rel_oggfn = get_filename(oggfn);		//Get the relative path to the target OGG file
	rel_backupfn = get_filename(backupfn);	//Get the relative path to the backup of the target OGG file
	//Call oggCat while the current working directory is the project folder.  This way, if the project folder's path contains any Unicode or extended ASCII, oggCat won't fail
	#ifdef ALLEGRO_WINDOWS
		//For some reason, the Windows build needs extra quotation marks to enclose the entire command if the command begins with a full executable path in quote marks
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "\"\"%s\" \"%s\" \"silence.ogg\" \"%s\"\"", oggcfn, rel_oggfn, rel_backupfn);
	#else
		(void) uszprintf(sys_command, (int) sizeof(sys_command) - 1, "\"%s\" \"%s\" \"silence.ogg\" \"%s\"", oggcfn, rel_oggfn, rel_backupfn);	//Use oggCat to overwrite the target OGG file with the silent audio concatenated with the backup of the target OGG file
	#endif
	retval = eof_system(sys_command);

	/* change back to the program folder */
	if(eof_chdir(old_wd))
	{
		allegro_message("Could not change directory to EOF's program folder!\n%s", backupfn);
		return 5;	//Return error:  Could not set working directory
	}

	if(retval)
	{	//If the command failed
		(void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "\tError issuing command \"%s\" from path \"%s\"", sys_command, eof_song_path);
		eof_log(eof_log_string, 1);
		(void) eof_copy_file(backupfn, oggfn);	//Restore the original OGG file
		eof_fix_window_title();
		return 6;	//Return error:  oggCat failed
	}

	/* clean up */
	(void) delete_file(wavfn);	//Delete silence.wav
	(void) delete_file(soggfn);	//Delete silence.ogg
	if(eof_load_ogg(oggfn, 0))
	{	//If the combined audio was loaded
		eof_fix_waveform_graph();
		eof_fix_spectrogram();
		eof_fix_window_title();
		eof_chart_length = eof_music_length;
		return 0;	//Return success
	}
	eof_fix_window_title();

	//If this part of the function is reached, the OGG failed to load
	if(exists(oggfn))
		return 7;	//Return error:  Could not load new audio, but audio file exists

	return 8;	//Return error:  Could not load new audio, file does not exist
}