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