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