call IO::prepare_for_reset() on BOTH IO nodes of a PortInsert's XML state, not just...
[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 LTCFileReader::LTCFileReader (std::string path, double expected_fps, LTC_TV_STANDARD tv_standard)
46         : _path (path)
47         , _expected_fps (expected_fps)
48         , _ltc_tv_standard (tv_standard)
49         , _sndfile (0)
50         , _interleaved_audio_buffer (0)
51         , _frames_decoded (0)
52         , _samples_read (0)
53 {
54         memset (&_info, 0, sizeof (_info));
55         assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
56
57         if (open ()) {
58                 throw failed_constructor ();
59         }
60
61         const int apv = rintf (_info.samplerate / _expected_fps);
62         decoder = ltc_decoder_create (apv, 8); // must be able to hold frmes for BUFFER_SIZE
63
64 #if 0 // TODO allow to auto-detect
65         if (expected_fps == 25.0) {
66                 _ltc_tv_standard = LTC_TV_625_50;
67         }
68         else if (expected_fps == 30.0) {
69                 _ltc_tv_standard = LTC_TV_525_60;
70         }
71         else {
72                 _ltc_tv_standard = LTC_TV_FILM_24;
73         }
74 #endif
75 }
76
77 LTCFileReader::~LTCFileReader ()
78 {
79         close ();
80         ltc_decoder_free (decoder);
81         free (_interleaved_audio_buffer);
82 }
83
84 int
85 LTCFileReader::open ()
86 {
87         if (_sndfile) {
88                 return 0;
89         }
90
91 #ifdef PLATFORM_WINDOWS
92         int fd = g_open (_path.c_str (), O_RDONLY, 0444);
93 #else
94         int fd = ::open (_path.c_str (), O_RDONLY, 0444);
95 #endif
96         if (fd == -1) {
97                 error << string_compose (_("LTCFileReader: cannot open file \"%1\""), _path) << endmsg;
98                 return -1;
99         }
100
101         _sndfile = sf_open_fd (fd, SFM_READ, &_info, true);
102
103         if (_sndfile == 0) {
104                 char errbuf[1024];
105                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
106                 error << string_compose (_("LTCFileReader: cannot open file \"%1\" (%3)"), _path, errbuf) << endmsg;
107                 return -1;
108         }
109         if (_info.frames == 0 || _info.channels < 1) {
110                 error << string_compose (_("LTCFileReader: \"%1\" is an empty audio file"), _path) << endmsg;
111                 return -1;
112         }
113         _interleaved_audio_buffer = (float*) calloc (_info.channels * BUFFER_SIZE, sizeof (float));
114         return 0;
115 }
116
117 void
118 LTCFileReader::close ()
119 {
120         if (_sndfile) {
121                 sf_close (_sndfile);
122                 _sndfile = 0;
123         }
124 }
125
126 std::vector<LTCFileReader::LTCMap>
127 LTCFileReader::read_ltc (uint32_t channel, uint32_t max_frames)
128 {
129         std::vector<LTCFileReader::LTCMap> rv;
130         ltcsnd_sample_t sound[BUFFER_SIZE];
131         LTCFrameExt frame;
132
133         const uint32_t channels = _info.channels;
134         if (channel >= channels) {
135                 warning << _("LTCFileReader:: invalid audio channel selected") << endmsg;
136                 return rv;
137         }
138
139         while (1) {
140                 int64_t n = sf_readf_float (_sndfile, _interleaved_audio_buffer, BUFFER_SIZE);
141                 if (n <= 0) {
142                         break;
143                 }
144
145                 // convert audio to 8bit unsigned
146                 for (int64_t i = 0; i < n; ++i) {
147                         sound [i]= 128 + _interleaved_audio_buffer[channels * i + channel] * 127;
148                 }
149
150                 ltc_decoder_write (decoder, sound, n, _samples_read);
151
152                 while (ltc_decoder_read (decoder, &frame)) {
153                         SMPTETimecode stime;
154                         ++_frames_decoded;
155
156                         ltc_frame_to_time (&stime, &frame.ltc, /*use_date*/ 0);
157
158                         // convert Timecode to samples @ audio-file rate
159                         Timecode::Time timecode (_expected_fps);
160                         timecode.hours   = stime.hours;
161                         timecode.minutes = stime.mins;
162                         timecode.seconds = stime.secs;
163                         timecode.frames  = stime.frame;
164
165                         int64_t sample = 0;
166                         Timecode::timecode_to_sample (
167                                         timecode, sample, false, false,
168                                         _info.samplerate,
169                                         0, 0, 0);
170
171                         // align LTC frame relative to video-frame
172                         sample -= ltc_frame_alignment (
173                                         _info.samplerate / _expected_fps,
174                                         _ltc_tv_standard);
175
176                         // convert to seconds (session can use session-rate)
177                         double fp_sec = frame.off_start / (double) _info.samplerate;
178                         double tc_sec = sample / (double) _info.samplerate;
179                         rv.push_back (LTCMap (fp_sec, tc_sec));
180
181 #if 0 // DEBUG
182                         printf("LTC %02d:%02d:%02d:%02d @%9lld -> %9lld -> %fsec\n",
183                                         stime.hours,
184                                         stime.mins,
185                                         stime.secs,
186                                         stime.frame,
187                                         frame.off_start,
188                                         sample,
189                                         tc_sec);
190 #endif
191                 }
192
193                 if (n > 0) {
194                         _samples_read += n;
195                 }
196
197                 if (max_frames > 0 && rv.size () >= max_frames) {
198                         break;
199                 }
200
201         }
202
203         return rv;
204 }