1 /*
2  * Copyright (C) 2002 2003 2004 2005 2006 2007 2008 2009 2011, Magnus Hjorth
3  * Copyright (C) 2012, Magnus Hjorth
4  *
5  * This file is part of mhWaveEdit.
6  *
7  * mhWaveEdit is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * mhWaveEdit is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with mhWaveEdit; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 
23 #include <config.h>
24 
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <math.h>
30 #include <sys/stat.h>
31 #include <gtk/gtk.h>
32 #include "gtkfiles.h"
33 #include "um.h"
34 #include "chunk.h"
35 #include "inifile.h"
36 #include "main.h"
37 #include "ringbuf.h"
38 #include "rawdialog.h"
39 #include "tempfile.h"
40 #include "rateconv.h"
41 #include "gettext.h"
42 
43 
44 gboolean chunk_filter_use_floating_tempfiles;
45 
46 static GtkObjectClass *parent_class;
47 
48 static GList *chunks = NULL;
49 
chunk_alive_count(void)50 guint chunk_alive_count(void)
51 {
52      return g_list_length ( chunks );
53 }
54 
chunk_destroy(GtkObject * object)55 static void chunk_destroy(GtkObject *object)
56 {
57      Chunk *c;
58      GList *l;
59      DataPart *dp;
60      /* printf("chunk_destroy: %p\n",object); */
61      c=CHUNK(object);
62      g_assert(c->opencount == 0);
63      if (c->parts) {
64 	  for (l=c->parts; l!=NULL; l=l->next) {
65 	       dp = (DataPart *)l->data;
66 	       gtk_object_unref(GTK_OBJECT(dp->ds));
67 	       g_free(dp);
68 	  }
69 	  g_list_free(c->parts);
70      }
71      c->parts = NULL;
72      parent_class->destroy(object);
73      chunks = g_list_remove ( chunks, object );
74 }
75 
chunk_class_init(GtkObjectClass * klass)76 static void chunk_class_init(GtkObjectClass *klass)
77 {
78      parent_class = gtk_type_class(gtk_object_get_type());
79      klass->destroy = chunk_destroy;
80 }
81 
chunk_init(Chunk * object)82 static void chunk_init(Chunk *object)
83 {
84      /* printf("chunk_init: %p\n",object); */
85      object->format.type = DATAFORMAT_PCM;
86      object->format.samplerate=44100;
87      object->format.samplesize=2;
88      object->format.packing=0;
89      object->format.channels=2;
90      object->format.sign=1;
91      object->format.bigendian = IS_BIGENDIAN;
92      object->format.samplebytes=4;
93      object->length=0;
94      object->size=0;
95      object->parts = 0;
96      chunks = g_list_append( chunks, object );
97 }
98 
chunk_get_type(void)99 GtkType chunk_get_type(void)
100 {
101      static GtkType id=0;
102      if (!id) {
103 	  GtkTypeInfo info = {
104 	       "Chunk",
105 	       sizeof(Chunk),
106 	       sizeof(ChunkClass),
107 	       (GtkClassInitFunc) chunk_class_init,
108 	       (GtkObjectInitFunc) chunk_init
109 	  };
110 	  id=gtk_type_unique(gtk_object_get_type(),&info);
111      }
112      return id;
113 }
114 
chunk_new(void)115 static Chunk *chunk_new(void)
116 {
117      return gtk_type_new(chunk_get_type());
118 }
119 
chunk_new_silent(Dataformat * format,gfloat seconds)120 Chunk *chunk_new_silent(Dataformat *format, gfloat seconds)
121 {
122      return chunk_new_from_datasource(
123 	  datasource_new_silent(format, seconds * format->samplerate));
124 }
125 
chunk_calc_length(Chunk * c)126 static void chunk_calc_length(Chunk *c)
127 {
128      GList *l;
129      DataPart *dp;
130      off_t len=0;
131      for(l=c->parts; l!=NULL; l=l->next) {
132 	  dp = (DataPart *)l->data;
133 	  len += dp->length;
134      }
135      c->length = len;
136      c->size = len*c->format.samplebytes;
137 }
138 
139 static rateconv *conv;
140 static const gchar *conv_driver;
141 static guint32 conv_outrate;
142 static int conv_dither_mode;
143 
chunk_convert_samplerate_proc(void * in,guint sample_size,chunk_writeout_func out_func,WriteoutID id,Dataformat * informat,Dataformat * outformat)144 static gboolean chunk_convert_samplerate_proc(void *in, guint sample_size,
145 					      chunk_writeout_func out_func,
146 					      WriteoutID id,
147 					      Dataformat *informat,
148 					      Dataformat *outformat)
149 {
150      guint i=0;
151      gchar *p = (gchar *)in;
152      gint j,k;
153      gchar buf[4096];
154      if (conv == NULL)
155 	  conv = rateconv_new(FALSE,conv_driver,informat,
156 			      conv_outrate,conv_dither_mode,FALSE);
157      if (conv == NULL) return TRUE;
158      if (sample_size == 0) rateconv_write(conv,NULL,0);
159      while (1) {
160 	  if (sample_size > 0) {
161 	       /*puts("chunk_convert_samplerate_proc: Calling rateconv_write.."); */
162 	       j = rateconv_write(conv,p+i,sample_size-i);
163 	       /* printf("rateconv_write: tried=%d, got=%d\n",(int)sample_size-i,
164 		  j); */
165 	       if (j == -1) return TRUE;
166 	       i += j;
167 	       if (i == sample_size) return FALSE;
168 	  }
169 	  /* puts("chunk_convert_samplerate_proc: calling rateconv_read..."); */
170 	  k = rateconv_read(conv,buf,sizeof(buf));
171 	  /* printf("rateconv_read: tried=%d, got=%d\n",(int)sizeof(buf),k); */
172 	  if (k == -1) return TRUE;
173 	  if (k == 0 && sample_size == 0) return FALSE;
174 	  if (k>0 && out_func(id,buf,k)) return TRUE;
175      }
176 }
177 
178 
chunk_convert_samplerate(Chunk * chunk,gint samplerate,const gchar * rateconv_driver,int dither_mode,StatusBar * bar)179 Chunk *chunk_convert_samplerate(Chunk *chunk, gint samplerate,
180 				const gchar *rateconv_driver,
181 				int dither_mode, StatusBar *bar)
182 {
183      Chunk *c;
184      Dataformat fmt;
185      /*puts("chunk_convert_samplerate: calling rateconv_new");*/
186      conv = NULL;
187      conv_driver = rateconv_driver;
188      conv_outrate = samplerate;
189      conv_dither_mode = dither_mode;
190      memcpy(&fmt,&(chunk->format),sizeof(Dataformat));
191      fmt.samplerate = samplerate;
192 
193      /* puts("chunk_convert_samplerate: calling chunk_filter"); */
194      c = chunk_filter_tofmt(chunk,chunk_convert_samplerate_proc,
195 			    chunk_convert_samplerate_proc,
196 			    CHUNK_FILTER_MANY,
197 			    rateconv_prefers_float(rateconv_driver),&fmt,
198 			    dither_mode,
199 			    bar, _("Converting samplerate"));
200      /* puts("chunk_convert_samplerate: calling rateconv_destroy"); */
201      if (conv != NULL) {
202 	  rateconv_destroy(conv);
203 	  conv = NULL;
204      }
205      return c;
206 }
207 
chunk_convert_speed(Chunk * chunk,gfloat speed_factor,int dither_mode,StatusBar * bar)208 Chunk *chunk_convert_speed(Chunk *chunk, gfloat speed_factor,
209 			   int dither_mode, StatusBar *bar)
210 {
211      guint32 target_samplerate;
212      Chunk *c;
213      int i;
214      target_samplerate = (guint32)(((float)chunk->format.samplerate) /
215 				   speed_factor);
216      conv_outrate = target_samplerate;
217 
218      i = inifile_get_guint32("speedConv",0);
219      if (i >= rateconv_driver_count(FALSE)) i=0;
220      conv_driver = rateconv_driver_id(FALSE,i);
221 
222      conv = NULL;
223      c = chunk_filter_tofmt(chunk,chunk_convert_samplerate_proc,
224 			    chunk_convert_samplerate_proc,CHUNK_FILTER_MANY,
225 			    FALSE,&(chunk->format),dither_mode,
226 			    bar,_("Adjusting speed"));
227      if (conv != NULL) rateconv_destroy(conv);
228      return c;
229 }
230 
chunk_convert_sampletype(Chunk * chunk,Dataformat * newtype)231 Chunk *chunk_convert_sampletype(Chunk *chunk, Dataformat *newtype)
232 {
233      GList *l;
234      Datasource *ds;
235      Chunk *r=NULL,*c,*c2;
236      DataPart *dp;
237      Dataformat newformat;
238 
239      g_assert(!dataformat_samples_equal(&(chunk->format),newtype));
240      memcpy(&newformat,newtype,sizeof(Dataformat));
241      newformat.samplerate = chunk->format.samplerate;
242      newformat.channels = chunk->format.channels;
243 
244      for (l=chunk->parts; l!=NULL; l=l->next) {
245 	  dp = (DataPart *)(l->data);
246 	  ds = datasource_convert(dp->ds,&newformat);
247 	  g_assert(ds != NULL);
248 	  c2 = chunk_new_from_datasource(ds);
249 	  c = chunk_get_part(c2,dp->position,dp->length);
250 	  gtk_object_sink(GTK_OBJECT(c2));
251 	  if (r != NULL) {
252 	       c2 = r;
253 	       r = chunk_append(c2,c);
254 	       gtk_object_sink(GTK_OBJECT(c2));
255 	       gtk_object_sink(GTK_OBJECT(c));
256 	  } else
257 	       r = c;
258      }
259 
260      return r;
261 }
262 
chunk_ds_remap(Chunk * chunk,int new_channels,int * map)263 static Chunk *chunk_ds_remap(Chunk *chunk, int new_channels, int *map)
264 {
265      GList *l;
266      DataPart *dp;
267      Datasource *new_ds;
268      Chunk *new_chunk,*new_chunk_part;
269      Chunk *res = NULL, *c;
270      for (l=chunk->parts; l!=NULL; l=l->next) {
271 	  dp = (DataPart *)l->data;
272 	  new_ds = datasource_channel_map(dp->ds,new_channels,map);
273 	  new_chunk = chunk_new_from_datasource(new_ds);
274 	  new_chunk_part = chunk_get_part(new_chunk,dp->position,dp->length);
275 	  gtk_object_sink(GTK_OBJECT(new_chunk));
276 	  if (res == NULL) {
277 	       res = new_chunk_part;
278 	  } else {
279 	       c = chunk_append(res,new_chunk_part);
280 	       gtk_object_sink(GTK_OBJECT(res));
281 	       gtk_object_sink(GTK_OBJECT(new_chunk_part));
282 	       res = c;
283 	  }
284      }
285      g_free(map);
286      return res;
287 }
288 
chunk_remove_channel(Chunk * chunk,gint channel,StatusBar * bar)289 Chunk *chunk_remove_channel(Chunk *chunk, gint channel, StatusBar *bar)
290 {
291      int *map,i,new_chans;
292 
293      new_chans = chunk->format.channels - 1;
294      map = g_malloc(new_chans * sizeof(int));
295      for (i=0; i<new_chans; i++) {
296 	  if (i >= channel) map[i]=i+1;
297 	  else map[i]=i;
298      }
299      return chunk_ds_remap(chunk, new_chans, map);
300 }
301 
chunk_dump(Chunk * chunk,EFILE * file,gboolean bigendian,int dither_mode,StatusBar * bar)302 gboolean chunk_dump(Chunk *chunk, EFILE *file, gboolean bigendian,
303 		    int dither_mode, StatusBar *bar)
304 {
305      GList *l;
306      DataPart *dp;
307      off_t clipcount = 0;
308      l = chunk->parts;
309      while (l) {
310 	  dp = (DataPart *)l->data;
311 	  if (datasource_dump(dp->ds,dp->position,dp->length,file,
312 			      dither_mode,bar,&clipcount))
313 	       return TRUE;
314 	  l = l->next;
315      }
316      return clipwarn(clipcount,TRUE);
317 }
318 
has_fake_pcm(Chunk * c)319 static gboolean has_fake_pcm(Chunk *c)
320 {
321      GList *l;
322      DataPart *part;
323      for (l=c->parts; l!=NULL; l=l->next) {
324 	  part = (DataPart *)(l->data);
325 	  if (part->ds->type == DATASOURCE_CONVERT) return TRUE;
326      }
327      return FALSE;
328 }
329 
330 /* Allm�n funktion f�r stegvis bearbetning av en Chunk.
331  * Funktionen l�ser steg f�r steg av chunken och anropar proc.
332  * Efter allt data skickats in kommer eof_proc (om != NULL) att anropas med
333  * samplesize=0.
334  */
335 
chunk_filter(Chunk * chunk,chunk_filter_proc proc,chunk_filter_proc eof_proc,gint amount,gboolean must_convert,int dither_mode,StatusBar * bar,gchar * title)336 Chunk *chunk_filter(Chunk *chunk, chunk_filter_proc proc,
337 		    chunk_filter_proc eof_proc, gint amount,
338 		    gboolean must_convert, int dither_mode,
339 		    StatusBar *bar, gchar *title)
340 {
341      return chunk_filter_tofmt(chunk,(chunk_filter_tofmt_proc)proc,
342 			       (chunk_filter_tofmt_proc)eof_proc,amount,
343 			       must_convert,&(chunk->format),dither_mode,
344 			       bar,title);
345 }
346 
347 struct convert_back {
348      TempFile tmp;
349      Dataformat *tofmt;
350      gchar buf[16384];
351      int dither_mode;
352      off_t *clipcount;
353 };
354 
convert_back_write(WriteoutID id,gpointer data,guint length)355 static gboolean convert_back_write(WriteoutID id, gpointer data, guint length)
356 {
357      struct convert_back *cbp = (struct convert_back *)id;
358      guint i;
359      i = length / sizeof(sample_t);
360      convert_array(data,&dataformat_sample_t,cbp->buf,cbp->tofmt,i,
361 		   cbp->dither_mode, cbp->clipcount);
362      return tempfile_write(cbp->tmp,cbp->buf,i*cbp->tofmt->samplesize);
363 }
364 
chunk_filter_tofmt(Chunk * chunk,chunk_filter_tofmt_proc proc,chunk_filter_tofmt_proc eof_proc,gint amount,gboolean must_convert,Dataformat * tofmt,int dither_mode,StatusBar * bar,gchar * title)365 Chunk *chunk_filter_tofmt(Chunk *chunk, chunk_filter_tofmt_proc proc,
366 			  chunk_filter_tofmt_proc eof_proc,
367 			  gint amount, gboolean must_convert,
368 			  Dataformat *tofmt, int dither_mode,
369 			  StatusBar *bar, gchar *title)
370 {
371      /* This code has to keep track of five different sample formats:
372       *   1) The Chunk's native format (chunk->format)
373       *   2) The processing function's input format (informat)
374       *   3) The processing function's output format (outformat)
375       *   4) The output temporary file's format (outformat or tofmt)
376       *   5) The output Chunk's native format (tofmt)
377       *
378       * These modes are possible:
379       *
380       *   1) Native format all the way
381       *      if must_convert == FALSE and no FP data in chunk
382       *      convert = FALSE, convert_back = FALSE,
383       *      formats (1)=(2)=(3), (4)=(5)
384       *
385       *   2) FP processing with FP tempfiles
386       *      if must_convert == TRUE || FP data in chunk
387       *      convert = TRUE, convert_back = FALSE
388       *      formats (2)=(3)=floating point version of (1)
389       *      format (4)=floating point version of (5)
390       *
391       *   3) FP processing with native tempfiles
392       *      (this mode is only used if the "use FP tempfiles option" is
393       *      disabled, could cause quality loss)
394       *      if (must_convert == TRUE || FP data in chunk) &&
395       *          !chunk_filter_use_floating_tempfiles,
396       *      convert = TRUE, convert_back = TRUE
397       *      formats (2)=(3)=floating point version of (1),  (4)=(5)
398       */
399 
400 
401      guint proc_size,single_size,full_size;
402      gchar buf[8192];
403      off_t samplepos=0, samplesleft=chunk->length;
404      guint u, x;
405      gboolean convert, convert_back;
406      Dataformat informat,outformat;
407      ChunkHandle *ch;
408      TempFile tmp;
409      Chunk *ds,*r;
410      struct convert_back *cbp = NULL;
411      off_t clipcount = 0;
412 
413      /* Force processing in floating-point if any of the Datasources has
414       * faked pcm data */
415      convert = must_convert || has_fake_pcm(chunk);
416      convert_back = convert && !chunk_filter_use_floating_tempfiles;
417 
418      if (convert) {
419 	  memcpy(&informat,&dataformat_sample_t,sizeof(Dataformat));
420 	  memcpy(&outformat,&dataformat_sample_t,sizeof(Dataformat));
421 	  informat.channels = chunk->format.channels;
422 	  outformat.channels = tofmt->channels;
423 	  informat.samplebytes = informat.samplesize * informat.channels;
424 	  outformat.samplebytes = outformat.samplesize * outformat.channels;
425 	  informat.samplerate = chunk->format.samplerate;
426 	  outformat.samplerate = tofmt->samplerate;
427      } else {
428 	  memcpy(&informat,&(chunk->format),sizeof(Dataformat));
429 	  memcpy(&outformat,tofmt,sizeof(Dataformat));
430      }
431 
432      single_size = informat.samplesize;
433      full_size = informat.samplebytes;
434 
435      if (amount == CHUNK_FILTER_FULL) proc_size = full_size;
436      else if (amount == CHUNK_FILTER_ONE) proc_size = single_size;
437      else proc_size = 0; /* Set this later for CHUNK_FILTER_MANY */
438 
439      ch = chunk_open(chunk);
440      if (ch == NULL) return NULL;
441      tmp = tempfile_init(convert_back ? tofmt : &outformat,FALSE);
442      if (convert_back) {
443 	  cbp = g_malloc(sizeof(*cbp));
444 	  cbp->tmp = tmp;
445 	  cbp->tofmt = tofmt;
446 	  cbp->dither_mode = dither_mode;
447 	  cbp->clipcount = &clipcount;
448      }
449      status_bar_begin_progress(bar,samplesleft,title);
450 
451      while (samplesleft > 0) {
452 	  if (convert)
453 	       u = chunk_read_array_fp(ch,samplepos,
454 				       MIN(sizeof(buf)/full_size,samplesleft),
455 				       (sample_t *)buf,dither_mode,
456 				       &clipcount) *
457 		    full_size;
458 	  else
459 	       u = chunk_read_array(ch,samplepos,
460 				    MIN(sizeof(buf),samplesleft*full_size),buf,
461 				    dither_mode,&clipcount);
462 	  if (!u) {
463 	       chunk_close(ch);
464 	       tempfile_abort(tmp);
465 	       if (cbp != NULL) g_free(cbp);
466 	       status_bar_end_progress(bar);
467 	       return NULL;
468 	  }
469 	  if (amount == CHUNK_FILTER_MANY) proc_size = u;
470 	  for (x=0; x<u; x+=proc_size) {
471 	       if (proc(buf+x,proc_size,
472 			convert_back?convert_back_write:tempfile_write,
473 			convert_back?cbp:tmp, &informat,&outformat)) {
474 		    chunk_close(ch);
475 		    tempfile_abort(tmp);
476 		    if (cbp != NULL) g_free(cbp);
477 		    status_bar_end_progress(bar);
478 		    return NULL;
479 	       }
480 	  }
481 	  samplesleft -= u / full_size;
482 	  samplepos += u / full_size;
483 	  if (status_bar_progress(bar, u / full_size)) {
484 	       chunk_close(ch);
485 	       tempfile_abort(tmp);
486 	       if (cbp != NULL) g_free(cbp);
487 	       status_bar_end_progress(bar);
488 	       return NULL;
489 	  }
490      }
491      if (eof_proc!=NULL &&
492 	 eof_proc(NULL,0, convert_back?convert_back_write:tempfile_write,
493 		  convert_back?cbp:tmp, &informat,&outformat)) {
494 	  chunk_close(ch);
495 	  tempfile_abort(tmp);
496 	  if (cbp != NULL) g_free(cbp);
497 	  status_bar_end_progress(bar);
498 	  return NULL;
499      }
500      chunk_close(ch);
501      ds = tempfile_finished(tmp);
502      status_bar_end_progress(bar);
503      if (cbp != NULL) g_free(cbp);
504 
505      if (clipwarn(clipcount,TRUE)) {
506 	  gtk_object_sink(GTK_OBJECT(ds));
507 	  return NULL;
508      }
509 
510      /* Check if the datasources format is the same as the user expects. If
511       * not, convert. */
512      if (ds != NULL && convert && !convert_back &&
513 	 !dataformat_samples_equal(&(ds->format),tofmt)) {
514 
515 	  r = chunk_convert_sampletype(ds,tofmt);
516 	  gtk_object_sink(GTK_OBJECT(ds));
517 	  return r;
518      } else
519 	  return ds;
520 }
521 
522 /* Allm�n funktion f�r stegvis avl�sning av en Chunk. proc kommer att anropas
523  * en g�ng f�r varje sampling i chunken */
524 
chunk_parse(Chunk * chunk,chunk_parse_proc proc,gboolean allchannels,gboolean convert,int dither_mode,StatusBar * bar,gchar * title,off_t samplepos,gboolean reverse)525 gboolean chunk_parse(Chunk *chunk, chunk_parse_proc proc,
526 		     gboolean allchannels, gboolean convert, int dither_mode,
527 		     StatusBar *bar, gchar *title, off_t samplepos,
528 		     gboolean reverse)
529 {
530 
531      guint single_size,full_size,proc_size;
532      gchar buf[4096],*c=NULL,*d;
533      off_t samplesleft;
534      off_t readpos;
535      off_t readsamples;
536      guint u;
537      gint x;
538      ChunkHandle *ch;
539      off_t clipcount = 0;
540 
541      if(reverse) {
542           samplesleft = samplepos;
543      } else {
544           samplesleft = chunk->length - samplepos;
545      }
546 
547      if (convert) single_size = sizeof(sample_t);
548      else single_size = chunk->format.samplesize;
549 
550      full_size = single_size * chunk->format.channels;
551 
552      if (allchannels) proc_size = full_size;
553      else proc_size = single_size;
554 
555      readsamples = sizeof(buf) / full_size;
556      if(samplesleft < readsamples) {
557           readsamples = samplesleft;
558      }
559 
560      ch = chunk_open(chunk);
561      if (ch == NULL) { g_free(c); return TRUE; }
562      status_bar_begin_progress( bar, chunk->length, title);
563 
564      while (samplesleft > 0) {
565 	  if(reverse) {
566 	       readpos = samplepos - readsamples;
567 	  } else {
568 	       readpos = samplepos;
569 	  }
570 
571 	  if (convert) {
572 	       u = chunk_read_array_fp(ch,readpos,
573 				       readsamples,
574 				       (sample_t *)buf,dither_mode,&clipcount);
575 	       u = u * full_size;
576 	  } else {
577 	       u = chunk_read_array(ch,readpos,readsamples * full_size,
578 				    buf,dither_mode,&clipcount);
579 	  }
580 
581 	  g_assert((u / full_size) == readsamples);
582 
583 	  if (!u) {
584 	       chunk_close(ch);
585 	       g_free(c);
586 	       status_bar_end_progress(bar);
587 	       return TRUE;
588 	  }
589 
590 	  d = buf;
591 
592 	  if(reverse) {
593 	       x = u - proc_size;
594 	  } else {
595 	       x = 0;
596 	  }
597 
598 	  while((x >= 0) && (x < u)) {
599 	       if (proc(d+x,proc_size,chunk)) {
600 		    chunk_close(ch);
601 		    g_free(c);
602 		    status_bar_end_progress(bar);
603 		    return TRUE;
604 	       }
605 	       if(reverse) {
606 		    x -= proc_size;
607 	       } else {
608 		    x += proc_size;
609 	       }
610 	  }
611 
612 	  samplesleft -= readsamples;
613 	  if(reverse) {
614 	       samplepos -= readsamples;
615 	       if(samplepos < 0) {
616 		    readsamples = readsamples + samplepos;
617 		    samplepos = 0;
618 	       }
619 	  } else {
620 	       samplepos += readsamples;
621 	  }
622 	  if(samplesleft < readsamples) {
623 	       readsamples = samplesleft;
624 	  }
625 	  if (status_bar_progress(bar, u / full_size)) {
626 	       chunk_close(ch);
627 	       g_free(c);
628 	       status_bar_end_progress(bar);
629 	       return TRUE;
630 	  }
631      }
632      chunk_close(ch);
633      g_free(c);
634      status_bar_end_progress(bar);
635      clipwarn(clipcount,FALSE);
636      return FALSE;
637 }
638 
chunk_onechannel(Chunk * chunk,int dither_mode,StatusBar * bar)639 Chunk *chunk_onechannel(Chunk *chunk, int dither_mode, StatusBar *bar)
640 {
641      gboolean *map;
642      int i;
643      Chunk *r;
644      map = g_malloc(chunk->format.channels * 1 * sizeof(gboolean));
645      for (i=0; i<chunk->format.channels; i++)
646 	  map[i] = TRUE;
647      r = chunk_remap_channels(chunk,1,map,dither_mode,bar);
648      g_free(map);
649      return r;
650 }
651 
chunk_copy_channel(Chunk * chunk,gint channel,int dither_mode,StatusBar * bar)652 Chunk *chunk_copy_channel(Chunk *chunk, gint channel, int dither_mode,
653 			  StatusBar *bar)
654 {
655      int i,new_chans;
656      int *map;
657 
658      new_chans = chunk->format.channels + 1;
659      map = g_malloc(new_chans * sizeof(int));
660      for (i=0; i<new_chans; i++) {
661 	  if (i <= channel) map[i] = i;
662 	  else map[i] = i-1;
663      }
664      return chunk_ds_remap(chunk,new_chans,map);
665 }
666 
667 
chunk_mix(Chunk * c1,Chunk * c2,int dither_mode,StatusBar * bar)668 Chunk *chunk_mix(Chunk *c1, Chunk *c2, int dither_mode, StatusBar *bar)
669 {
670      #define BUFLEN 256
671      off_t u,mixlen;
672      guint i,chn,x1,x2,x;
673      off_t clipcount = 0;
674      sample_t buf1[BUFLEN],buf2[BUFLEN],buf3[BUFLEN];
675      sample_t s,pmax;
676      gchar *str;
677      Dataformat format;
678      Chunk *m,*c,*d;
679      ChunkHandle *ch1, *ch2;
680      TempFile tmp;
681 
682      g_assert(chunk_format_equal(c1,c2));
683 
684      pmax = maximum_float_value(&(c1->format));
685 
686      /* Number of channels */
687      chn = c1->format.channels;
688      /* Number of multi-channel samples to mix */
689      mixlen = MIN(c1->length, c2->length);
690 
691      memcpy(&format,&(c1->format),sizeof(Dataformat));
692      format.type = DATAFORMAT_FLOAT;
693      format.samplesize = sizeof(sample_t);
694      format.bigendian = dataformat_sample_t.bigendian;
695      format.samplebytes = format.samplesize * format.channels;
696 
697      /* Prepare for processing */
698      ch1 = chunk_open(c1);
699      if ( ch1 == NULL ) return NULL;
700      ch2 = chunk_open(c2);
701      if ( ch2 == NULL ) { chunk_close(ch1); return NULL; }
702      tmp = tempfile_init(&format,FALSE);
703      status_bar_begin_progress(bar, mixlen, _("Mixing"));
704 
705      for (u=0; u<mixlen; u+=x) {
706 
707 	  x1 = chunk_read_array_fp(ch1,u,BUFLEN/chn,buf1,dither_mode,
708 				   &clipcount);
709 	  x2 = chunk_read_array_fp(ch2,u,BUFLEN/chn,buf2,dither_mode,
710 				   &clipcount);
711 	  if (x1 == 0 || x2 == 0) {
712 	       tempfile_abort(tmp);
713 	       chunk_close(ch1);
714 	       chunk_close(ch2);
715 	       status_bar_end_progress(bar);
716 	       return NULL;
717 	  }
718 
719 	  /* Number of mixable multi-channel samples for this run */
720 	  x = MIN(x1,x2);
721 	  /* Mix the data from buf1,buf2 into buf3 */
722 	  for (i=0; i<x*chn; i++) {
723 	       s = buf1[i] + buf2[i];
724 	       if (s > pmax) { clipcount ++; s = pmax; }
725 	       else if (s < -1.0) { clipcount ++; s = -1.0; }
726 	       buf3[i] = s;
727 	  }
728 
729 	  /* Write buf3 directly */
730 	  if (tempfile_write(tmp,buf3,x*chn*sizeof(sample_t))
731 	      || status_bar_progress(bar,x)) {
732 	       tempfile_abort(tmp);
733 	       chunk_close(ch1);
734 	       chunk_close(ch2);
735 	       status_bar_end_progress(bar);
736 	       return NULL;
737 	  }
738      }
739 
740      /* Finish processing */
741      chunk_close(ch1);
742      chunk_close(ch2);
743      m = tempfile_finished(tmp);
744      status_bar_end_progress(bar);
745      if (!m) return NULL;
746 
747      /* Fake the original pcm format */
748      if (!dataformat_equal(&(c1->format),&(m->format))) {
749 	  c = chunk_convert_sampletype(m,&(c1->format));
750 	  g_assert(c != NULL);
751 	  gtk_object_sink(GTK_OBJECT(m));
752 	  m = c;
753      }
754 
755      /* Warn if clipping occured */
756      if (clipcount > 0) {
757 	  if (clipcount > 1000000000) clipcount = 1000000000;
758 	  str = g_strdup_printf(_("The mixed result was clipped %d times."),
759 				(int)clipcount);
760 	  user_warning(str);
761 	  g_free(str);
762      }
763 
764      /* We may need to append some unmixed data at the end */
765      if (c1->length == c2->length) return m;
766      if (c1->length > mixlen)
767 	  c = chunk_get_part(c1,mixlen,c1->length-mixlen);
768      else
769 	  c = chunk_get_part(c2,mixlen,c2->length-mixlen);
770      d = chunk_append(m,c);
771      gtk_object_sink(GTK_OBJECT(m));
772      gtk_object_sink(GTK_OBJECT(c));
773 
774      return d;
775 #undef BUFLEN
776 }
777 
sandwich_copy(char * dest_buf,int dest_offset,int dest_item_size,char * source_buf,int source_item_size,int items)778 static void sandwich_copy(char *dest_buf, int dest_offset, int dest_item_size,
779 			  char *source_buf, int source_item_size, int items)
780 {
781      int i;
782      for (i=0; i<items; i++)
783 	  memcpy(dest_buf+dest_offset+i*dest_item_size,
784 		 source_buf+i*source_item_size,
785 		 source_item_size);
786 }
787 
788 
chunk_sandwich_main(Chunk * c1,Chunk * c2,int dither_mode,StatusBar * bar)789 static Chunk *chunk_sandwich_main(Chunk *c1, Chunk *c2, int dither_mode, StatusBar *bar)
790 {
791 #define BUFLEN 512
792      off_t u,mixlen;
793      guint chn1,chn2,x,x1,x2;
794      off_t clipcount = 0;
795      char *buf1,*buf2,*outbuf;
796      Dataformat format;
797      Chunk *m;
798      ChunkHandle *ch1, *ch2;
799      TempFile tmp;
800 
801      g_assert(dataformat_samples_equal(&(c1->format),&(c2->format)) &&
802 	      c1->format.samplerate == c2->format.samplerate);
803 
804      /* Number of channels */
805      chn1 = c1->format.channels;
806      chn2 = c2->format.channels;
807 
808      /* Number of multi-channel samples to mix */
809      g_assert(c1->length == c2->length);
810      mixlen = c1->length;
811 
812      memcpy(&format,&(c1->format),sizeof(Dataformat));
813      format.channels = chn1+chn2;
814      format.samplebytes = format.samplesize * format.channels;
815 
816      /* Prepare for processing */
817      ch1 = chunk_open(c1);
818      if ( ch1 == NULL ) return NULL;
819      ch2 = chunk_open(c2);
820      if ( ch2 == NULL ) { chunk_close(ch1); return NULL; }
821      tmp = tempfile_init(&format,FALSE);
822      status_bar_begin_progress(bar, mixlen, _("Combining channels"));
823 
824      buf1 = g_malloc(BUFLEN*c1->format.samplebytes);
825      buf2 = g_malloc(BUFLEN*c2->format.samplebytes);
826      outbuf = g_malloc(BUFLEN*format.samplebytes);
827 
828      for (u=0; u<mixlen; u+=x) {
829 
830 	  x = BUFLEN;
831 	  if ((off_t)x > (mixlen-u))
832 	       x = ((guint)(mixlen-u));
833 
834 	  x1 = chunk_read_array(ch1,u,x*c1->format.samplebytes,buf1,
835 				dither_mode,&clipcount);
836 	  x2 = chunk_read_array(ch2,u,x*c2->format.samplebytes,
837 				buf2,dither_mode,&clipcount);
838 
839 	  if (x1 == 0 || x2 == 0) {
840 	       tempfile_abort(tmp);
841 	       chunk_close(ch1);
842 	       chunk_close(ch2);
843 	       status_bar_end_progress(bar);
844 	       g_free(buf1);
845 	       g_free(buf2);
846 	       g_free(outbuf);
847 	       return NULL;
848 	  }
849 
850 	  g_assert(x1 == x*c1->format.samplebytes &&
851 		   x2 == x*c2->format.samplebytes);
852 
853 	  /* Combine the data from buf1,buf2 into outbuf */
854 	  sandwich_copy(outbuf,0,format.samplebytes,
855 			buf1,c1->format.samplebytes, x);
856 	  sandwich_copy(outbuf,c1->format.samplebytes,format.samplebytes,
857 			buf2,c2->format.samplebytes, x);
858 
859 	  /* Write outbuf */
860 	  if (tempfile_write(tmp,outbuf,x*format.samplebytes)
861 	      || status_bar_progress(bar,x)) {
862 	       tempfile_abort(tmp);
863 	       chunk_close(ch1);
864 	       chunk_close(ch2);
865 	       status_bar_end_progress(bar);
866 	       g_free(buf1);
867 	       g_free(buf2);
868 	       g_free(outbuf);
869 	       return NULL;
870 	  }
871      }
872 
873      /* Finish processing */
874      chunk_close(ch1);
875      chunk_close(ch2);
876      m = tempfile_finished(tmp);
877      status_bar_end_progress(bar);
878      g_free(buf1);
879      g_free(buf2);
880      g_free(outbuf);
881      if (!m) return NULL;
882 
883      /* Warn if clipping occured */
884      clipwarn(clipcount,FALSE);
885 
886      return m;
887 #undef BUFLEN
888 }
889 
chunk_sandwich(Chunk * c1,Chunk * c2,off_t c1_align_point,off_t c2_align_point,off_t * align_point_out,int dither_mode,StatusBar * bar)890 Chunk *chunk_sandwich(Chunk *c1, Chunk *c2,
891 		      off_t c1_align_point, off_t c2_align_point,
892 		      off_t *align_point_out, int dither_mode, StatusBar *bar)
893 {
894      Chunk *before, *mainpart_c1, *mainpart_c2, *mainpart_sw, *after;
895      Chunk *c,*d,*c1_remap,*c2_remap;
896      int *map1,*map2,outchans,i;
897      int mp_c1_maxlen,mp_c2_maxlen,mp_c1_offset,mp_c2_offset,mp_len;
898      off_t offset;
899 
900      offset = c2_align_point-c1_align_point;
901      outchans = c1->format.channels + c2->format.channels;
902 
903      map1 = g_malloc(outchans * sizeof(map1[0]));
904      map2 = g_malloc(outchans * sizeof(map2[0]));
905      for (i=0; i<c1->format.channels; i++) { map1[i]=i; map2[i]=-1; }
906      for (; i<outchans; i++) { map1[i]=-1; map2[i]=i-(c1->format.channels); }
907 
908      c1_remap = chunk_ds_remap(c1,outchans,map1);
909      c2_remap = chunk_ds_remap(c2,outchans,map2);
910 
911      /* g_free(map1); g_free(map2); Done already by chunk_ds_remap */
912 
913      if (offset == 0) {
914 	  before = NULL;
915 	  mp_c1_maxlen = c1->length;
916 	  mp_c1_offset = 0;
917 	  mp_c2_maxlen = c2->length;
918 	  mp_c2_offset = 0;
919 	  *align_point_out = c1_align_point;
920      } else if (offset > 0) {
921 	  before = chunk_get_part(c2_remap, 0, offset);
922 	  mp_c1_maxlen = c1->length;
923 	  mp_c1_offset = 0;
924 	  mp_c2_maxlen = c2->length - offset;
925 	  mp_c2_offset = offset;
926 	  *align_point_out = c2_align_point;
927      } else {
928 	  before = chunk_get_part(c1_remap, 0, -offset);
929 	  mp_c1_maxlen = c1->length+offset;
930 	  mp_c1_offset = -offset;
931 	  mp_c2_maxlen = c2->length;
932 	  mp_c2_offset = 0;
933 	  *align_point_out = c1_align_point;
934      }
935 
936      mp_len = MIN(mp_c1_maxlen, mp_c2_maxlen);
937      if (mp_len > 0) {
938 	  mainpart_c1 = chunk_get_part(c1, mp_c1_offset, mp_len);
939 	  mainpart_c2 = chunk_get_part(c2, mp_c2_offset, mp_len);
940      } else
941 	  mainpart_c1 = mainpart_c2 = NULL;
942 
943      if (mp_len < mp_c1_maxlen) {
944 	  after = chunk_get_part(c1_remap, mp_c1_offset+mp_len,
945 				 mp_c1_maxlen-mp_len);
946      } else if (mp_len < mp_c2_maxlen) {
947 	  after = chunk_get_part(c2_remap, mp_c2_offset+mp_len,
948 				 mp_c2_maxlen-mp_len);
949      } else {
950 	  after = NULL;
951      }
952 
953      /* Floating refs: c1_remap,c2_remap,before,after,mainpart_c1,mainpart_c2 */
954      gtk_object_sink(GTK_OBJECT(c1_remap));
955      gtk_object_sink(GTK_OBJECT(c2_remap));
956 
957      if (mp_len > 0) {
958 	  mainpart_sw = chunk_sandwich_main(mainpart_c1, mainpart_c2,
959 					    dither_mode, bar);
960 	  gtk_object_sink(GTK_OBJECT(mainpart_c1));
961 	  gtk_object_sink(GTK_OBJECT(mainpart_c2));
962 	  if (mainpart_sw == NULL) {
963 	       if (before != NULL) gtk_object_sink(GTK_OBJECT(before));
964 	       if (after != NULL) gtk_object_sink(GTK_OBJECT(after));
965 	       return NULL;
966 	  }
967      } else
968 	  mainpart_sw = NULL;
969 
970      /* Floating refs: before,after,mainpart_sw */
971 
972      c = before;
973      if (mainpart_sw != NULL) {
974 	  if (c != NULL) {
975 	       d = chunk_append(c,mainpart_sw);
976 	       gtk_object_sink(GTK_OBJECT(c));
977 	       gtk_object_sink(GTK_OBJECT(mainpart_sw));
978 	       c = d;
979 	  } else
980 	       c = mainpart_sw;
981      }
982      if (after != NULL) {
983 	  if (c != NULL) {
984 	       d = chunk_append(c,after);
985 	       gtk_object_sink(GTK_OBJECT(c));
986 	       gtk_object_sink(GTK_OBJECT(after));
987 	       c = d;
988 	  } else
989 	       c = after;
990      }
991      return c;
992 }
993 
994 
995 static struct {
996      sample_t *buf;
997      int bufsize;
998      /* (outchannels x (inchannels+1))-matrix */
999      /* Each row has a list of input channel numbers, ending with -1 */
1000      int *map;
1001 } chunk_remap_channels_data;
1002 
chunk_remap_channels_mixmode_proc(void * in,guint sample_size,chunk_writeout_func out_func,WriteoutID id,Dataformat * informat,Dataformat * outformat)1003 static gboolean chunk_remap_channels_mixmode_proc(void *in,
1004 						  guint sample_size,
1005 						  chunk_writeout_func out_func,
1006 						  WriteoutID id,
1007 						  Dataformat *informat,
1008 						  Dataformat *outformat)
1009 {
1010      int samps,i,j,k,l;
1011      sample_t *iptr, *optr, s;
1012      samps = sample_size / informat->samplebytes;
1013 
1014      /* Make sure we have room in the buffer */
1015      if (samps * outformat->samplebytes > chunk_remap_channels_data.bufsize) {
1016 	  g_free(chunk_remap_channels_data.buf);
1017 	  chunk_remap_channels_data.buf =
1018 	       g_malloc(samps*outformat->samplebytes);
1019 	  chunk_remap_channels_data.bufsize = samps*outformat->samplebytes;
1020      }
1021 
1022      /* Process data */
1023      iptr = (sample_t *)in;
1024      optr = chunk_remap_channels_data.buf;
1025 
1026      for (i=0; i<samps; i++) {
1027 	  for (j=0; j<outformat->channels; j++) {
1028 	       s = 0.0;
1029 	       for (k=(j*(informat->channels+1)); 1; k++) {
1030 		    l = chunk_remap_channels_data.map[k];
1031 		    if (l < 0) break;
1032 		    s += iptr[l];
1033 	       }
1034 	       optr[j] = s;
1035 	  }
1036 	  iptr += informat->channels;
1037 	  optr += outformat->channels;
1038      }
1039 
1040      return out_func(id, chunk_remap_channels_data.buf,
1041 		     samps*outformat->samplebytes);
1042 }
1043 
chunk_remap_channels(Chunk * chunk,int channels_out,gboolean * map,int dither_mode,StatusBar * bar)1044 Chunk *chunk_remap_channels(Chunk *chunk, int channels_out, gboolean *map,
1045 			    int dither_mode, StatusBar *bar)
1046 {
1047      gboolean mixmode;
1048      int i,j,k;
1049      int channels_in = chunk->format.channels;
1050      Dataformat tofmt;
1051      Chunk *r;
1052      int *bigmap,*smallmap;
1053 
1054      memcpy(&tofmt,&(chunk->format),sizeof(Dataformat));
1055      tofmt.channels = channels_out;
1056      tofmt.samplebytes = tofmt.channels * tofmt.samplesize;
1057 
1058      chunk_remap_channels_data.buf = NULL;
1059      chunk_remap_channels_data.bufsize = 0;
1060 
1061      /* Generate the maps */
1062      mixmode = FALSE;
1063      bigmap = g_malloc((channels_in+1)*channels_out*sizeof(int));
1064      smallmap = g_malloc(channels_out*sizeof(int));
1065 
1066      for (i=0; i<channels_out; i++) {
1067 	  smallmap[i] = -1;
1068 	  k = 0;
1069 	  for (j=0; j<channels_in; j++)
1070 	       if (map[j*channels_out + i]) {
1071 		    bigmap[i*(channels_in+1)+(k++)] = j;
1072 		    smallmap[i] = j;
1073 	       }
1074 	  bigmap[i*(channels_in+1) + k] = -1;
1075 	  if (k > 1) mixmode = TRUE;
1076      }
1077 
1078      if (mixmode) {
1079 	  chunk_remap_channels_data.map = bigmap;
1080 	  g_free(smallmap);
1081 	  r = chunk_filter_tofmt(chunk,chunk_remap_channels_mixmode_proc,
1082 				 NULL,CHUNK_FILTER_MANY,TRUE,&tofmt,
1083 				 dither_mode,bar,_("Mixing channels"));
1084 	  g_free(chunk_remap_channels_data.buf);
1085 	  g_free(chunk_remap_channels_data.map);
1086      } else {
1087 	  g_free(bigmap);
1088 	  r = chunk_ds_remap(chunk,channels_out,smallmap);
1089      }
1090 
1091      return r;
1092 }
1093 
chunk_foreach(GFunc func,gpointer user_data)1094 void chunk_foreach(GFunc func, gpointer user_data)
1095 {
1096      g_list_foreach(chunks,func,user_data);
1097 }
1098 
chunk_new_from_datasource(Datasource * ds)1099 Chunk *chunk_new_from_datasource(Datasource *ds)
1100 {
1101      Chunk *c;
1102      DataPart *dp;
1103      if (ds==NULL) return NULL;
1104      dp = g_malloc(sizeof(*dp));
1105      dp->ds = ds;
1106      dp->position = 0;
1107      dp->length = ds->length;
1108      gtk_object_ref(GTK_OBJECT(ds));
1109      gtk_object_sink(GTK_OBJECT(ds));
1110      c = chunk_new();
1111      memcpy(&(c->format),&(ds->format),sizeof(Dataformat));
1112      c->length = ds->length;
1113      c->size = c->length * c->format.samplebytes;
1114      c->parts = g_list_append(NULL,dp);
1115      /* printf("chunk_new_from_datasource(%p) -> %p\n",ds,c); */
1116      return c;
1117 }
1118 
chunk_open(Chunk * chunk)1119 ChunkHandle *chunk_open(Chunk *chunk)
1120 {
1121      GList *l;
1122      DataPart *dp;
1123      for (l=chunk->parts;l!=NULL;l=l->next) {
1124 	  dp = (DataPart *)l->data;
1125 	  if (datasource_open(dp->ds)) {
1126 	       for (l=l->prev;l!=NULL;l=l->prev) {
1127 		    dp = (DataPart *)l->data;
1128 		    datasource_close(dp->ds);
1129 	       }
1130 	       return NULL;
1131 	  }
1132      }
1133      chunk->opencount ++;
1134      return chunk;
1135 }
1136 
chunk_close(ChunkHandle * handle)1137 void chunk_close(ChunkHandle *handle)
1138 {
1139      GList *l;
1140      DataPart *dp;
1141      g_assert(handle->opencount > 0);
1142      for (l=handle->parts;l!=NULL;l=l->next) {
1143 	  dp = (DataPart *)l->data;
1144 	  datasource_close(dp->ds);
1145      }
1146      handle->opencount --;
1147 }
1148 
chunk_read(ChunkHandle * handle,off_t sampleno,void * buffer,int dither_mode)1149 gboolean chunk_read(ChunkHandle *handle, off_t sampleno, void *buffer,
1150 		    int dither_mode)
1151 {
1152      GList *l;
1153      DataPart *dp;
1154      for (l=handle->parts;l!=NULL;l=l->next) {
1155 	  dp = (DataPart *)l->data;
1156 	  if (dp->length > sampleno)
1157 	       return datasource_read(dp->ds,sampleno,buffer,dither_mode);
1158 	  else
1159 	       sampleno -= dp->length;
1160      }
1161      g_assert_not_reached();
1162      return TRUE;
1163 }
1164 
chunk_read_fp(ChunkHandle * handle,off_t sampleno,sample_t * buffer,int dither_mode)1165 gboolean chunk_read_fp(ChunkHandle *handle, off_t sampleno, sample_t *buffer,
1166 		       int dither_mode)
1167 {
1168      GList *l;
1169      DataPart *dp;
1170      for (l=handle->parts;l!=NULL;l=l->next) {
1171 	  dp = (DataPart *)l->data;
1172 	  if (dp->length > sampleno)
1173 	       return datasource_read_fp(dp->ds,dp->position+sampleno,buffer,
1174 					 dither_mode);
1175 	  else
1176 	       sampleno -= dp->length;
1177      }
1178      g_assert_not_reached();
1179      return TRUE;
1180 }
1181 
chunk_read_array(ChunkHandle * handle,off_t sampleno,guint size,void * buffer,int dither_mode,off_t * clipcount)1182 guint chunk_read_array(ChunkHandle *handle, off_t sampleno,
1183 		       guint size, void *buffer, int dither_mode,
1184 		       off_t *clipcount)
1185 {
1186      GList *l;
1187      DataPart *dp;
1188      guint r=0,i,j;
1189      guint sb = handle->format.samplebytes;
1190      off_t o;
1191 
1192      /* Loop until we have collected enough data or reached EOF
1193       * The condition size >= sb handles the case size is not an even
1194       * multiple of the number of sample bytes (24-bit data usually) */
1195 
1196      for (l=handle->parts; l!=NULL && size>=sb; l=l->next) {
1197 	  dp = (DataPart *)l->data;
1198 	  if (dp->length > sampleno) {
1199 	       /* Calculate required size if it's larger than we need. */
1200 	       o = dp->length - sampleno;
1201 	       o *= (off_t)sb;
1202 	       if (o < (off_t)size) j = (guint)o;
1203 	       else j = size;
1204 	       /* Read data. */
1205 	       i = datasource_read_array(dp->ds,
1206 					 dp->position + sampleno,
1207 					 j,buffer,dither_mode,clipcount);
1208 	       if (i == 0) return 0;
1209 	       r+=i;
1210 	       sampleno = 0;
1211 	       size -= i;
1212 	       buffer = ((gchar *)buffer) + i;
1213 	  } else
1214 	       sampleno -= dp->length;
1215      }
1216      return r;
1217 }
1218 
chunk_read_array_fp(ChunkHandle * handle,off_t sampleno,guint samples,sample_t * buffer,int dither_mode,off_t * clipcount)1219 guint chunk_read_array_fp(ChunkHandle *handle, off_t sampleno,
1220 			  guint samples, sample_t *buffer, int dither_mode,
1221 			  off_t *clipcount)
1222 {
1223      GList *l;
1224      DataPart *dp;
1225      guint r=0,i,j;
1226      off_t o;
1227      g_assert(sampleno < handle->length);
1228      for (l=handle->parts;l!=NULL;l=l->next) {
1229 	  dp = (DataPart *)l->data;
1230 	  if (dp->length > sampleno) {
1231 	       o = dp->length-sampleno;
1232 	       if (o < (off_t)samples)
1233 		    j = (guint)o;
1234 	       else
1235 		    j = samples;
1236 	       i = datasource_read_array_fp(dp->ds,
1237 					    dp->position+sampleno,
1238 					    j,buffer,dither_mode,clipcount);
1239 	       g_assert(i <= samples);
1240 	       g_assert(i <= dp->length - sampleno);
1241 	       if (i==0) return 0;
1242 	       r += i;
1243 	       buffer += i*handle->format.channels;
1244 	       samples -= i;
1245 	       sampleno = 0;
1246 	       if (samples == 0 || l->next==NULL) return r;
1247 	  } else
1248 	       sampleno -= dp->length;
1249      }
1250      return r;
1251 }
1252 
datapart_list_copy(GList * src,GList ** dest)1253 static DataPart *datapart_list_copy(GList *src, GList **dest)
1254 {
1255      DataPart *old,*new;
1256      old = src->data;
1257      new = g_malloc(sizeof(DataPart));
1258      new->ds = old->ds;
1259      new->position = old->position;
1260      new->length = old->length;
1261      gtk_object_ref(GTK_OBJECT(old->ds));
1262      (*dest) = g_list_append((*dest),new);
1263      return new;
1264 }
1265 
chunk_append(Chunk * first,Chunk * second)1266 Chunk *chunk_append(Chunk *first, Chunk *second)
1267 {
1268      Chunk *c;
1269      GList *nl=NULL,*l;
1270      off_t len=0;
1271      DataPart *dp;
1272      g_assert(chunk_format_equal(first,second));
1273      for (l=first->parts; l!=NULL; l=l->next) {
1274 	  dp = datapart_list_copy(l,&nl);
1275 	  len += dp->length;
1276      }
1277      for (l=second->parts; l!=NULL; l=l->next) {
1278 	  dp = datapart_list_copy(l,&nl);
1279 	  len += dp->length;
1280      }
1281      c = chunk_new();
1282      memcpy(&(c->format),&(first->format),sizeof(Dataformat));
1283      c->parts = nl;
1284      c->length = len;
1285      c->size = len * c->format.samplebytes;
1286      return c;
1287 }
1288 
chunk_insert(Chunk * chunk,Chunk * part,off_t sampleno)1289 Chunk *chunk_insert(Chunk *chunk, Chunk *part, off_t sampleno)
1290 {
1291      GList *nl=NULL,*l,*m;
1292      DataPart *dp;
1293      Chunk *c;
1294 
1295      g_assert(sampleno <= chunk->length);
1296      g_assert(chunk_format_equal(chunk,part));
1297      if (sampleno == chunk->length) return chunk_append(chunk,part);
1298 
1299      /* Get beginning */
1300      for (l=chunk->parts; sampleno>0; l=l->next) {
1301 	  dp = datapart_list_copy(l,&nl);
1302 	  if (sampleno < dp->length) {
1303 	       dp->length = sampleno;
1304 	       break;
1305 	  }
1306 	  sampleno -= dp->length;
1307      }
1308 
1309      /* Add the inserted part */
1310      for (m=part->parts; m!=NULL; m=m->next)
1311 	  datapart_list_copy(m,&nl);
1312 
1313      /* Add the rest */
1314      for (; l!=NULL; l=l->next) {
1315 	  dp = datapart_list_copy(l,&nl);
1316 	  dp->position += sampleno;
1317 	  dp->length -= sampleno;
1318 	  sampleno = 0;
1319      }
1320 
1321      /* Create the chunk */
1322      c = chunk_new();
1323      memcpy(&(c->format),&(chunk->format),sizeof(Dataformat));
1324      c->parts = nl;
1325      c->length = chunk->length + part->length;
1326      c->size = chunk->size + part->size;
1327      return c;
1328 }
1329 
chunk_get_part(Chunk * chunk,off_t start,off_t length)1330 Chunk *chunk_get_part(Chunk *chunk, off_t start, off_t length)
1331 {
1332      GList *l,*nl=NULL;
1333      DataPart *dp;
1334      Chunk *c;
1335      l=chunk->parts;
1336      /* Skip beginning parts */
1337      while (1) {
1338 	  dp = (DataPart *)l->data;
1339 	  if (start < dp->length) break;
1340 	  start -= dp->length;
1341 	  l=l->next;
1342      }
1343      while (length>0 && l!=NULL) {
1344 	  dp = datapart_list_copy(l,&nl);
1345 	  dp->position += start;
1346 	  dp->length -= start;
1347 	  start = 0;
1348 	  if (dp->length > length) dp->length=length;
1349 	  length -= dp->length;
1350 	  l=l->next;
1351      }
1352 
1353      c = chunk_new();
1354      memcpy(&(c->format),&(chunk->format),sizeof(Dataformat));
1355      c->parts = nl;
1356      chunk_calc_length(c);
1357      return c;
1358 }
1359 
chunk_remove_part(Chunk * chunk,off_t start,off_t length)1360 Chunk *chunk_remove_part(Chunk *chunk, off_t start, off_t length)
1361 {
1362      GList *nl=NULL,*l;
1363      DataPart *dp;
1364      Chunk *c;
1365 
1366      /* Copy beginning parts */
1367      l=chunk->parts;
1368      while (start>0) {
1369 	  dp = datapart_list_copy(l,&nl);
1370 	  if (start < dp->length) {
1371 	       dp->length = start;
1372 	       break;
1373 	  }
1374 	  start -= dp->length;
1375 	  l=l->next;
1376      }
1377 
1378      /* Skip parts */
1379      length += start;
1380      while (length>0 && l!=NULL) {
1381 	  dp = (DataPart *)l->data;
1382 	  if (dp->length > length) break;
1383 	  length -= dp->length;
1384 	  l=l->next;
1385      }
1386 
1387      /* Copy remaining parts */
1388      for (;l!=NULL;l=l->next) {
1389 	  dp = datapart_list_copy(l,&nl);
1390 	  dp->position += length;
1391 	  dp->length -= length;
1392 	  length = 0;
1393      }
1394 
1395      c = chunk_new();
1396      memcpy(&(c->format),&(chunk->format),sizeof(Dataformat));
1397      c->parts = nl;
1398      chunk_calc_length(c);
1399      return c;
1400 }
1401 
chunk_replace_part(Chunk * chunk,off_t start,off_t length,Chunk * new)1402 Chunk *chunk_replace_part(Chunk *chunk, off_t start, off_t length, Chunk *new)
1403 {
1404      Chunk *c;
1405      GList *nl=NULL,*l;
1406      DataPart *dp;
1407      guint i;
1408      g_assert(dataformat_equal(&(chunk->format),&(new->format)));
1409      for (l=new->parts; l!=NULL; l=l->next)
1410 	  datapart_list_copy(l,&nl);
1411      c = chunk_remove_part(chunk,start,length);
1412      for (l=c->parts,i=0; start>0; l=l->next,i++) {
1413 	  dp = (DataPart *)l->data;
1414 	  g_assert(dp->length <= start);
1415 	  start -= dp->length;
1416      }
1417      for (l=nl; l!=NULL; l=l->next,i++)
1418 	  c->parts = g_list_insert(c->parts, l->data, i);
1419      g_list_free(nl);
1420      c->length += new->length;
1421      c->size = c->length * c->format.samplebytes;
1422      return c;
1423 }
1424 
chunk_clone_df(Chunk * chunk,Dataformat * format)1425 Chunk *chunk_clone_df(Chunk *chunk, Dataformat *format)
1426 {
1427      Chunk *c;
1428      GList *l,*nl=NULL;
1429      DataPart *dp,*ndp;
1430 
1431      for (l=chunk->parts; l!=NULL; l=l->next) {
1432 	  dp = (DataPart *)l->data;
1433 	  ndp = g_malloc(sizeof(*ndp));
1434 	  ndp->ds = dp->ds;
1435 	  if (!dataformat_equal(format,&(chunk->format)))
1436 	       ndp->ds = datasource_clone_df(ndp->ds, format);
1437 	  gtk_object_ref(GTK_OBJECT(ndp->ds));
1438 	  gtk_object_sink(GTK_OBJECT(ndp->ds));
1439 	  ndp->position = dp->position;
1440 	  ndp->length = (dp->length * dp->ds->format.samplebytes) /
1441 	       ndp->ds->format.samplebytes;
1442 	  nl = g_list_append(nl,ndp);
1443      }
1444 
1445      c = chunk_new();
1446      memcpy(&(c->format),format,sizeof(Dataformat));
1447      c->parts = nl;
1448      chunk_calc_length(c);
1449      return c;
1450 }
1451 
1452 
1453 static sample_t chunk_peak_level_max;
1454 
chunk_peak_level_proc(void * sample,gint sample_size,Chunk * chunk)1455 static gboolean chunk_peak_level_proc(void *sample, gint sample_size,
1456 				      Chunk *chunk)
1457 {
1458      sample_t s;
1459      s = (sample_t)fabs((double)(*((sample_t *)sample)));
1460      if (s > chunk_peak_level_max) {
1461 	  chunk_peak_level_max = s;
1462 	  if (s == 1.0 && chunk->format.type == DATAFORMAT_PCM) return TRUE;
1463      }
1464      return FALSE;
1465 }
1466 
chunk_peak_level(Chunk * c,StatusBar * bar)1467 sample_t chunk_peak_level(Chunk *c, StatusBar *bar)
1468 {
1469      chunk_peak_level_max = 0.0;
1470      if (chunk_parse(c,chunk_peak_level_proc,FALSE,TRUE,DITHER_NONE,bar,
1471 		     _("Calculating peak level"),0,FALSE)) return -1.0;
1472      return chunk_peak_level_max;
1473 }
1474 
1475 /* BEGIN zero-crossing search added by Forest Bond */
1476 
1477 static off_t chunk_zero_crossing_seen_samples;
1478 static sample_t *chunk_zero_crossing_saved_sample = NULL;
1479 
chunk_signal_crossed_zero(sample_t prev,sample_t current)1480 static gboolean chunk_signal_crossed_zero(sample_t prev, sample_t current)
1481 {
1482      if((current >= 0.0) && (prev <= 0.0)) {
1483           return TRUE;
1484      } else if((current <= 0.0) && (prev >= 0.0)) {
1485           return TRUE;
1486      }
1487      return FALSE;
1488 }
1489 
chunk_zero_crossing_init(gint sample_size)1490 static void chunk_zero_crossing_init(gint sample_size) {
1491      if(chunk_zero_crossing_saved_sample != NULL) {
1492           g_free(chunk_zero_crossing_saved_sample);
1493           chunk_zero_crossing_saved_sample = NULL;
1494      }
1495      chunk_zero_crossing_saved_sample = g_malloc(sample_size);
1496 }
1497 
chunk_zero_crossing_cleanup()1498 static void chunk_zero_crossing_cleanup() {
1499      if(chunk_zero_crossing_saved_sample != NULL) {
1500           g_free(chunk_zero_crossing_saved_sample);
1501           chunk_zero_crossing_saved_sample = NULL;
1502      }
1503 }
1504 
chunk_zero_crossing_save_sample(sample_t * sample,gint sample_size)1505 static void chunk_zero_crossing_save_sample(sample_t *sample,
1506   gint sample_size) {
1507      memcpy(chunk_zero_crossing_saved_sample, sample, sample_size);
1508 }
1509 
chunk_zero_crossing_any_proc(void * sample,gint sample_size,Chunk * chunk)1510 static gboolean chunk_zero_crossing_any_proc(void *sample, gint sample_size,
1511 				      Chunk *chunk)
1512 {
1513      sample_t *start = (sample_t *)sample;
1514      sample_t *end = start + (sample_size/sizeof(sample_t));
1515      sample_t *current = start;
1516      sample_t *prev = chunk_zero_crossing_saved_sample;
1517 
1518      if(chunk_zero_crossing_seen_samples < 1) {
1519           chunk_zero_crossing_init(sample_size);
1520           chunk_zero_crossing_save_sample(start, sample_size);
1521           chunk_zero_crossing_seen_samples++;
1522           return FALSE;
1523      }
1524 
1525      while(current < end) {
1526           if(chunk_signal_crossed_zero(*prev, *current)) {
1527                return TRUE;
1528           }
1529           current++;
1530           prev++;
1531      }
1532 
1533      chunk_zero_crossing_save_sample(start, sample_size);
1534      chunk_zero_crossing_seen_samples++;
1535      return FALSE;
1536 }
1537 
chunk_zero_crossing_any_forward(Chunk * c,StatusBar * bar,off_t samplepos)1538 off_t chunk_zero_crossing_any_forward(Chunk *c, StatusBar *bar,off_t samplepos)
1539 {
1540      chunk_zero_crossing_seen_samples = 0;
1541      chunk_parse(c,chunk_zero_crossing_any_proc,TRUE,TRUE,DITHER_NONE,bar,
1542 		     _("Finding zero-crossing"), samplepos, FALSE);
1543 
1544      chunk_zero_crossing_cleanup();
1545      return samplepos + chunk_zero_crossing_seen_samples;
1546 }
1547 
chunk_zero_crossing_any_reverse(Chunk * c,StatusBar * bar,off_t samplepos)1548 off_t chunk_zero_crossing_any_reverse(Chunk *c, StatusBar *bar,off_t samplepos)
1549 {
1550      chunk_zero_crossing_seen_samples = 0;
1551      chunk_parse(c,chunk_zero_crossing_any_proc,TRUE,TRUE,DITHER_NONE,bar,
1552 		     _("Finding zero-crossing"), samplepos, TRUE);
1553 
1554      chunk_zero_crossing_cleanup();
1555      return samplepos - chunk_zero_crossing_seen_samples;
1556 }
1557 
chunk_zero_crossing_all_proc(void * sample,gint sample_size,Chunk * chunk)1558 static gboolean chunk_zero_crossing_all_proc(void *sample, gint sample_size,
1559 				      Chunk *chunk)
1560 {
1561      sample_t *start = (sample_t *)sample;
1562      sample_t *end = start + (sample_size/sizeof(sample_t));
1563      sample_t *current = start;
1564      sample_t *prev = chunk_zero_crossing_saved_sample;
1565 
1566      if(chunk_zero_crossing_seen_samples < 1) {
1567           chunk_zero_crossing_init(sample_size);
1568           chunk_zero_crossing_save_sample(start, sample_size);
1569           chunk_zero_crossing_seen_samples++;
1570           return FALSE;
1571      }
1572 
1573      while(current < end) {
1574 
1575           if(! chunk_signal_crossed_zero(*prev, *current)) {
1576                chunk_zero_crossing_save_sample(start, sample_size);
1577                chunk_zero_crossing_seen_samples++;
1578                return FALSE;
1579           }
1580           current++;
1581           prev++;
1582      }
1583      return TRUE;
1584 }
1585 
chunk_zero_crossing_all_forward(Chunk * c,StatusBar * bar,off_t samplepos)1586 off_t chunk_zero_crossing_all_forward(Chunk *c, StatusBar *bar,off_t samplepos)
1587 {
1588      chunk_zero_crossing_seen_samples = 0;
1589      chunk_parse(c,chunk_zero_crossing_all_proc,TRUE,TRUE,DITHER_NONE,bar,
1590 		     _("Finding zero-crossing"), samplepos, FALSE);
1591 
1592      chunk_zero_crossing_cleanup();
1593      return samplepos + chunk_zero_crossing_seen_samples;
1594 }
1595 
chunk_zero_crossing_all_reverse(Chunk * c,StatusBar * bar,off_t samplepos)1596 off_t chunk_zero_crossing_all_reverse(Chunk *c, StatusBar *bar,off_t samplepos)
1597 {
1598      chunk_zero_crossing_seen_samples = 0;
1599      chunk_parse(c,chunk_zero_crossing_all_proc,TRUE,TRUE,DITHER_NONE,bar,
1600 		     _("Finding zero-crossing"), samplepos, TRUE);
1601 
1602      chunk_zero_crossing_cleanup();
1603 
1604      return samplepos - chunk_zero_crossing_seen_samples;
1605 }
1606 
1607 /* END zero-crossing search */
1608 
1609 static sample_t chunk_amplify_factor;
1610 
chunk_amplify_proc(void * in,guint sample_size,chunk_writeout_func out_func,WriteoutID id,Dataformat * format)1611 static gboolean chunk_amplify_proc(void *in, guint sample_size,
1612 				   chunk_writeout_func out_func,
1613 				   WriteoutID id, Dataformat *format)
1614 {
1615      sample_t *sp,*ep;
1616      sp = ((sample_t *)in);
1617      ep = (sample_t *)(((gchar *)in)+sample_size);
1618      for (; sp<ep; sp++) *sp *= chunk_amplify_factor;
1619      return out_func(id,in,sample_size);
1620 }
1621 
chunk_amplify(Chunk * c,sample_t factor,int dither_mode,StatusBar * bar)1622 Chunk *chunk_amplify(Chunk *c, sample_t factor, int dither_mode,
1623 		     StatusBar *bar)
1624 {
1625      gchar *s;
1626      Chunk *r;
1627 
1628      s = g_strdup_printf(_("Amplifying (by %3.1f%% / %+.1fdB)"),factor*100.0,
1629 			 20*log10(factor));
1630      chunk_amplify_factor = factor;
1631      r = chunk_filter(c,chunk_amplify_proc,NULL,CHUNK_FILTER_MANY,TRUE,
1632 		      dither_mode,bar,s);
1633      g_free(s);
1634      return r;
1635 }
1636 
1637 static sample_t ramp_start,ramp_diff;
1638 static off_t samples_done,samples_total;
1639 
volume_ramp_proc(void * in,guint sample_size,chunk_writeout_func out_func,WriteoutID id,Dataformat * format)1640 static gboolean volume_ramp_proc(void *in, guint sample_size,
1641 				 chunk_writeout_func out_func,
1642 				 WriteoutID id, Dataformat *format)
1643 {
1644      sample_t *sp = (sample_t *)in;
1645      sample_t factor;
1646      int i,j;
1647      for (j=0; j<sample_size; j+=format->channels*sizeof(sample_t)) {
1648 	  factor = ramp_start + (ramp_diff * ((sample_t)samples_done /
1649 					      (sample_t)samples_total));
1650 	  for (i=0; i<format->channels; i++) {
1651 	       *sp *= factor;
1652 	       sp++;
1653 	  }
1654 	  samples_done ++;
1655      }
1656      return out_func(id,in,sample_size);
1657 }
1658 
chunk_volume_ramp(Chunk * c,sample_t start_factor,sample_t end_factor,int dither_mode,StatusBar * bar)1659 Chunk *chunk_volume_ramp(Chunk *c, sample_t start_factor, sample_t end_factor,
1660 			 int dither_mode, StatusBar *bar)
1661 {
1662      if (start_factor == end_factor)
1663 	  return chunk_amplify(c,start_factor,dither_mode,bar);
1664      ramp_start = start_factor;
1665      ramp_diff = end_factor - start_factor;
1666      samples_done = 0;
1667      samples_total = c->length;
1668      return chunk_filter(c,volume_ramp_proc,NULL,CHUNK_FILTER_MANY,TRUE,
1669 			 dither_mode, bar, _("Amplifying"));
1670 }
1671 
chunk_new_with_ramp(Dataformat * format,off_t length,sample_t * startvals,sample_t * endvals,int dither_mode,StatusBar * bar)1672 Chunk *chunk_new_with_ramp(Dataformat *format, off_t length,
1673 			   sample_t *startvals, sample_t *endvals,
1674 			   int dither_mode, StatusBar *bar)
1675 {
1676 #define BUF_LENGTH 512
1677      int i,k;
1678      sample_t diffval[8], *sbuf;
1679      sample_t slength = (sample_t)length;
1680      TempFile tf;
1681      off_t ctr = 0;
1682      int channels = format->channels;
1683      int bufctr;
1684      Dataformat fmt;
1685      Chunk *r,*q;
1686 
1687      g_assert(channels <= 8);
1688 
1689      for (i=0; i<channels; i++)
1690 	  diffval[i] = endvals[i] - startvals[i];
1691 
1692      memcpy(&fmt,&dataformat_sample_t,sizeof(Dataformat));
1693      fmt.channels = channels;
1694      fmt.samplerate = format->samplerate;
1695      fmt.samplebytes = fmt.channels * fmt.samplesize;
1696      tf = tempfile_init(&fmt,FALSE);
1697      if (tf == NULL) return NULL;
1698 
1699      status_bar_begin_progress(bar,length,NULL);
1700      sbuf = g_malloc(BUF_LENGTH*sizeof(sample_t));
1701 
1702      /* Output data */
1703      while (ctr < length) {
1704 	  bufctr = BUF_LENGTH / channels;
1705 	  if ((length-ctr) < (off_t)bufctr) bufctr = (guint)(length-ctr);
1706 	  for (i=0; i<bufctr*channels; i+=channels,ctr++)
1707 	       for (k=0; k<channels; k++)
1708 		    sbuf[i+k] = startvals[k] +
1709 			 diffval[k]*(((sample_t)ctr)/slength);
1710 	  if (tempfile_write(tf,sbuf,bufctr*channels*sizeof(sample_t)) ||
1711 	      status_bar_progress(bar,bufctr)) {
1712 	       g_free(sbuf);
1713 	       tempfile_abort(tf);
1714 	       status_bar_end_progress(bar);
1715 	       return NULL;
1716 	  }
1717      }
1718      /* Finish */
1719      g_free(sbuf);
1720      r = tempfile_finished(tf);
1721      status_bar_end_progress(bar);
1722      if (r!=NULL && !dataformat_equal(&(r->format),format)) {
1723        q = chunk_convert_sampletype(r,format);
1724        gtk_object_sink(GTK_OBJECT(r));
1725        return q;
1726      } else
1727        return r;
1728 
1729 #undef BUF_LENGTH
1730 }
1731 
chunk_interpolate_endpoints(Chunk * chunk,gboolean falldown_mode,int dither_mode,StatusBar * bar)1732 Chunk *chunk_interpolate_endpoints(Chunk *chunk, gboolean falldown_mode,
1733 				   int dither_mode, StatusBar *bar)
1734 {
1735      int i;
1736      Chunk *start,*mid,*end,*c,*d;
1737      ChunkHandle *ch;
1738 
1739      sample_t startval[8],endval[8],zeroval[8];
1740      off_t length = chunk->length;
1741 
1742      /* get the endpoint values */
1743      ch = chunk_open(chunk);
1744      if (ch == NULL) return NULL;
1745      if (chunk_read_fp(ch,0,startval,dither_mode) ||
1746 	 chunk_read_fp(ch,length-1,endval,dither_mode)) {
1747 	  chunk_close(ch);
1748 	  return NULL;
1749      }
1750      chunk_close(ch);
1751      memset(zeroval,0,sizeof(zeroval));
1752 
1753      /* Length of 0.1 s in samples */
1754      i = chunk->format.samplerate / 10;
1755      if (i < 1) i=1;
1756 
1757      if (!falldown_mode || chunk->length <= 2*i) {
1758 	  return chunk_new_with_ramp(&(chunk->format),chunk->length,startval,
1759 				     endval,dither_mode,bar);
1760      } else {
1761 	  start = chunk_new_with_ramp(&(chunk->format),i,startval,zeroval,
1762 				      dither_mode,bar);
1763 	  if (start == NULL) return NULL;
1764 	  end = chunk_new_with_ramp(&(chunk->format),i,zeroval,endval,
1765 				    dither_mode,bar);
1766 	  if (end == NULL) {
1767 	       gtk_object_sink(GTK_OBJECT(start));
1768 	       return NULL;
1769 	  }
1770 	  mid = chunk_new_empty(&(chunk->format),chunk->length-2*i);
1771 	  g_assert(mid != NULL);
1772 
1773 	  c = chunk_append(start,mid);
1774 	  d = chunk_append(c,end);
1775 
1776 	  gtk_object_sink(GTK_OBJECT(start));
1777 	  gtk_object_sink(GTK_OBJECT(mid));
1778 	  gtk_object_sink(GTK_OBJECT(end));
1779 	  gtk_object_sink(GTK_OBJECT(c));
1780 	  return d;
1781 
1782      }
1783 }
1784 
chunk_byteswap(Chunk * chunk)1785 Chunk *chunk_byteswap(Chunk *chunk)
1786 {
1787      Chunk *c,*d;
1788      Dataformat fmt;
1789      memcpy(&fmt,&(chunk->format),sizeof(Dataformat));
1790      fmt.bigendian = !fmt.bigendian;
1791      c = chunk_clone_df(chunk,&fmt);
1792      d = chunk_convert(c,&(chunk->format),DITHER_UNSPEC,NULL);
1793      gtk_object_sink(GTK_OBJECT(c));
1794      return d;
1795 }
1796 
chunk_convert_channels(Chunk * chunk,guint new_channels)1797 Chunk *chunk_convert_channels(Chunk *chunk, guint new_channels)
1798 {
1799      int *map;
1800      int i;
1801      g_assert(chunk->format.channels != new_channels);
1802      map = g_malloc(new_channels * sizeof(int));
1803      for (i=0; i<new_channels; i++) map[i] = i;
1804      /* When converting mono files, put mono channel in both left and right.
1805       * This is in most cases what we want. */
1806      if (chunk->format.channels==1 && new_channels > 1)
1807 	  map[1] = 0;
1808      return chunk_ds_remap(chunk,new_channels,map);
1809 }
1810 
chunk_convert(Chunk * chunk,Dataformat * new_format,int dither_mode,StatusBar * bar)1811 Chunk *chunk_convert(Chunk *chunk, Dataformat *new_format,
1812 		     int dither_mode, StatusBar *bar)
1813 {
1814      Chunk *c=NULL,*d;
1815      const gchar *conv_driver;
1816      if (new_format->samplerate != chunk->format.samplerate) {
1817 	  conv_driver = inifile_get("RateconvDefault",NULL);
1818 	  if (conv_driver == NULL ||
1819 	      rateconv_driver_index(FALSE,conv_driver)==-1)
1820 	       conv_driver = rateconv_driver_id(FALSE,0);
1821 	  if (new_format->channels < chunk->format.channels) {
1822 	       /* First decrease channels, then convert rate */
1823 	       d = chunk_convert_channels(chunk,new_format->channels);
1824 	       if (d == NULL) return NULL;
1825 	       c = chunk_convert_samplerate(d,new_format->samplerate,
1826 					    conv_driver,dither_mode,bar);
1827 	       gtk_object_sink(GTK_OBJECT(d));
1828 	       if (c == NULL) return NULL;
1829 
1830 	  } else if (new_format->channels > chunk->format.channels) {
1831 	       /* First convert rate, then increase channels */
1832 	       d = chunk_convert_samplerate(chunk,new_format->samplerate,
1833 					    conv_driver,dither_mode,bar);
1834 	       if (d == NULL) return NULL;
1835 	       c = chunk_convert_channels(d,new_format->channels);
1836 	       gtk_object_sink(GTK_OBJECT(d));
1837 	       if (c == NULL) return NULL;
1838 
1839 	  } else {
1840 	       /* Just convert rate */
1841 	       c = chunk_convert_samplerate(chunk,new_format->samplerate,
1842 					    conv_driver,dither_mode,bar);
1843 	       if (c == NULL) return NULL;
1844 	  }
1845      } else if (new_format->channels != chunk->format.channels) {
1846 	  /* Just convert channels */
1847 	  c = chunk_convert_channels(chunk,new_format->channels);
1848 	  if (c == NULL) return NULL;
1849      }
1850 
1851      /* Sample format conversion */
1852      if (c == NULL) d = chunk;
1853      else d = c;
1854      if (dataformat_equal(&(d->format),new_format)) return d;
1855      d = chunk_convert_sampletype(d,new_format);
1856      if (c != NULL) gtk_object_sink(GTK_OBJECT(c));
1857      return d;
1858 }
1859 
clipwarn(off_t clipcount,gboolean maycancel)1860 gboolean clipwarn(off_t clipcount, gboolean maycancel)
1861 {
1862      gboolean b = FALSE;
1863      gchar *c;
1864      if (clipcount > 0) {
1865 	  if (clipcount > 1000000000)
1866 	       clipcount = 1000000000;
1867 	  c = g_strdup_printf(_("The input was clipped %d times during "
1868 				"processing."),(int)clipcount);
1869 	  if (maycancel)
1870 	       b = (user_message(c,UM_OKCANCEL) != MR_OK);
1871 	  else
1872 	       user_warning(c);
1873 
1874 	  g_free(c);
1875      }
1876 
1877      return b;
1878 }
1879