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>
27 #include "lib/cross.h"
30 using namespace boost;
35 cerr << "Syntax: " << n << " [--help] [--chop-audio-start] [--chop-audio-end] --film <film>\n";
39 sox (vector<string> const & audio_files, string const & process)
41 for (vector<string>::const_iterator i = audio_files.begin(); i != audio_files.end(); ++i) {
43 cmd << "sox \"" << *i << "\" -t wav \"" << *i << ".tmp\" " << process;
44 cout << "> " << cmd.str() << "\n";
45 int r = ::system (cmd.str().c_str());
46 if (r == -1 || WEXITSTATUS (r) != 0) {
47 cerr << "fixlengths: call to sox failed.\n";
50 filesystem::rename (*i + ".tmp", *i);
54 int main (int argc, char* argv[])
57 bool chop_audio_start = false;
58 bool chop_audio_end = false;
59 bool pad_audio_end = false;
62 static struct option long_options[] = {
63 { "help", no_argument, 0, 'h' },
64 { "chop-audio-start", no_argument, 0, 'c' },
65 { "chop-audio-end", no_argument, 0, 'd' },
66 { "pad-audio-end", no_argument, 0, 'p' },
67 { "film", required_argument, 0, 'f' },
72 int c = getopt_long (argc, argv, "hcf:", long_options, &option_index);
83 chop_audio_start = true;
86 chop_audio_end = true;
97 if (film_dir.empty ()) {
106 film = new Film (film_dir, true);
107 } catch (std::exception& e) {
108 cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n";
113 int video_frames = 0;
114 for (filesystem::directory_iterator i = filesystem::directory_iterator (film->j2k_dir()); i != filesystem::directory_iterator(); ++i) {
118 float const video_length = video_frames / film->frames_per_second();
119 cout << "Video length: " << video_length << " (" << video_frames << " frames at " << film->frames_per_second() << " frames per second).\n";
121 vector<string> audio_files = film->audio_files ();
122 if (audio_files.empty ()) {
123 cerr << argv[0] << ": film has no audio files.\n";
127 sf_count_t audio_frames = 0;
128 int audio_sample_rate = 0;
130 for (vector<string>::iterator i = audio_files.begin(); i != audio_files.end(); ++i) {
133 SNDFILE* sf = sf_open (i->c_str(), SFM_READ, &info);
135 cerr << argv[0] << ": could not open WAV file for reading.\n";
139 if (audio_frames == 0) {
140 audio_frames = info.frames;
143 if (audio_sample_rate == 0) {
144 audio_sample_rate = info.samplerate;
147 if (audio_frames != info.frames) {
148 cerr << argv[0] << ": audio files have differing lengths.\n";
152 if (audio_sample_rate != info.samplerate) {
153 cerr << argv[0] << ": audio files have differing sample rates.\n";
160 float const audio_length = audio_frames / float (audio_sample_rate);
162 cout << "Audio length: " << audio_length << " (" << audio_frames << " frames at " << audio_sample_rate << " frames per second).\n";
166 if (audio_length > video_length) {
167 cout << setprecision (3);
168 cout << "Audio " << (audio_length - video_length) << "s longer than video.\n";
170 float const delta = audio_length - video_length;
171 int const delta_samples = delta * audio_sample_rate;
173 if (chop_audio_start) {
174 cout << "Chopping difference off the start of the audio.\n";
177 s << "trim " << delta_samples << "s";
178 sox (audio_files, s.str ());
180 } else if (chop_audio_end) {
181 cout << "Chopping difference off the end of the audio.\n";
184 s << "reverse trim " << delta_samples << "s reverse";
185 sox (audio_files, s.str ());
188 cout << "Re-run with --chop-audio-start or --chop-audio-end, perhaps.\n";
191 } else if (audio_length < video_length) {
192 cout << setprecision (3);
193 cout << "Audio " << (video_length - audio_length) << "s shorter than video.\n";
197 float const delta = video_length - audio_length;
198 int const delta_samples = delta * audio_sample_rate;
200 s << "pad 0 " << delta_samples << "s";
201 sox (audio_files, s.str ());
204 cout << "Re-run with --pad-audio-end, perhaps.\n";