Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / fileflac.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program 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  * This program 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 this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "FLAC/stream_decoder.h"
28 #include "FLAC/stream_encoder.h"
29
30 #define IS_FILEFLAC
31 #include "asset.h"
32 #include "bcsignals.h"
33 #include "bitspopup.h"
34 #include "byteorder.h"
35 #include "clip.h"
36 #include "file.h"
37 #include "fileflac.h"
38 #include "filesystem.h"
39 #include "guicast.h"
40 #include "language.h"
41 #include "mwindow.inc"
42
43
44 FileFLAC::FileFLAC(Asset *asset, File *file)
45  : FileBase(asset, file)
46 {
47         reset_parameters();
48         if(asset->format == FILE_UNKNOWN) asset->format = FILE_FLAC;
49         asset->byte_order = 0;
50 }
51
52 FileFLAC::~FileFLAC()
53 {
54         close_file();
55 }
56
57 void FileFLAC::get_parameters(BC_WindowBase *parent_window,
58         Asset *asset, BC_WindowBase* &format_window,
59         int audio_options, int video_options, EDL *edl)
60 {
61         if(audio_options)
62         {
63                 FLACConfigAudio *window = new FLACConfigAudio(parent_window, asset);
64                 format_window = window;
65                 window->create_objects();
66                 window->run_window();
67                 delete window;
68         }
69 }
70
71
72
73 int FileFLAC::check_sig(Asset *asset, char *test)
74 {
75         return test[0]=='f' && test[1]=='L' && test[2]=='a' && test[3]=='C' ? 1 : 0;
76 }
77
78 int FileFLAC::reset_parameters_derived()
79 {
80         pcm_history = 0;
81         flac_decode = 0;
82         flac_encode = 0;
83         temp_buffer = 0;
84         temp_allocated = 0;
85         temp_channels = 0;
86         initialized = 0;
87         is_reading = 0;
88         return 0;
89 }
90
91
92 static FLAC__StreamDecoderWriteStatus write_callback(
93         const FLAC__StreamDecoder *decoder,
94         const FLAC__Frame *frame,
95         const FLAC__int32 * const buffer[],
96         void *client_data)
97 {
98         FileFLAC *ptr = (FileFLAC*)client_data;
99
100         if(!ptr->initialized)
101         {
102                 ptr->initialized = 1;
103                 ptr->asset->audio_data = 1;
104                 ptr->asset->channels = FLAC__stream_decoder_get_channels(ptr->flac_decode);
105                 ptr->asset->bits = FLAC__stream_decoder_get_bits_per_sample(ptr->flac_decode);
106                 ptr->asset->sample_rate = FLAC__stream_decoder_get_sample_rate(ptr->flac_decode);
107                 ptr->asset->audio_length = FLAC__stream_decoder_get_total_samples(ptr->flac_decode);
108                 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
109         }
110         else
111         if(ptr->is_reading)
112         {
113                 int fragment = FLAC__stream_decoder_get_blocksize(ptr->flac_decode);
114                 ptr->samples_read += fragment;
115 //printf("write_callback 2 %d\n", fragment);
116
117                 if(ptr->temp_allocated < fragment)
118                 {
119                         if(ptr->temp_buffer)
120                         {
121                                 for(int i = 0; i < ptr->temp_channels; i++)
122                                 {
123                                         delete [] ptr->temp_buffer[i];
124                                 }
125                                 delete [] ptr->temp_buffer;
126                         }
127
128                         ptr->temp_channels = ptr->asset->channels;
129                         ptr->temp_buffer = new int32_t*[ptr->temp_channels];
130                         for(int i = 0; i < ptr->temp_channels; i++)
131                         {
132                                 ptr->temp_buffer[i] = new int32_t[fragment];
133                         }
134                         ptr->temp_allocated = fragment;
135                 }
136
137                 float audio_max = (float)0x7fff;
138                 if(FLAC__stream_decoder_get_bits_per_sample(ptr->flac_decode) == 24)
139                         audio_max = (float)0x7fffff;
140
141                 int nchannels = FLAC__stream_decoder_get_channels(ptr->flac_decode);
142                 if( nchannels > ptr->temp_channels ) nchannels = ptr->temp_channels;
143                 for(int j = 0; j < nchannels; j++)
144                 {
145                         float *dst = (float*)ptr->temp_buffer[j];
146                         int32_t *src = (int32_t*)buffer[j];
147                         for(int i = 0; i < fragment; i++)
148                         {
149                                 *dst++ = (float)*src++ / audio_max;
150                         }
151                 }
152
153                 ptr->append_history((float**)ptr->temp_buffer, fragment);
154
155 //printf("write_callback 3\n");
156                 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
157         }
158
159         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
160 }
161
162
163 static void metadata_callback(const FLAC__StreamDecoder *decoder,
164         const FLAC__StreamMetadata *metadata,
165         void *client_data)
166 {
167 //      printf("metadata_callback\n");
168 }
169
170 static void error_callback(const FLAC__StreamDecoder *decoder,
171         FLAC__StreamDecoderErrorStatus status,
172         void *client_data)
173 {
174 //      printf("error_callback\n");
175 }
176
177
178
179
180
181 int FileFLAC::open_file(int rd, int wr)
182 {
183         int result = 0;
184
185         if(rd)
186         {
187                 file_bytes = FileSystem::get_size(asset->path);
188                 flac_decode = FLAC__stream_decoder_new();
189                 FLAC__stream_decoder_init_file(flac_decode,
190                         asset->path,
191                         write_callback,
192                         metadata_callback,
193                         error_callback,
194                         this);
195
196                 initialized = 0;
197                 while(!initialized)
198                 {
199                         if(!FLAC__stream_decoder_process_single(flac_decode)) break;
200                 }
201
202                 if(!initialized)
203                         result = 1;
204                 else
205                 {
206                         FLAC__stream_decoder_seek_absolute(flac_decode, 0);
207                 }
208         }
209
210         if(wr)
211         {
212                 flac_encode = FLAC__stream_encoder_new();
213                 FLAC__stream_encoder_set_channels(flac_encode, asset->channels);
214                 FLAC__stream_encoder_set_bits_per_sample(flac_encode, asset->bits);
215                 FLAC__stream_encoder_set_sample_rate(flac_encode, asset->sample_rate);
216                 FLAC__stream_encoder_set_compression_level(flac_encode, asset->flac_compression);
217                 FLAC__stream_encoder_init_file(flac_encode, asset->path, 0, 0);
218         }
219
220         return result;
221 }
222
223
224 int FileFLAC::close_file_derived()
225 {
226         if(flac_decode)
227         {
228                 FLAC__stream_decoder_finish(flac_decode);
229                 FLAC__stream_decoder_delete(flac_decode);
230         }
231
232         if(flac_encode)
233         {
234                 FLAC__stream_encoder_finish(flac_encode);
235                 FLAC__stream_encoder_delete(flac_encode);
236         }
237
238
239         if(temp_buffer)
240         {
241                 for(int i = 0; i < temp_channels; i++)
242                         delete [] temp_buffer[i];
243                 delete [] temp_buffer;
244         }
245         return 0;
246 }
247
248
249 int FileFLAC::write_samples(double **buffer, int64_t len)
250 {
251 // Create temporary buffer of samples
252         if(temp_allocated < len)
253         {
254                 if(temp_buffer)
255                 {
256                         for(int i = 0; i < asset->channels; i++)
257                         {
258                                 delete [] temp_buffer[i];
259                         }
260                         delete [] temp_buffer;
261                 }
262
263                 temp_buffer = new int32_t*[asset->channels];
264                 for(int i = 0; i < asset->channels; i++)
265                 {
266                         temp_buffer[i] = new int32_t[len];
267                 }
268                 temp_allocated = len;
269         }
270
271         float audio_max = (float)0x7fff;
272
273         switch(asset->bits)
274         {
275                 case 24:
276                         audio_max = (float)0x7fffff;
277                         break;
278         }
279
280         for(int i = 0; i < asset->channels; i++)
281         {
282                 int32_t *dst = temp_buffer[i];
283                 double *src = buffer[i];
284                 for(int j = 0; j < len; j++)
285                 {
286                         double sample = *src++ * audio_max;
287                         CLAMP(sample, -audio_max, audio_max);
288                         *dst++ = (int32_t)sample;
289                 }
290         }
291
292         int result = FLAC__stream_encoder_process(flac_encode,
293                 temp_buffer,
294                 len);
295
296         return !result;
297 }
298
299 int FileFLAC::read_samples(double *buffer, int64_t len)
300 {
301         int result = 0;
302         update_pcm_history(len);
303
304         if(decode_end != decode_start)
305         {
306                 FLAC__stream_decoder_seek_absolute(flac_decode, decode_start);
307                 decode_end = decode_start;
308         }
309
310         samples_read = 0;
311         is_reading = 1;
312
313         while(samples_read < decode_len)
314         {
315                 FLAC__uint64 position;
316                 FLAC__stream_decoder_get_decode_position(flac_decode, &position);
317 // EOF
318                 if((int64_t)position >= file_bytes) break;
319                 if(!FLAC__stream_decoder_process_single(flac_decode)) {
320                         result = 1;
321                         break;
322                 }
323         }
324         is_reading = 0;
325
326         if(!result)
327         {
328                 read_history(buffer,
329                         file->current_sample,
330                         file->current_channel,
331                         len);
332         }
333
334 //printf("FileFLAC::read_samples 10\n");
335         return result;
336 }
337
338
339 FLACConfigAudio::FLACConfigAudio(BC_WindowBase *parent_window,
340         Asset *asset)
341  : BC_Window(_(PROGRAM_NAME ": Audio Compression"),
342         parent_window->get_abs_cursor_x(1), parent_window->get_abs_cursor_y(1),
343         xS(350), yS(170), -1, -1, 0, 0, 1)
344 {
345         this->parent_window = parent_window;
346         this->asset = asset;
347         compression = 0;
348 // *** CONTEXT_HELP ***
349         context_help_set_keyword("Single File Rendering");
350 }
351
352 FLACConfigAudio::~FLACConfigAudio()
353 {
354         delete compression;
355 }
356
357 void FLACConfigAudio::create_objects()
358 {
359         BC_Title *title;
360         int ys5 = yS(5), xs100 = xS(100);
361         int x = xS(10), y = yS(10);
362         lock_window("FLACConfigAudio::create_objects");
363         bits_popup = new BitsPopup(this, x, y, &asset->bits, 0, 0, 0, 0, 0);
364         bits_popup->create_objects();
365         y += bits_popup->get_h() + ys5;
366         add_subwindow(title = new BC_Title(x,y,_("Compression:")));
367         int x1 = x + title->get_w() + xs100;
368         compression = new FLACCompression(this, x1, y);
369         compression->create_objects();
370         y += compression->get_h() + ys5;
371         add_subwindow(new BC_OKButton(this));
372         show_window(1);
373         unlock_window();
374 }
375
376 FLACCompression::FLACCompression(FLACConfigAudio *gui, int x, int y)
377 : BC_TumbleTextBox(gui, (int64_t)gui->asset->flac_compression,
378   (int64_t)0, (int64_t)8, x, y, xS(40))
379
380 {
381         this->gui = gui;
382 }
383
384 int FLACCompression::handle_event()
385 {
386         gui->asset->flac_compression = atol(get_text());
387         return 1;
388 }
389
390
391 int FLACConfigAudio::close_event()
392 {
393         set_done(0);
394         return 1;
395 }
396