2 Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <boost/filesystem.hpp>
29 using namespace boost;
34 cerr << "Syntax: " << n << " [--help] [--chop-audio-start] [--chop-audio-end] --film <film>\n";
38 sox (vector<string> const & audio_files, string const & process)
40 for (vector<string>::const_iterator i = audio_files.begin(); i != audio_files.end(); ++i) {
42 cmd << "sox \"" << *i << "\" -t wav \"" << *i << ".tmp\" " << process;
43 cout << "> " << cmd.str() << "\n";
44 int r = ::system (cmd.str().c_str());
45 if (r == -1 || WEXITSTATUS (r) != 0) {
46 cerr << "fixlengths: call to sox failed.\n";
49 filesystem::rename (*i + ".tmp", *i);
53 int main (int argc, char* argv[])
56 bool chop_audio_start = false;
57 bool chop_audio_end = false;
58 bool pad_audio_end = false;
61 static struct option long_options[] = {
62 { "help", no_argument, 0, 'h' },
63 { "chop-audio-start", no_argument, 0, 'c' },
64 { "chop-audio-end", no_argument, 0, 'd' },
65 { "pad-audio-end", no_argument, 0, 'p' },
66 { "film", required_argument, 0, 'f' },
71 int c = getopt_long (argc, argv, "hcf:", long_options, &option_index);
82 chop_audio_start = true;
85 chop_audio_end = true;
96 if (film_dir.empty ()) {
105 film = new Film (film_dir, true);
106 } catch (std::exception& e) {
107 cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n";
112 int video_frames = 0;
113 for (filesystem::directory_iterator i = filesystem::directory_iterator (film->j2k_dir()); i != filesystem::directory_iterator(); ++i) {
117 float const video_length = video_frames / film->frames_per_second();
118 cout << "Video length: " << video_length << " (" << video_frames << " frames at " << film->frames_per_second() << " frames per second).\n";
120 vector<string> audio_files = film->audio_files ();
121 if (audio_files.empty ()) {
122 cerr << argv[0] << ": film has no audio files.\n";
126 sf_count_t audio_frames = 0;
127 int audio_sample_rate = 0;
129 for (vector<string>::iterator i = audio_files.begin(); i != audio_files.end(); ++i) {
132 SNDFILE* sf = sf_open (i->c_str(), SFM_READ, &info);
134 cerr << argv[0] << ": could not open WAV file for reading.\n";
138 if (audio_frames == 0) {
139 audio_frames = info.frames;
142 if (audio_sample_rate == 0) {
143 audio_sample_rate = info.samplerate;
146 if (audio_frames != info.frames) {
147 cerr << argv[0] << ": audio files have differing lengths.\n";
151 if (audio_sample_rate != info.samplerate) {
152 cerr << argv[0] << ": audio files have differing sample rates.\n";
159 float const audio_length = audio_frames / float (audio_sample_rate);
161 cout << "Audio length: " << audio_length << " (" << audio_frames << " frames at " << audio_sample_rate << " frames per second).\n";
165 if (audio_length > video_length) {
166 cout << setprecision (3);
167 cout << "Audio " << (audio_length - video_length) << "s longer than video.\n";
169 float const delta = audio_length - video_length;
170 int const delta_samples = delta * audio_sample_rate;
172 if (chop_audio_start) {
173 cout << "Chopping difference off the start of the audio.\n";
176 s << "trim " << delta_samples << "s";
177 sox (audio_files, s.str ());
179 } else if (chop_audio_end) {
180 cout << "Chopping difference off the end of the audio.\n";
183 s << "reverse trim " << delta_samples << "s reverse";
184 sox (audio_files, s.str ());
187 cout << "Re-run with --chop-audio-start or --chop-audio-end, perhaps.\n";
190 } else if (audio_length < video_length) {
191 cout << setprecision (3);
192 cout << "Audio " << (video_length - audio_length) << "s shorter than video.\n";
196 float const delta = video_length - audio_length;
197 int const delta_samples = delta * audio_sample_rate;
199 s << "pad 0 " << delta_samples << "s";
200 sox (audio_files, s.str ());
203 cout << "Re-run with --pad-audio-end, perhaps.\n";