99dd1ded0062ad3c77a136f0452d383077f4c97c
[dcpomatic.git] / src / lib / external_audio_decoder.cc
1 #include <sndfile.h>
2 #include "external_audio_decoder.h"
3 #include "film.h"
4 #include "exceptions.h"
5
6 using std::vector;
7 using std::string;
8 using std::min;
9 using boost::shared_ptr;
10
11 ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
12         : Decoder (f, o, j)
13         , AudioDecoder (f, o, j)
14 {
15
16 }
17
18 bool
19 ExternalAudioDecoder::pass ()
20 {
21         vector<string> const files = _film->external_audio ();
22
23         int N = 0;
24         for (size_t i = 0; i < files.size(); ++i) {
25                 if (!files[i].empty()) {
26                         N = i + 1;
27                 }
28         }
29
30         if (N == 0) {
31                 return true;
32         }
33
34         bool first = true;
35         sf_count_t frames = 0;
36         
37         vector<SNDFILE*> sndfiles;
38         for (vector<string>::const_iterator i = files.begin(); i != files.end(); ++i) {
39                 if (i->empty ()) {
40                         sndfiles.push_back (0);
41                 } else {
42                         SF_INFO info;
43                         SNDFILE* s = sf_open (i->c_str(), SFM_READ, &info);
44                         if (!s) {
45                                 throw DecodeError ("could not open external audio file for reading");
46                         }
47
48                         if (info.channels != 1) {
49                                 throw DecodeError ("external audio files must be mono");
50                         }
51                         
52                         sndfiles.push_back (s);
53
54                         if (first) {
55                                 /* XXX: nasty magic value */
56                                 AudioStream st ("DVDOMATIC-EXTERNAL", -1, info.samplerate, av_get_default_channel_layout (info.channels));
57                                 _audio_streams.push_back (st);
58                                 _audio_stream = st;
59                                 frames = info.frames;
60                                 first = false;
61                         } else {
62                                 if (info.frames != frames) {
63                                         throw DecodeError ("external audio files have differing lengths");
64                                 }
65                         }
66                 }
67         }
68
69         sf_count_t const block = 65536;
70
71         shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream.get().channels(), block));
72         while (frames > 0) {
73                 sf_count_t const this_time = min (block, frames);
74                 for (size_t i = 0; i < sndfiles.size(); ++i) {
75                         if (!sndfiles[i]) {
76                                 audio->make_silent (i);
77                         } else {
78                                 sf_read_float (sndfiles[i], audio->data(i), block);
79                         }
80                 }
81
82                 Audio (audio);
83                 frames -= this_time;
84         }
85         
86         return true;
87 }