45b91bfa5d2b4c0254b729284715cce84d0f7b50
[ardour.git] / libs / ardour / ltc_file_reader.cc
1 /*
2     Copyright (C) 2015 Robin Gareus <robin@gareus.org>
3
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.
8
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.
13
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.
17 */
18
19 #include <fcntl.h>
20 #include <sys/stat.h>
21
22 #include <glib.h>
23 #include "pbd/gstdio_compat.h"
24
25 #include <assert.h>
26 #include <string.h>
27 #include <glibmm.h>
28
29 #include "pbd/error.h"
30 #include "pbd/failed_constructor.h"
31
32 #include "temporal/time.h"
33
34 #include "ardour/ltc_file_reader.h"
35
36 #include "pbd/i18n.h"
37
38 using namespace std;
39 using namespace ARDOUR;
40 using namespace PBD;
41 using std::string;
42
43 #define BUFFER_SIZE 1024 // audio chunk size
44
45 LTCReader::LTCReader (int expected_apv, LTC_TV_STANDARD tv_standard)
46         : _position (0)
47 {
48         _decoder = ltc_decoder_create (expected_apv, 8); // must be able to hold frmes for BUFFER_SIZE
49 }
50
51 LTCReader::~LTCReader ()
52 {
53         ltc_decoder_free (_decoder);
54 }
55
56 void
57 LTCReader::write (float const* data, samplecnt_t n_samples, samplepos_t pos)
58 {
59         ltc_off_t off = _position;
60         if (pos < 0) {
61                 off = _position;
62                 _position += n_samples;
63         }
64
65         samplecnt_t remain = n_samples;
66         while (remain > 0) {
67                 ltcsnd_sample_t sound[BUFFER_SIZE];
68                 int c = std::min (remain, (samplecnt_t)BUFFER_SIZE);
69                 for (int i = 0; i < c; ++i) {
70                         sound[i] = 128 + (*data++) * 127.0;
71                 }
72                 ltc_decoder_write (_decoder, sound, c, off);
73                 off += c;
74                 remain -= c;
75         }
76 }
77
78 void
79 LTCReader::raw_write (ltcsnd_sample_t* buf, size_t size, ltc_off_t off)
80 {
81         ltc_decoder_write (_decoder, buf, size, off);
82 }
83
84 bool
85 LTCReader::read (uint32_t& hh, uint32_t& mm, uint32_t& ss, uint32_t& ff)
86 {
87         LTCFrameExt ltc_frame;
88         bool rv = 0 != ltc_decoder_read (_decoder, &ltc_frame);
89         if (rv) {
90                 SMPTETimecode stime;
91                 ltc_frame_to_time (&stime, &ltc_frame.ltc, /*use_date*/ 0);
92                 hh   = stime.hours;
93                 mm = stime.mins;
94                 ss = stime.secs;
95                 ff  = stime.frame;
96
97 #if 0 // DEBUG
98                         printf("LTC %02d:%02d:%02d:%02d @%9lld -> %9lld -> %fsec\n",
99                                         stime.hours,
100                                         stime.mins,
101                                         stime.secs,
102                                         stime.frame,
103                                         frame.off_start,
104                                         sample,
105                                         tc_sec);
106 #endif
107         }
108         return rv;
109 }
110
111
112 LTCFileReader::LTCFileReader (std::string path, double expected_fps, LTC_TV_STANDARD tv_standard)
113         : _path (path)
114         , _expected_fps (expected_fps)
115         , _ltc_tv_standard (tv_standard)
116         , _sndfile (0)
117         , _reader (0)
118         , _interleaved_audio_buffer (0)
119         , _samples_read (0)
120 {
121         memset (&_info, 0, sizeof (_info));
122         assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
123
124         if (open ()) {
125                 throw failed_constructor ();
126         }
127
128         const int apv = rintf (_info.samplerate / _expected_fps);
129
130 #if 0 // TODO allow to auto-detect
131         if (expected_fps == 25.0) {
132                 _ltc_tv_standard = LTC_TV_625_50;
133         }
134         else if (expected_fps == 30.0) {
135                 _ltc_tv_standard = LTC_TV_525_60;
136         }
137         else {
138                 _ltc_tv_standard = LTC_TV_FILM_24;
139         }
140 #endif
141         _reader = new LTCReader (apv, _ltc_tv_standard);
142 }
143
144 LTCFileReader::~LTCFileReader ()
145 {
146         close ();
147         delete _reader;
148         free (_interleaved_audio_buffer);
149 }
150
151 int
152 LTCFileReader::open ()
153 {
154         if (_sndfile) {
155                 return 0;
156         }
157
158 #ifdef PLATFORM_WINDOWS
159         int fd = g_open (_path.c_str (), O_RDONLY, 0444);
160 #else
161         int fd = ::open (_path.c_str (), O_RDONLY, 0444);
162 #endif
163         if (fd == -1) {
164                 error << string_compose (_("LTCFileReader: cannot open file \"%1\""), _path) << endmsg;
165                 return -1;
166         }
167
168         _sndfile = sf_open_fd (fd, SFM_READ, &_info, true);
169
170         if (_sndfile == 0) {
171                 char errbuf[1024];
172                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
173                 error << string_compose (_("LTCFileReader: cannot open file \"%1\" (%3)"), _path, errbuf) << endmsg;
174                 return -1;
175         }
176         if (_info.frames == 0 || _info.channels < 1) {
177                 error << string_compose (_("LTCFileReader: \"%1\" is an empty audio file"), _path) << endmsg;
178                 return -1;
179         }
180         _interleaved_audio_buffer = (float*) calloc (_info.channels * BUFFER_SIZE, sizeof (float));
181         return 0;
182 }
183
184 void
185 LTCFileReader::close ()
186 {
187         if (_sndfile) {
188                 sf_close (_sndfile);
189                 _sndfile = 0;
190         }
191 }
192
193 std::vector<LTCFileReader::LTCMap>
194 LTCFileReader::read_ltc (uint32_t channel, uint32_t max_frames)
195 {
196         std::vector<LTCFileReader::LTCMap> rv;
197         ltcsnd_sample_t sound[BUFFER_SIZE];
198         LTCFrameExt frame;
199
200         const uint32_t channels = _info.channels;
201         if (channel >= channels) {
202                 warning << _("LTCFileReader:: invalid audio channel selected") << endmsg;
203                 return rv;
204         }
205
206         while (1) {
207                 int64_t n = sf_readf_float (_sndfile, _interleaved_audio_buffer, BUFFER_SIZE);
208                 if (n <= 0) {
209                         break;
210                 }
211
212                 // convert audio to 8bit unsigned
213                 for (int64_t i = 0; i < n; ++i) {
214                         sound [i]= 128 + _interleaved_audio_buffer[channels * i + channel] * 127;
215                 }
216
217                 _reader->raw_write (sound, n, _samples_read);
218                 Timecode::Time timecode (_expected_fps);
219
220                 while (_reader->read (timecode.hours, timecode.minutes, timecode.seconds, timecode.frames)) {
221                         int64_t sample = 0;
222                         Timecode::timecode_to_sample (
223                                         timecode, sample, false, false,
224                                         _info.samplerate,
225                                         0, 0, 0);
226
227                         // align LTC frame relative to video-frame
228                         sample -= ltc_frame_alignment (
229                                         _info.samplerate / _expected_fps,
230                                         _ltc_tv_standard);
231
232                         // convert to seconds (session can use session-rate)
233                         double fp_sec = frame.off_start / (double) _info.samplerate;
234                         double tc_sec = sample / (double) _info.samplerate;
235                         rv.push_back (LTCMap (fp_sec, tc_sec));
236                 }
237
238                 if (n > 0) {
239                         _samples_read += n;
240                 }
241
242                 if (max_frames > 0 && rv.size () >= max_frames) {
243                         break;
244                 }
245         }
246
247         return rv;
248 }