/* Copyright (C) 2012 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include "lib/film.h" #include "lib/cross.h" using namespace std; using namespace boost; void help (string n) { cerr << "Syntax: " << n << " [--help] [--chop-audio-start] [--chop-audio-end] --film \n"; } void sox (vector const & audio_files, string const & process) { for (vector::const_iterator i = audio_files.begin(); i != audio_files.end(); ++i) { stringstream cmd; cmd << "sox \"" << *i << "\" -t wav \"" << *i << ".tmp\" " << process; cout << "> " << cmd.str() << "\n"; int r = ::system (cmd.str().c_str()); if (r == -1 || WEXITSTATUS (r) != 0) { cerr << "fixlengths: call to sox failed.\n"; exit (EXIT_FAILURE); } filesystem::rename (*i + ".tmp", *i); } } int main (int argc, char* argv[]) { string film_dir; bool chop_audio_start = false; bool chop_audio_end = false; bool pad_audio_end = false; while (1) { static struct option long_options[] = { { "help", no_argument, 0, 'h' }, { "chop-audio-start", no_argument, 0, 'c' }, { "chop-audio-end", no_argument, 0, 'd' }, { "pad-audio-end", no_argument, 0, 'p' }, { "film", required_argument, 0, 'f' }, { 0, 0, 0, 0 } }; int option_index = 0; int c = getopt_long (argc, argv, "hcf:", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'h': help (argv[0]); exit (EXIT_SUCCESS); case 'c': chop_audio_start = true; break; case 'd': chop_audio_end = true; break; case 'p': pad_audio_end = true; break; case 'f': film_dir = optarg; break; } } if (film_dir.empty ()) { help (argv[0]); exit (EXIT_FAILURE); } dvdomatic_setup (); Film* film = 0; try { film = new Film (film_dir, true); } catch (std::exception& e) { cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n"; exit (EXIT_FAILURE); } /* XXX: hack */ int video_frames = 0; for (filesystem::directory_iterator i = filesystem::directory_iterator (film->j2k_dir()); i != filesystem::directory_iterator(); ++i) { ++video_frames; } float const video_length = video_frames / film->frames_per_second(); cout << "Video length: " << video_length << " (" << video_frames << " frames at " << film->frames_per_second() << " frames per second).\n"; vector audio_files = film->audio_files (); if (audio_files.empty ()) { cerr << argv[0] << ": film has no audio files.\n"; exit (EXIT_FAILURE); } sf_count_t audio_frames = 0; int audio_sample_rate = 0; for (vector::iterator i = audio_files.begin(); i != audio_files.end(); ++i) { SF_INFO info; info.format = 0; SNDFILE* sf = sf_open (i->c_str(), SFM_READ, &info); if (sf == 0) { cerr << argv[0] << ": could not open WAV file for reading.\n"; exit (EXIT_FAILURE); } if (audio_frames == 0) { audio_frames = info.frames; } if (audio_sample_rate == 0) { audio_sample_rate = info.samplerate; } if (audio_frames != info.frames) { cerr << argv[0] << ": audio files have differing lengths.\n"; exit (EXIT_FAILURE); } if (audio_sample_rate != info.samplerate) { cerr << argv[0] << ": audio files have differing sample rates.\n"; exit (EXIT_FAILURE); } sf_close (sf); } float const audio_length = audio_frames / float (audio_sample_rate); cout << "Audio length: " << audio_length << " (" << audio_frames << " frames at " << audio_sample_rate << " frames per second).\n"; cout << "\n"; if (audio_length > video_length) { cout << setprecision (3); cout << "Audio " << (audio_length - video_length) << "s longer than video.\n"; float const delta = audio_length - video_length; int const delta_samples = delta * audio_sample_rate; if (chop_audio_start) { cout << "Chopping difference off the start of the audio.\n"; stringstream s; s << "trim " << delta_samples << "s"; sox (audio_files, s.str ()); } else if (chop_audio_end) { cout << "Chopping difference off the end of the audio.\n"; stringstream s; s << "reverse trim " << delta_samples << "s reverse"; sox (audio_files, s.str ()); } else { cout << "Re-run with --chop-audio-start or --chop-audio-end, perhaps.\n"; } } else if (audio_length < video_length) { cout << setprecision (3); cout << "Audio " << (video_length - audio_length) << "s shorter than video.\n"; if (pad_audio_end) { float const delta = video_length - audio_length; int const delta_samples = delta * audio_sample_rate; stringstream s; s << "pad 0 " << delta_samples << "s"; sox (audio_files, s.str ()); } else { cout << "Re-run with --pad-audio-end, perhaps.\n"; } } return 0; }