1 /*
2 * Copyright (C) 2002 2003 2004 2005 2006 2009 2010 2012, Magnus Hjorth
3 *
4 * This file is part of mhWaveEdit.
5 *
6 * mhWaveEdit 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 * mhWaveEdit 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 mhWaveEdit; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21
22 #include <config.h>
23
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include "gtkfiles.h"
28 #include "ringbuf.h"
29 #include "um.h"
30 #include "main.h"
31 #include "inifile.h"
32
33 #include "datasource.h"
34 #include "tempfile.h"
35 #include "gettext.h"
36
37 static GtkObjectClass *parent_class;
38 static GList *datasource_list = NULL;
39
40
datasource_count(void)41 guint datasource_count(void)
42 {
43 return g_list_length(datasource_list);
44 }
45
datasource_init(Datasource * obj)46 static void datasource_init(Datasource *obj)
47 {
48 /* printf("datasource_init(%p)\n",obj); */
49 datasource_list = g_list_append(datasource_list, obj);
50 obj->type = DATASOURCE_SILENCE;
51 obj->format.type = DATAFORMAT_PCM;
52 obj->format.samplerate=44100;
53 obj->format.samplesize=2;
54 obj->format.packing=0;
55 obj->format.channels=2;
56 obj->format.sign=1;
57 obj->format.bigendian = IS_BIGENDIAN;
58 obj->format.samplebytes=4;
59 obj->length = 0;
60 obj->bytes = 0;
61 obj->opencount = 0;
62 obj->read_temparea.ptr = NULL;
63 obj->read_temparea.size = 0;
64 obj->readfp_temparea.ptr = NULL;
65 obj->readfp_temparea.size = 0;
66 obj->tag = 0;
67 }
68
datasource_clear(Datasource * ds)69 static void datasource_clear(Datasource *ds)
70 {
71 g_assert(ds->opencount == 0);
72 g_assert(ds->read_temparea.ptr == NULL && ds->readfp_temparea.ptr == NULL);
73
74 switch (ds->type) {
75
76 case DATASOURCE_TEMPFILE:
77 if (ds->data.virtual.filename)
78 xunlink(ds->data.virtual.filename);
79 /* Fall through */
80
81 case DATASOURCE_VIRTUAL:
82 if (ds->data.virtual.filename) {
83 g_free(ds->data.virtual.filename);
84 ds->data.virtual.filename = NULL;
85 }
86 break;
87
88 case DATASOURCE_REAL:
89 if (ds->data.real) {
90 g_free(ds->data.real);
91 ds->data.real = NULL;
92 }
93 break;
94
95 case DATASOURCE_SNDFILE_TEMPORARY:
96 if (ds->data.sndfile.filename)
97 xunlink(ds->data.sndfile.filename);
98 /* Fall through */
99
100 case DATASOURCE_SNDFILE:
101 if (ds->data.sndfile.filename) {
102 g_free(ds->data.sndfile.filename);
103 ds->data.sndfile.filename = NULL;
104 }
105 break;
106
107 case DATASOURCE_REF:
108 case DATASOURCE_CLONE:
109 case DATASOURCE_BYTESWAP:
110 case DATASOURCE_CONVERT:
111 if (ds->data.clone)
112 gtk_object_unref(GTK_OBJECT(ds->data.clone));
113 ds->data.clone = NULL;
114 break;
115
116 case DATASOURCE_CHANMAP:
117 if (ds->data.chanmap.clone)
118 gtk_object_unref(GTK_OBJECT(ds->data.chanmap.clone));
119 if (ds->data.chanmap.map)
120 g_free(ds->data.chanmap.map);
121 ds->data.chanmap.clone = NULL;
122 ds->data.chanmap.map = NULL;
123
124 }
125
126 ds->type = DATASOURCE_SILENCE;
127 }
128
datasource_destroy(GtkObject * obj)129 static void datasource_destroy(GtkObject *obj)
130 {
131 Datasource *ds = DATASOURCE(obj);
132 /* printf("datasource_destroy(%p)\n",obj); */
133 datasource_clear(ds);
134 datasource_list = g_list_remove(datasource_list, obj);
135 parent_class->destroy(obj);
136 }
137
datasource_class_init(GtkObjectClass * klass)138 static void datasource_class_init(GtkObjectClass *klass)
139 {
140 parent_class = gtk_type_class(gtk_object_get_type());
141 klass->destroy = datasource_destroy;
142 }
143
datasource_get_type(void)144 GtkType datasource_get_type(void)
145 {
146 static GtkType id = 0;
147 if (!id) {
148 GtkTypeInfo info = {
149 "Datasource",
150 sizeof(Datasource),
151 sizeof(DatasourceClass),
152 (GtkClassInitFunc) datasource_class_init,
153 (GtkObjectInitFunc) datasource_init
154 };
155 id=gtk_type_unique(gtk_object_get_type(),&info);
156 }
157 return id;
158 }
159
datasource_get_temparea(struct temparea * ta,int size)160 static char *datasource_get_temparea(struct temparea *ta, int size)
161 {
162 if (size > ta->size) {
163 g_free(ta->ptr);
164 ta->ptr = g_malloc(size);
165 ta->size = size;
166 }
167 return ta->ptr;
168 }
169
170 /* Creates a copy of the original datasource
171 * If it refers to a file, create a DATASOURCE_REF instead.
172 */
173
datasource_copy(Datasource * orig)174 static Datasource *datasource_copy(Datasource *orig)
175 {
176 Datasource *ds;
177
178 ds = gtk_type_new(datasource_get_type());
179 ds->type = orig->type;
180 memcpy(&(ds->format),&(orig->format),sizeof(Dataformat));
181 ds->length = orig->length;
182 ds->bytes = orig->bytes;
183
184 switch (orig->type) {
185 case DATASOURCE_VIRTUAL:
186 case DATASOURCE_TEMPFILE:
187 case DATASOURCE_SNDFILE:
188 case DATASOURCE_SNDFILE_TEMPORARY:
189 ds->type = DATASOURCE_REF;
190 ds->data.clone = orig;
191 gtk_object_ref(GTK_OBJECT(orig));
192 gtk_object_sink(GTK_OBJECT(orig));
193 break;
194 case DATASOURCE_REAL:
195 ds->data.real = g_malloc(orig->bytes);
196 memcpy(ds->data.real, orig->data.real, orig->bytes);
197 break;
198 case DATASOURCE_CLONE:
199 case DATASOURCE_BYTESWAP:
200 case DATASOURCE_REF:
201 case DATASOURCE_CONVERT:
202 ds->data.clone = orig->data.clone;
203 gtk_object_ref(GTK_OBJECT(ds->data.clone));
204 gtk_object_sink(GTK_OBJECT(ds->data.clone));
205 break;
206 case DATASOURCE_CHANMAP:
207 ds->data.chanmap.clone = orig->data.chanmap.clone;
208 gtk_object_ref(GTK_OBJECT(ds->data.chanmap.clone));
209 gtk_object_sink(GTK_OBJECT(ds->data.chanmap.clone));
210 ds->data.chanmap.map = g_malloc(ds->format.channels * sizeof(int));
211 memcpy(ds->data.chanmap.map, orig->data.chanmap.map,
212 ds->format.channels*sizeof(int));
213 break;
214 }
215 return ds;
216 }
217
datasource_clone_df(Datasource * source,Dataformat * format)218 Datasource *datasource_clone_df(Datasource *source, Dataformat *format)
219 {
220 Datasource *df;
221
222 if (source->type == DATASOURCE_REAL ||
223 source->type == DATASOURCE_SILENCE ||
224 source->type == DATASOURCE_CLONE) {
225 df = datasource_copy(source);
226 g_assert(df->type == source->type);
227 memcpy(&(df->format),format,sizeof(Dataformat));
228 df->length = df->bytes / format->samplebytes;
229 return df;
230 }
231
232 df = gtk_type_new(datasource_get_type());
233 df->type = DATASOURCE_CLONE;
234 memcpy(&(df->format),format,sizeof(Dataformat));
235 df->bytes = source->bytes;
236 df->length = source->bytes / format->samplebytes;
237 df->data.clone = source;
238 gtk_object_ref(GTK_OBJECT(source));
239 return df;
240 }
241
datasource_byteswap(Datasource * source)242 Datasource *datasource_byteswap(Datasource *source)
243 {
244 Datasource *ds;
245 if (source == NULL) return NULL;
246 ds = gtk_type_new(datasource_get_type());
247 ds->type = DATASOURCE_BYTESWAP;
248 memcpy(&(ds->format),&(source->format),sizeof(Dataformat));
249 ds->format.bigendian = !source->format.bigendian;
250 ds->length = source->length;
251 ds->bytes = source->bytes;
252 ds->data.clone = source;
253 gtk_object_ref(GTK_OBJECT(source));
254 gtk_object_sink(GTK_OBJECT(source));
255 return ds;
256 }
257
datasource_channel_map(Datasource * source,int n_channels,int * map)258 Datasource *datasource_channel_map(Datasource *source, int n_channels,
259 int *map)
260 {
261 Datasource *ds;
262
263 if (source == NULL) return NULL;
264
265 ds = gtk_type_new(datasource_get_type());
266 ds->type = DATASOURCE_CHANMAP;
267 memcpy(&(ds->format),&(source->format),sizeof(Dataformat));
268 ds->format.channels = n_channels;
269 ds->format.samplebytes = ds->format.samplesize * n_channels;
270 ds->length = source->length;
271 ds->bytes = ds->length * ds->format.samplebytes;
272 ds->data.chanmap.clone = source;
273 gtk_object_ref(GTK_OBJECT(source));
274 gtk_object_sink(GTK_OBJECT(source));
275 ds->data.chanmap.map = g_malloc(n_channels * sizeof(int));
276 memcpy(ds->data.chanmap.map, map, n_channels*sizeof(int));
277
278 return ds;
279 }
280
datasource_new_silent(Dataformat * format,off_t samples)281 Datasource *datasource_new_silent(Dataformat *format, off_t samples)
282 {
283 Datasource *ds;
284 ds = gtk_type_new(datasource_get_type());
285 memcpy(&(ds->format), format, sizeof(Dataformat));
286 ds->type = DATASOURCE_SILENCE;
287 ds->length = samples;
288 ds->bytes = samples * ds->format.samplebytes;
289 return ds;
290 }
291
datasource_new_from_data(void * data,Dataformat * format,guint32 size)292 Datasource *datasource_new_from_data(void *data, Dataformat *format,
293 guint32 size)
294 {
295 Datasource *ds;
296 ds = (Datasource *)gtk_type_new(datasource_get_type());
297 ds->type = DATASOURCE_REAL;
298 memcpy(&(ds->format),format,sizeof(Dataformat));
299 ds->length = size / format->samplebytes;
300 ds->bytes = size;
301 ds->data.real = data;
302 return ds;
303 }
304
305 #define DUMP_BUFSIZE 65536
306
datasource_dump(Datasource * ds,off_t position,off_t length,EFILE * file,int dither_mode,StatusBar * bar,off_t * clipcount)307 gboolean datasource_dump(Datasource *ds, off_t position,
308 off_t length, EFILE *file, int dither_mode,
309 StatusBar *bar, off_t *clipcount)
310 {
311 gchar *buf;
312 off_t i;
313 guint u;
314 if (datasource_open(ds)) return TRUE;
315 buf = g_malloc(DUMP_BUFSIZE);
316 while (length > 0) {
317 i = MIN(length*ds->format.samplebytes,DUMP_BUFSIZE);
318 u = datasource_read_array(ds,position,i,buf,dither_mode,clipcount);
319 if (u==0 || e_fwrite(buf,u,file) || status_bar_progress(bar,u)) {
320 datasource_close(ds);
321 g_free(buf);
322 return TRUE;
323 }
324 length -= u/ds->format.samplebytes;
325 position += u/ds->format.samplebytes;
326 }
327 datasource_close(ds);
328 g_free(buf);
329 return FALSE;
330 }
331
datasource_realize(Datasource * ds,int dither_mode)332 gboolean datasource_realize(Datasource *ds, int dither_mode)
333 {
334 gchar *c;
335 guint32 sz=ds->bytes;
336
337 if (datasource_open(ds)) return TRUE;
338
339 c = g_malloc(sz);
340 if (datasource_read_array(ds,0,sz,c, dither_mode,NULL)) {
341 g_free(c);
342 datasource_close(ds);
343 return TRUE;
344 }
345 datasource_close(ds);
346
347 datasource_clear(ds);
348 ds->type = DATASOURCE_REAL;
349 ds->data.real = c;
350
351 return FALSE;
352 }
353
datasource_open_sndfile(Datasource * ds)354 static gboolean datasource_open_sndfile(Datasource *ds)
355 {
356 #if defined(HAVE_LIBSNDFILE)
357 SF_INFO i;
358 SNDFILE *s;
359 char *d;
360 int fd;
361 fd = xopen(ds->data.sndfile.filename,O_RDONLY,0);
362 if (fd == -1) return TRUE;
363 i.format = 0;
364 s = sf_open_fd(fd,SFM_READ,&i,TRUE);
365 if (s == NULL) {
366 d = g_strdup_printf(_("Couldn't open %s"),
367 ds->data.sndfile.filename);
368 user_error(d);
369 g_free(d);
370 close(fd);
371 return TRUE;
372 }
373
374 ds->data.sndfile.handle = s;
375 ds->data.sndfile.pos = 0;
376
377 return FALSE;
378 #else
379 g_assert_not_reached();
380 return TRUE;
381 #endif
382 }
383
datasource_close_sndfile(Datasource * ds)384 static void datasource_close_sndfile(Datasource *ds)
385 {
386 #if defined(HAVE_LIBSNDFILE)
387 sf_close(ds->data.sndfile.handle);
388 #else
389 g_assert_not_reached();
390 #endif
391 }
392
datasource_open(Datasource * ds)393 gboolean datasource_open(Datasource *ds)
394 {
395 if (ds->opencount == 0)
396 switch (ds->type) {
397 case DATASOURCE_VIRTUAL:
398 case DATASOURCE_TEMPFILE:
399 ds->data.virtual.handle = e_fopen(ds->data.virtual.filename,
400 EFILE_READ);
401 if (ds->data.virtual.handle == NULL) return TRUE;
402 ds->data.virtual.pos = 0;
403 break;
404 case DATASOURCE_SNDFILE:
405 case DATASOURCE_SNDFILE_TEMPORARY:
406 if (datasource_open_sndfile(ds)) return TRUE;
407 break;
408 case DATASOURCE_REF:
409 case DATASOURCE_CLONE:
410 case DATASOURCE_BYTESWAP:
411 case DATASOURCE_CONVERT:
412 if (datasource_open(ds->data.clone)) return TRUE;
413 break;
414 case DATASOURCE_CHANMAP:
415 if (datasource_open(ds->data.chanmap.clone)) return TRUE;
416 break;
417 }
418 ds->opencount ++;
419 return FALSE;
420 }
421
clear_temparea(struct temparea * ta)422 static void clear_temparea(struct temparea *ta)
423 {
424 if (ta->ptr != NULL) {
425 g_free(ta->ptr);
426 ta->ptr = NULL;
427 ta->size = 0;
428 }
429 }
430
datasource_close(Datasource * ds)431 void datasource_close(Datasource *ds)
432 {
433 g_assert(ds->opencount != 0);
434 ds->opencount --;
435 if (ds->opencount > 0) return;
436
437 clear_temparea(&ds->read_temparea);
438 clear_temparea(&ds->readfp_temparea);
439
440 switch (ds->type) {
441 case DATASOURCE_VIRTUAL:
442 case DATASOURCE_TEMPFILE:
443 e_fclose(ds->data.virtual.handle);
444 break;
445 case DATASOURCE_SNDFILE:
446 case DATASOURCE_SNDFILE_TEMPORARY:
447 datasource_close_sndfile(ds);
448 break;
449 case DATASOURCE_REF:
450 case DATASOURCE_CLONE:
451 case DATASOURCE_BYTESWAP:
452 case DATASOURCE_CONVERT:
453 datasource_close(ds->data.clone);
454 break;
455 case DATASOURCE_CHANMAP:
456 datasource_close(ds->data.chanmap.clone);
457 break;
458 }
459 }
460
datasource_clone_read_array(Datasource * source,off_t sampleno,guint size,gpointer buffer,int dither_mode,off_t * clipcount)461 static guint datasource_clone_read_array(Datasource *source, off_t sampleno,
462 guint size, gpointer buffer,
463 int dither_mode, off_t *clipcount)
464 {
465 /* This is not optimized but it's only used in rare cases so the important
466 * thing is that it works.*/
467 off_t orig_offset;
468 off_t orig_sampleno;
469 off_t orig_size;
470 off_t orig_adjust;
471 guint x;
472 gchar *p;
473 /* Offset to be sent to the original chunk */
474 orig_offset = sampleno * source->format.samplebytes;
475 /* orig_offset converted to sample number */
476 orig_sampleno = orig_offset / source->data.clone->format.samplebytes;
477 /* How bany bytes too early will we read? */
478 orig_adjust = orig_offset % source->data.clone->format.samplebytes;
479 /* How much data should we read (should be able to fill buffer) */
480 orig_size = size + orig_adjust + source->data.clone->format.samplebytes - 1;
481 p = datasource_get_temparea(&(source->read_temparea),orig_size);
482 x = datasource_read_array(source->data.clone, orig_sampleno, orig_size, p,
483 dither_mode,clipcount);
484 if (x != 0) {
485 g_assert(x-orig_adjust >= size);
486 memcpy(buffer, p+orig_adjust, size);
487 x = size;
488 }
489 return x;
490 }
491
492 #if defined(HAVE_LIBSNDFILE)
sndfile_read_error(sf_count_t x,Datasource * source)493 static void sndfile_read_error(sf_count_t x, Datasource *source)
494 {
495 gchar c[256],*d;
496 if (x<0) sf_error_str(source->data.sndfile.handle,c,sizeof(c));
497 else strcpy(c,_("Unexpected end of file"));
498 d = g_strdup_printf(_("Error reading %s: %s"),
499 source->data.sndfile.filename, c);
500 user_error(d);
501 g_free(d);
502 }
503 #endif
504
datasource_sndfile_read_array(Datasource * source,off_t sampleno,guint size,gpointer buffer)505 static guint datasource_sndfile_read_array(Datasource *source,
506 off_t sampleno, guint size,
507 gpointer buffer)
508 {
509 #if defined(HAVE_LIBSNDFILE)
510 gchar c[256],*d;
511 sf_count_t samples,x;
512 if (source->data.sndfile.pos != sampleno) {
513 if (sf_seek(source->data.sndfile.handle,sampleno,SEEK_SET) == -1) {
514 sf_error_str(source->data.sndfile.handle,c,sizeof(c));
515 d = g_strdup_printf(_("Error seeking in %s: %s"),
516 source->data.sndfile.filename, c);
517 user_error(d);
518 g_free(d);
519 return 0;
520 }
521 source->data.sndfile.pos = sampleno;
522 }
523 samples = size / source->format.samplebytes;
524 if (source->format.type == DATAFORMAT_FLOAT) {
525 x = sf_readf_sample_t(source->data.sndfile.handle,buffer,samples);
526 } else if (source->data.sndfile.raw_readable) {
527 /* Read raw */
528 x = sf_read_raw(source->data.sndfile.handle,buffer,size);
529 x /= source->format.samplebytes;
530 } else if (source->format.samplesize==2 && source->format.sign) {
531 /* Read as short */
532 x = sf_readf_short(source->data.sndfile.handle,buffer,samples);
533 } else if (source->format.samplesize==4 && source->format.sign &&
534 source->format.packing < 2) {
535 /* Read as int */
536 /* TODO: Handle archs with sizeof(int)>4 */
537 x = sf_readf_int(source->data.sndfile.handle,buffer,samples);
538 } else {
539 g_assert_not_reached();
540 return 0;
541 }
542 if (x>0) source->data.sndfile.pos += x;
543 if (x<samples) {
544 sndfile_read_error(x,source);
545 return 0;
546 }
547 return x * source->format.samplebytes;
548 #else
549 g_assert_not_reached();
550 return 0;
551 #endif
552 }
553
remap_main(void * source_buf,int item_size,int source_channels,void * dest_buf,int dest_channels,int * map,int items)554 static void remap_main(void *source_buf, int item_size, int source_channels,
555 void *dest_buf, int dest_channels, int *map, int items)
556 {
557 int i,j;
558 char *sp,*dp;
559 int dstep,sstep;
560 /* Simplest possible implementation - room for optimization */
561 dstep = item_size*dest_channels;
562 sstep = item_size*source_channels;
563 for (i=0; i<dest_channels; i++) {
564 dp = ((char *)dest_buf) + i*item_size;
565 if (map[i] < 0 || map[i] >= source_channels) {
566 for (j=0; j<items; j++,dp+=dstep)
567 memset(dp,0,item_size);
568 } else {
569 sp = ((char *)source_buf) + map[i]*item_size;
570 for (j=0; j<items; j++,sp+=sstep,dp+=dstep)
571 memcpy(dp,sp,item_size);
572 }
573 }
574 }
575
datasource_read_array_main(Datasource * source,off_t sampleno,guint size,gpointer buffer,int dither_mode,off_t * clipcount)576 static guint datasource_read_array_main(Datasource *source,
577 off_t sampleno, guint size,
578 gpointer buffer, int dither_mode,
579 off_t *clipcount)
580 {
581 off_t x;
582 guint u,s;
583 sample_t *c;
584 switch (source->type) {
585 case DATASOURCE_REAL:
586 memcpy(buffer,source->data.real+sampleno*source->format.samplebytes,
587 size);
588 return size;
589 case DATASOURCE_VIRTUAL:
590 case DATASOURCE_TEMPFILE:
591 /* Calculate offset in file */
592 x = source->data.virtual.offset +
593 sampleno*source->format.samplebytes;
594 if (x != source->data.virtual.pos &&
595 e_fseek(source->data.virtual.handle, x, SEEK_SET))
596 return 0;
597 source->data.virtual.pos = x;
598 if (e_fread(buffer,size,source->data.virtual.handle)) return 0;
599 source->data.virtual.pos += size;
600 return size;
601 case DATASOURCE_SILENCE:
602 memset(buffer,0,size);
603 return size;
604 case DATASOURCE_SNDFILE:
605 case DATASOURCE_SNDFILE_TEMPORARY:
606 return datasource_sndfile_read_array(source,sampleno,size,buffer);
607 case DATASOURCE_REF:
608 return datasource_read_array_main(source->data.clone,sampleno,size,
609 buffer,dither_mode,clipcount);
610 case DATASOURCE_CLONE:
611 return datasource_clone_read_array(source,sampleno,size,buffer,
612 dither_mode,clipcount);
613 case DATASOURCE_BYTESWAP:
614 u = datasource_read_array_main(source->data.clone,sampleno,size,
615 buffer,dither_mode,clipcount);
616 if (u>0) byteswap(buffer,source->format.samplesize,u);
617 return u;
618 case DATASOURCE_CONVERT:
619 u = size / source->format.samplebytes;
620 if (dataformat_samples_equal(&(source->format),&dataformat_sample_t))
621 return datasource_read_array_fp(source->data.clone,sampleno,u,
622 buffer,dither_mode,clipcount) *
623 source->format.samplebytes ;
624 c = (sample_t *)datasource_get_temparea(&(source->read_temparea),
625 u*sizeof(sample_t)*
626 source->format.channels);
627 u = datasource_read_array_fp(source->data.clone, sampleno, u,
628 (gpointer)c,dither_mode,clipcount);
629 if (u > 0) {
630 apply_convert_factor(&(source->data.clone->format), &(source->format),
631 (sample_t *)c, u*source->format.channels);
632 convert_array(c,&dataformat_sample_t,buffer,&(source->format),
633 u*source->format.channels,dither_mode,clipcount);
634 }
635 return u * source->format.samplebytes;
636 case DATASOURCE_CHANMAP:
637 u = (size / source->format.samplebytes) *
638 source->data.chanmap.clone->format.samplebytes;
639 c = (sample_t *)datasource_get_temparea(&(source->read_temparea),u);
640 g_assert(c != buffer);
641 u = datasource_read_array_main(source->data.chanmap.clone, sampleno,
642 u, c, dither_mode,clipcount);
643 s = u / source->data.chanmap.clone->format.samplebytes;
644 if (s > 0)
645 remap_main(c, source->data.chanmap.clone->format.samplesize,
646 source->data.chanmap.clone->format.channels,
647 buffer, source->format.channels,
648 source->data.chanmap.map, s);
649 return s*source->format.samplebytes;
650 default:
651 g_assert_not_reached();
652 return 0;
653 }
654 }
655
datasource_read_array(Datasource * source,off_t sampleno,guint size,gpointer buffer,int dither_mode,off_t * clipcount)656 guint datasource_read_array(Datasource *source, off_t sampleno, guint size,
657 gpointer buffer, int dither_mode,
658 off_t *clipcount)
659 {
660 off_t o;
661 g_assert(source->opencount > 0);
662 /* Check sampleno */
663 g_assert(sampleno <= source->length);
664 /* Check size */
665 /* Round down to even samples */
666 size = size - size % source->format.samplebytes;
667 o = (source->length - sampleno) * (off_t)(source->format.samplebytes);
668 if (size > o) size = (guint)o; /* Round down to available data */
669 if (size == 0) return 0;
670 /* Do it */
671 return datasource_read_array_main(source,sampleno,size,buffer,
672 dither_mode,clipcount);
673 }
674
datasource_read(Datasource * source,off_t sampleno,gpointer buffer,int dither_mode)675 gboolean datasource_read(Datasource *source, off_t sampleno, gpointer buffer,
676 int dither_mode)
677 {
678 return (datasource_read_array(source,sampleno,source->format.samplebytes,
679 buffer,dither_mode,NULL)
680 != source->format.samplebytes);
681 }
682
683
datasource_read_array_fp(Datasource * source,off_t sampleno,guint samples,sample_t * buffer,int dither_mode,off_t * clipcount)684 guint datasource_read_array_fp(Datasource *source, off_t sampleno,
685 guint samples, sample_t *buffer,
686 int dither_mode, off_t *clipcount)
687 {
688 gchar *p;
689 guint x,s;
690
691 g_assert(source->opencount > 0);
692
693 g_assert(sampleno <= source->length);
694 if (samples > source->length-sampleno)
695 samples = (guint)(source->length-sampleno);
696 if (samples == 0) return 0;
697
698
699 switch (source->type) {
700 case DATASOURCE_SILENCE:
701 memset(buffer,0,samples*source->format.channels*sizeof(sample_t));
702 return samples;
703 case DATASOURCE_REF:
704 case DATASOURCE_CONVERT:
705 g_assert(source->type == DATASOURCE_CONVERT ||
706 dataformat_equal(&(source->format), &(source->data.clone->format)));
707 x = datasource_read_array_fp(source->data.clone,sampleno,
708 samples,buffer,dither_mode,
709 clipcount);
710 apply_convert_factor(&(source->data.clone->format), &(source->format),
711 buffer, x*source->format.channels);
712 return x;
713 default:
714 if (dataformat_samples_equal(&(source->format),&dataformat_sample_t))
715 return datasource_read_array(source,sampleno,
716 samples*source->format.samplebytes,
717 buffer, dither_mode, clipcount)
718 / source->format.samplebytes;
719
720 s = samples * source->format.samplebytes;
721 p = datasource_get_temparea(&(source->readfp_temparea),s);
722 x = datasource_read_array(source,sampleno,s,p,dither_mode,clipcount);
723 g_assert(x==s || x==0);
724 if (x==s) {
725 convert_array(p,&(source->format),buffer,&dataformat_sample_t,
726 samples*source->format.channels,dither_mode,clipcount);
727 return samples;
728 }
729 return 0;
730 }
731 }
732
datasource_read_fp(Datasource * ds,off_t sampleno,sample_t * buffer,int dither_mode)733 gboolean datasource_read_fp(Datasource *ds, off_t sampleno, sample_t *buffer,
734 int dither_mode)
735 {
736 return (datasource_read_array_fp(ds,sampleno,1,buffer,dither_mode,NULL)!=1);
737 }
738
datasource_uses_file(Datasource * ds,gchar * filename)739 static gboolean datasource_uses_file(Datasource *ds, gchar *filename)
740 {
741 return ((ds->type==DATASOURCE_VIRTUAL &&
742 is_same_file(ds->data.virtual.filename,filename)) ||
743 ((ds->type==DATASOURCE_SNDFILE &&
744 is_same_file(ds->data.sndfile.filename,filename))));
745 }
746
datasource_backup_unlink(gchar * filename)747 gboolean datasource_backup_unlink(gchar *filename)
748 {
749 GList *l,*q=NULL;
750 Datasource *ds;
751 Datasource *backup=NULL;
752 gchar *lastname=filename,*t;
753 guint dirnum=0;
754 gint i;
755
756 /* Find out which Datasources actually use the file. */
757 for (l=datasource_list; l!=NULL; l=l->next) {
758 ds = (Datasource *)l->data;
759 if (datasource_uses_file(ds,filename))
760 q = g_list_append(q,ds);
761 }
762
763 /* Now iterate through those files. */
764 for (l=q; l!=NULL; l=l->next) {
765 ds = (Datasource *)l->data;
766 if (!datasource_uses_file(ds,filename)) continue;
767
768 /* For the first affected datasource (backup == NULL), the file is
769 * moved to a temporary directory and the filename in the datasource
770 * is updated. For each remaining sources, the file is copied.
771 *
772 * This is not optimal, but the case with more than one reference to
773 * a file can only happen when the user has opened the same file
774 * multiple times.
775 */
776 if (backup == NULL) {
777 /* This loop first tries to move the file to each temporary
778 * directory. If all directories fail, we copy the file. */
779 dirnum = 0;
780 while (1) {
781 t = get_temp_filename(dirnum);
782 if (t == NULL) {
783 dirnum = 0;
784 t = get_temp_filename(0);
785 i = xrename(lastname,t,TRUE);
786 break;
787 }
788 i = xrename(lastname,t,FALSE);
789 if (i!=2) break;
790 dirnum ++;
791 g_free(t);
792 }
793 if (i) {
794 g_free(t);
795 return TRUE;
796 }
797 } else {
798 /* Special case: the same file has been opened many times. */
799 t = get_temp_filename(0);
800 if (errdlg_copyfile(lastname,t)) {
801 g_free(t);
802 return TRUE;
803 }
804 }
805
806 switch (ds->type) {
807 case DATASOURCE_VIRTUAL:
808 g_free(ds->data.virtual.filename);
809 ds->data.virtual.filename = t;
810 ds->type = DATASOURCE_TEMPFILE;
811 break;
812 case DATASOURCE_SNDFILE:
813 g_free(ds->data.sndfile.filename);
814 ds->data.sndfile.filename = t;
815 ds->type = DATASOURCE_SNDFILE_TEMPORARY;
816 break;
817 default:
818 g_assert_not_reached();
819 break;
820 }
821 backup = ds;
822 lastname = t;
823 }
824
825 g_list_free(q);
826 return xunlink(filename);
827 }
828
datasource_convert(Datasource * source,Dataformat * new_format)829 Datasource *datasource_convert(Datasource *source, Dataformat *new_format)
830 {
831 Datasource *ds;
832 if (source == NULL) return NULL;
833 g_assert(!dataformat_equal(new_format,&(source->format)));
834 g_assert(new_format->channels == source->format.channels &&
835 new_format->samplerate == source->format.samplerate);
836
837 if (source->format.type == DATAFORMAT_PCM &&
838 new_format->type == DATAFORMAT_PCM &&
839 source->format.samplesize == new_format->samplesize &&
840 source->format.sign == new_format->sign &&
841 source->format.packing == new_format->packing) {
842 g_assert(XOR(source->format.bigendian,new_format->bigendian));
843 return datasource_byteswap(source);
844 }
845 if (source->format.type == DATAFORMAT_FLOAT &&
846 new_format->type == DATAFORMAT_FLOAT &&
847 source->format.samplesize == new_format->samplesize) {
848 g_assert(XOR(source->format.bigendian,new_format->bigendian));
849 return datasource_byteswap(source);
850 }
851
852 ds = gtk_type_new(datasource_get_type());
853 ds->type = DATASOURCE_CONVERT;
854 memcpy(&(ds->format),new_format,sizeof(Dataformat));
855 ds->format.samplebytes = ds->format.samplesize * ds->format.channels;
856 ds->length = source->length;
857 ds->bytes = ds->length * new_format->samplebytes;
858 ds->data.clone = source;
859 gtk_object_ref(GTK_OBJECT(source));
860 gtk_object_sink(GTK_OBJECT(source));
861 return ds;
862 }
863
864 #define NS 4096
datasource_clip_check_fp(Datasource * ds,StatusBar * bar)865 static gint datasource_clip_check_fp(Datasource *ds, StatusBar *bar)
866 {
867 sample_t *buf;
868 off_t o;
869 guint i;
870 off_t clipcount = 0;
871 g_assert(ds->format.type == DATAFORMAT_FLOAT);
872 if (datasource_open(ds)) return -1;
873 buf = g_malloc(sizeof(sample_t) * ds->format.samplebytes);
874 for (o=0; o<ds->length; ) {
875 i = datasource_read_array_fp(ds,o,NS,buf,DITHER_UNSPEC,&clipcount);
876 o += i;
877 if (i == 0) {
878 g_free(buf);
879 datasource_close(ds);
880 return -1;
881 }
882 if (clipcount > 0) {
883 g_free(buf);
884 datasource_close(ds);
885 return 1;
886 }
887 if (status_bar_progress(bar,NS)) {
888 g_free(buf);
889 datasource_close(ds);
890 return -2;
891 }
892 }
893 datasource_close(ds);
894 g_free(buf);
895 return 0;
896 }
897 #undef NS
898
datasource_clip_check(Datasource * ds,StatusBar * bar)899 gint datasource_clip_check(Datasource *ds, StatusBar *bar)
900 {
901 gint i;
902 switch (ds->type) {
903 case DATASOURCE_SNDFILE:
904 case DATASOURCE_SNDFILE_TEMPORARY:
905 /* Libsndfile is always used with normalization turned on */
906 return 0;
907 case DATASOURCE_SILENCE:
908 /* Trivial */
909 return 0;
910 case DATASOURCE_REAL:
911 case DATASOURCE_VIRTUAL:
912 case DATASOURCE_TEMPFILE:
913 /* If we contain PCM data, clipping can't occur */
914 if (ds->format.type == DATAFORMAT_PCM) return 0;
915 return datasource_clip_check_fp(ds,bar);
916 case DATASOURCE_BYTESWAP:
917 case DATASOURCE_CLONE:
918 /* This could cause clipping in special cases.
919 * That clipping can not be solved by normalizing the data. */
920 i = datasource_clip_check(ds->data.clone,bar);
921 if (i < 0) return i;
922 if (i > 0) return 2;
923 if (ds->format.type == DATAFORMAT_FLOAT)
924 return datasource_clip_check_fp(ds,bar);
925 else
926 return 0;
927 case DATASOURCE_REF:
928 case DATASOURCE_CONVERT:
929 return datasource_clip_check(ds->data.clone,bar);
930 case DATASOURCE_CHANMAP:
931 return datasource_clip_check(ds->data.chanmap.clone,bar);
932 default:
933 break;
934 }
935 g_assert_not_reached();
936 return 0;
937 }
938