Set AudioDecoder::fast a different way.
[dcpomatic.git] / src / lib / resampler.cc
1 /*
2     Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "resampler.h"
22 #include "audio_buffers.h"
23 #include "exceptions.h"
24 #include "compose.hpp"
25 #include "dcpomatic_assert.h"
26 #include <samplerate.h>
27 #include <iostream>
28
29 #include "i18n.h"
30
31 using std::cout;
32 using std::pair;
33 using std::make_pair;
34 using std::runtime_error;
35 using boost::shared_ptr;
36
37 /** @param in Input sampling rate (Hz)
38  *  @param out Output sampling rate (Hz)
39  *  @param channels Number of channels.
40  */
41 Resampler::Resampler (int in, int out, int channels)
42         : _in_rate (in)
43         , _out_rate (out)
44         , _channels (channels)
45 {
46         int error;
47         _src = src_new (SRC_SINC_BEST_QUALITY, _channels, &error);
48         if (!_src) {
49                 throw runtime_error (String::compose (N_("could not create sample-rate converter (%1)"), error));
50         }
51 }
52
53 Resampler::~Resampler ()
54 {
55         src_delete (_src);
56 }
57
58 void
59 Resampler::set_fast ()
60 {
61         src_delete (_src);
62         int error;
63         _src = src_new (SRC_LINEAR, _channels, &error);
64         if (!_src) {
65                 throw runtime_error (String::compose (N_("could not create sample-rate converter (%1)"), error));
66         }
67 }
68
69 shared_ptr<const AudioBuffers>
70 Resampler::run (shared_ptr<const AudioBuffers> in)
71 {
72         int in_frames = in->frames ();
73         int in_offset = 0;
74         int out_offset = 0;
75         shared_ptr<AudioBuffers> resampled (new AudioBuffers (_channels, 0));
76
77         while (in_frames > 0) {
78
79                 /* Compute the resampled frames count and add 32 for luck */
80                 int const max_resampled_frames = ceil ((double) in_frames * _out_rate / _in_rate) + 32;
81
82                 SRC_DATA data;
83                 data.data_in = new float[in_frames * _channels];
84
85                 {
86                         float** p = in->data ();
87                         float* q = data.data_in;
88                         for (int i = 0; i < in_frames; ++i) {
89                                 for (int j = 0; j < _channels; ++j) {
90                                         *q++ = p[j][in_offset + i];
91                                 }
92                         }
93                 }
94
95                 data.input_frames = in_frames;
96
97                 data.data_out = new float[max_resampled_frames * _channels];
98                 data.output_frames = max_resampled_frames;
99
100                 data.end_of_input = 0;
101                 data.src_ratio = double (_out_rate) / _in_rate;
102
103                 int const r = src_process (_src, &data);
104                 if (r) {
105                         delete[] data.data_in;
106                         delete[] data.data_out;
107                         throw EncodeError (
108                                 String::compose (
109                                         N_("could not run sample-rate converter (%1) [processing %2 to %3, %4 channels]"),
110                                         src_strerror (r),
111                                         in_frames,
112                                         max_resampled_frames,
113                                         _channels
114                                         )
115                                 );
116                 }
117
118                 if (data.output_frames_gen == 0) {
119                         break;
120                 }
121
122                 resampled->ensure_size (out_offset + data.output_frames_gen);
123                 resampled->set_frames (out_offset + data.output_frames_gen);
124
125                 {
126                         float* p = data.data_out;
127                         float** q = resampled->data ();
128                         for (int i = 0; i < data.output_frames_gen; ++i) {
129                                 for (int j = 0; j < _channels; ++j) {
130                                         q[j][out_offset + i] = *p++;
131                                 }
132                         }
133                 }
134
135                 in_frames -= data.input_frames_used;
136                 in_offset += data.input_frames_used;
137                 out_offset += data.output_frames_gen;
138
139                 delete[] data.data_in;
140                 delete[] data.data_out;
141         }
142
143         return resampled;
144 }
145
146 shared_ptr<const AudioBuffers>
147 Resampler::flush ()
148 {
149         shared_ptr<AudioBuffers> out (new AudioBuffers (_channels, 0));
150         int out_offset = 0;
151         int64_t const output_size = 65536;
152
153         float dummy[1];
154         float* buffer = new float[output_size];
155
156         SRC_DATA data;
157         data.data_in = dummy;
158         data.input_frames = 0;
159         data.data_out = buffer;
160         data.output_frames = output_size;
161         data.end_of_input = 1;
162         data.src_ratio = double (_out_rate) / _in_rate;
163
164         int const r = src_process (_src, &data);
165         if (r) {
166                 delete[] buffer;
167                 throw EncodeError (String::compose (N_("could not run sample-rate converter (%1)"), src_strerror (r)));
168         }
169
170         out->ensure_size (out_offset + data.output_frames_gen);
171
172         float* p = data.data_out;
173         float** q = out->data ();
174         for (int i = 0; i < data.output_frames_gen; ++i) {
175                 for (int j = 0; j < _channels; ++j) {
176                         q[j][out_offset + i] = *p++;
177                 }
178         }
179
180         out_offset += data.output_frames_gen;
181         out->set_frames (out_offset);
182
183         delete[] buffer;
184         return out;
185 }