Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / filesndfile.C
blob1ac7494c5094a17f7fbdc3ad2bf8e96013b575c8
1 #include "asset.h"
2 #include "assets.h"
3 #include "bcsignals.h"
4 #include "bcwidgetgrid.h"
5 #include "bitspopup.h"
6 #include "clip.h"
7 #include "file.h"
8 #include "filesndfile.h"
9 #include "language.h"
10 #include "mwindow.inc"
11 #include "mainerror.h"
13 FileSndFile::FileSndFile(Asset_GC asset, File *file)
14  : FileBase(asset, file)
16         temp_double = 0;
17         temp_allocated = 0;
18         fd_config.format = 0;
19         fd = 0;
22 FileSndFile::~FileSndFile()
24         if(temp_double) delete [] temp_double;
27 int FileSndFile::check_sig(Asset_GC asset)
29         int result = 0;
30         SF_INFO fd_config;
31         fd_config.format = 0;
32         SNDFILE *fd = sf_open(asset->path, SFM_READ, &fd_config);
33         if(fd)
34         {
35                 sf_close(fd);
36                 result = 1;
37         }
39         return result;
42 void FileSndFile::asset_to_format()
44         switch(asset->format)
45         {
46                 case FILE_PCM:  fd_config.format = SF_FORMAT_RAW;  break;
47                 case FILE_WAV:  fd_config.format = SF_FORMAT_WAV;  break;
48                 case FILE_AU:   fd_config.format = SF_FORMAT_AU;   break;
49                 case FILE_AIFF: fd_config.format = SF_FORMAT_AIFF; break;
50         }
52 // Not all of these are allowed in all sound formats.
53 // Raw can't be float.
54         switch(asset->bits)
55         {
56                 case BITSLINEAR8:
57                         if(asset->format == FILE_WAV)
58                                 fd_config.format |= SF_FORMAT_PCM_U8;
59                         else
60                         if(asset->signed_)
61                                 fd_config.format |= SF_FORMAT_PCM_S8;
62                         else
63                                 fd_config.format |= SF_FORMAT_PCM_U8;
64                         break;
66                 case BITSLINEAR16:
67                         fd_config.format |= SF_FORMAT_PCM_16;
69                         if(asset->byte_order || asset->format == FILE_WAV)
70                                 fd_config.format |= SF_ENDIAN_LITTLE;
71                         else
72                                 fd_config.format |= SF_ENDIAN_BIG;
73                         break;
75                 case BITSLINEAR24:
76                         fd_config.format |= SF_FORMAT_PCM_24;
78                         if(asset->byte_order || asset->format == FILE_WAV)
79                                 fd_config.format |= SF_ENDIAN_LITTLE;
80                         else
81                                 fd_config.format |= SF_ENDIAN_BIG;
82                         break;
84                 case BITSLINEAR32:
85                         fd_config.format |= SF_FORMAT_PCM_32;
87                         if(asset->byte_order || asset->format == FILE_WAV)
88                                 fd_config.format |= SF_ENDIAN_LITTLE;
89                         else
90                                 fd_config.format |= SF_ENDIAN_BIG;
91                         break;
93                 case BITSULAW: 
94                         fd_config.format |= SF_FORMAT_ULAW; 
95                         break;
97                 case BITSFLOAT: 
98                         fd_config.format |= SF_FORMAT_FLOAT; 
99                         break;
101                 case BITS_ADPCM: 
102                         if(fd_config.format == FILE_WAV)
103                                 fd_config.format |= SF_FORMAT_MS_ADPCM;
104                         else
105                                 fd_config.format |= SF_FORMAT_IMA_ADPCM; 
106                         fd_config.format |= SF_FORMAT_PCM_16;
107                         break;
108         }
110         fd_config.seekable = 1;
111         fd_config.samplerate = asset->sample_rate;
112         fd_config.channels  = asset->channels;
113 //printf("FileSndFile::asset_to_format %x %d %d\n", fd_config.format, fd_config.pcmbitwidth, fd_config.channels);
116 void FileSndFile::format_to_asset()
118 //printf("FileSndFile::format_to_asset 1\n");
119 // User supplies values if PCM
120         if(asset->format == 0)
121         {
122                 asset->byte_order = 0;
123                 asset->signed_ = 1;
124                 switch(fd_config.format & SF_FORMAT_TYPEMASK)
125                 {
126                         case SF_FORMAT_WAV:  
127                                 asset->format = FILE_WAV;  
128                                 asset->byte_order = 1;
129                                 asset->header = 44;
130                                 break;
131                         case SF_FORMAT_AIFF: asset->format = FILE_AIFF; break;
132                         case SF_FORMAT_AU:   asset->format = FILE_AU;   break;
133                         case SF_FORMAT_RAW:  asset->format = FILE_PCM;  break;
134                         case SF_FORMAT_PAF:  asset->format = FILE_SND;  break;
135                         case SF_FORMAT_SVX:  asset->format = FILE_SND;  break;
136                         case SF_FORMAT_NIST: asset->format = FILE_SND;  break;
137                 }
139                 switch(fd_config.format & SF_FORMAT_SUBMASK)
140                 {
141                         case SF_FORMAT_FLOAT: 
142                                 asset->bits = BITSFLOAT; 
143                                 break;
144                         case SF_FORMAT_ULAW: 
145                                 asset->bits = BITSULAW; 
146                                 break;
147                         case SF_FORMAT_IMA_ADPCM:
148                         case SF_FORMAT_MS_ADPCM:
149                                 asset->bits = BITS_ADPCM;
150                                 break;
151                         case SF_FORMAT_PCM_16:
152                                 asset->signed_ = 1;
153                                 asset->bits = 16;
154                                 break;
155                         case SF_FORMAT_PCM_24:
156                                 asset->signed_ = 1;
157                                 asset->bits = 24;
158                                 break;
159                         case SF_FORMAT_PCM_32:
160                                 asset->signed_ = 1;
161                                 asset->bits = 32;
162                                 break;
163                         case SF_FORMAT_PCM_S8:
164                                 asset->signed_ = 1;
165                                 asset->bits = BITSLINEAR8;
166                                 break;
167                         case SF_FORMAT_PCM_U8:
168                                 asset->signed_ = 0;
169                                 asset->bits = BITSLINEAR8;
170                                 break;
171                 }
173                 switch(fd_config.format & SF_FORMAT_ENDMASK)
174                 {
175                         case SF_ENDIAN_LITTLE:
176                                 asset->byte_order = 1;
177                                 break;
178                         case SF_ENDIAN_BIG:
179                                 asset->byte_order = 0;
180                                 break;
181                 }
183                 asset->channels = fd_config.channels;
184         }
186         asset->audio_data = 1;
187         asset->audio_length = fd_config.frames;
188         if(!asset->sample_rate)
189                 asset->sample_rate = fd_config.samplerate;
190 //printf("FileSndFile::format_to_asset %x %d %d %x\n", fd_config.format & SF_FORMAT_TYPEMASK, fd_config.pcmbitwidth, fd_config.samples, fd_config.format & SF_FORMAT_SUBMASK);
191 //asset->dump();
194 int FileSndFile::open_file(int rd, int wr)
196         int result = 0;
197         this->rd = rd;
198         this->wr = wr;
200         if(rd)
201         {
202                 if(asset->format == FILE_PCM)
203                 {
204                         asset_to_format();
205                         fd = sf_open(asset->path, SFM_READ, &fd_config);
206 // Already given by user
207                         if(fd) format_to_asset();
208                 }
209                 else
210                 {
211                         fd = sf_open(asset->path, SFM_READ, &fd_config);
212 // Doesn't calculate the length
213                         if(fd) format_to_asset();
214                 }
215 SET_TRACE
216         }
217         else
218         if(wr)
219         {
220 printf("FileSNDFile::open 1\n");
221                 asset_to_format();
222 printf("FileSNDFile::open 1\n");
223                 fd = sf_open(asset->path, SFM_WRITE, &fd_config);
224 printf("FileSNDFile::open 10 %p\n", fd);
225         }
227         if(!fd) 
228         {
229                 result = 1;
230                 eprintf("%s", sf_strerror(0));
231         }
233         return result;
236 int FileSndFile::close_file()
238         if(fd) sf_close(fd);
239         fd = 0;
240         FileBase::close_file();
241         fd_config.format = 0;
242         return 0;
245 int FileSndFile::set_audio_position(int64_t sample)
247 // Commented out /* && psf->dataoffset */ in sndfile.c: 761
248         if(sf_seek(fd, sample, SEEK_SET) < 0)
249         {
250                 eprintf("sf_seek() to sample %lld failed, reason: %s\n", sample, sf_strerror(fd));
251                 return 1;
252         }
253         return 0;
256 int FileSndFile::read_samples(double *buffer, int64_t len)
258         int result = 0;
260 //printf("FileSndFile::read_samples %lld %lld\n", file->current_sample, len);
261 // Get temp buffer for interleaved channels
262         if(len <= 0 || len > 1000000)
263                 eprintf("len=%d\n", len);
265         if(!buffer)
266                 eprintf("buffer=%p\n", buffer);
268         if(temp_allocated && temp_allocated < len)
269         {
270                 delete [] temp_double;
271                 temp_double = 0;
272                 temp_allocated = 0;
273         }
275         if(!temp_allocated)
276         {
277                 temp_allocated = len;
278                 temp_double = new double[len * asset->channels];
279         }
281         result = !sf_read_double(fd, temp_double, len * asset->channels);
283         if(result)
284                 eprintf("fd=%p temp_double=%p len=%d asset=%p asset->channels=%d\n",
285                         fd, temp_double, len, asset, asset->channels);
287 // Extract single channel
288         for(int i = 0, j = file->current_channel; 
289                 i < len;
290                 i++, j += asset->channels)
291         {
292                 buffer[i] = temp_double[j];
293         }
295         return result;
298 int FileSndFile::write_samples(double **buffer, int64_t len)
300         int result = 0;
302 // Get temp buffer for interleaved channels
303 //printf("FileSndFile::read_samples 1\n");
304         if(temp_allocated && temp_allocated < len)
305         {
306                 temp_allocated = 0;
307                 delete [] temp_double;
308                 temp_double = 0;
309         }
311 //printf("FileSndFile::read_samples 2\n");
312         if(!temp_allocated)
313         {
314                 temp_allocated = len;
315                 temp_double = new double[len * asset->channels];
316         }
318 // Interleave channels
319         for(int i = 0; i < asset->channels; i++)
320         {
321                 for(int j = 0; j < len; j++)
322                 {
323                         double sample = buffer[i][j];
324 // Libsndfile does not limit values
325 //if(sample > 1.0 || sample < -1.0) printf("FileSndFile::write_samples %f\n", sample);
326 //printf("FileSndFile::write_samples %d %d\n", asset->bits, BITSFLOAT);
327                         if(asset->bits != BITSFLOAT) CLAMP(sample, -1.0, (32767.0 / 32768.0));
328                         temp_double[j * asset->channels + i] = sample;
329                 }
330         }
332         result = !sf_writef_double(fd, temp_double, len);
334         return result;
337 void FileSndFile::get_parameters(BC_WindowBase *parent_window, 
338                 Asset_GC asset, 
339                 BC_WindowBase* &format_window,
340                 int audio_options,
341                 int video_options)
343         if(audio_options)
344         {
345                 SndFileConfig *window = new SndFileConfig(parent_window, asset);
346                 format_window = window;
347                 window->create_objects();
348                 window->run_window();
349                 delete window;
350         }
353 SndFileConfig::SndFileConfig(BC_WindowBase *parent_window, Asset_GC asset)
354  : BC_Window(PROGRAM_NAME ": Audio Compression",
355         parent_window->get_abs_cursor_x(1),
356         parent_window->get_abs_cursor_y(1),
357         250,
358              250,
359              250,
360              250,
361              0,
362              1)
364         this->parent_window = parent_window;
365         this->asset = asset;
368 SndFileConfig::~SndFileConfig()
370         if(bits_popup) delete bits_popup;
372 int SndFileConfig::create_objects()
374         int x = 10, y = 10;
376         BC_WidgetGrid *wg, *wg2;
377         BC_RelocatableWidget *rw;
378         int wg_row = 0;
379         wg = add_widgetgrid(new BC_WidgetGrid(10, 10, 10, 10, 3, 3));
381         bits_popup = 0;
382         switch(asset->format)
383         {
384                 case FILE_WAV:
385                 case FILE_PCM:
386                 case FILE_AIFF:
387                         rw =
388                         add_tool(new BC_Title(x, y, _("Compression:")));
389                         y += 25;
390                         if(asset->format == FILE_WAV)
391                                 bits_popup = new BitsPopup(this, x, y, &asset->bits, 0, 0, 1, 1, 0);
392                         else
393                                 bits_popup = new BitsPopup(this, x, y, &asset->bits, 0, 0, 0, 0, 0);
394                         y += 40;
395                         bits_popup->create_objects();
396                         wg->add(rw, wg_row, 0);
397                         wg->add(bits_popup, wg_row++, 1);
398                         break;
399         }
401         x = 10;
402         if(asset->format == FILE_AU)
403         {
404                 rw =
405                 add_subwindow(new BC_Title(x, y,_("There are no audio options for this format")));
406                 wg->add(rw, wg_row++, 1);
407         }
408         y += 30;
410         if(asset->format != FILE_AU)
411         {
412                 rw =
413                 add_subwindow(new BC_CheckBox(x, y, &asset->dither, _("Dither")));
414                 wg->add(rw, wg_row++, 1);
415         }
416         y += 30;
417         if(asset->format == FILE_PCM)
418         {
419                 rw =
420                 add_subwindow(new BC_CheckBox(x, y, &asset->signed_, _("Signed")));
421                 wg->add(rw, wg_row++, 1);
422                 y += 35;
423                 rw =
424                 add_subwindow(new BC_Title(x, y, _("Byte order:")));
425                 add_subwindow(hilo = new SndFileHILO(this, x + 100, y));
426                 add_subwindow(lohi = new SndFileLOHI(this, x + 170, y));
427                 wg->add(rw, wg_row, 0);
428                 wg2 = add_widgetgrid(new BC_WidgetGrid(10, 10, 10, 10, 3, 3));
429                 wg2->add(hilo, 0, 0);
430                 wg2->add(lohi, 0, 1);
431                 wg->add(wg2, wg_row++, 1);
432         }
433         rw =
434         add_subwindow(new BC_OKButton(this));
436         wg->move_widgets();
437         resize_window(wg->get_w_wm(), wg->get_h_wm() + rw->get_h());
438         return 0;
441 int SndFileConfig::close_event()
443         set_done(0);
444         return 1;
449 SndFileHILO::SndFileHILO(SndFileConfig *gui, int x, int y)
450  : BC_Radial(x, y, gui->asset->byte_order == 0, _("Hi Lo"))
452         this->gui = gui;
454 int SndFileHILO::handle_event()
456         gui->asset->byte_order = 0;
457         gui->lohi->update(0);
458         return 1;
464 SndFileLOHI::SndFileLOHI(SndFileConfig *gui, int x, int y)
465  : BC_Radial(x, y, gui->asset->byte_order == 1, _("Lo Hi"))
467         this->gui = gui;
469 int SndFileLOHI::handle_event()
471         gui->asset->byte_order = 1;
472         gui->hilo->update(0);
473         return 1;
478 //      Local Variables:
479 //      mode: C++
480 //      c-file-style: "linux"
481 //      End: