1 /*
2 * Copyright (C) 2004 2005 2006 2007 2009 2010, Magnus Hjorth
3 *
4 * This file is part of mhWaveEdit.
5 *
6 * mhWaveEdit is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * mhWaveEdit is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with mhWaveEdit; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21
22 #include <config.h>
23
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include <gtk/gtk.h>
28
29 #ifdef HAVE_LIBSAMPLERATE
30 #include <samplerate.h>
31 #endif
32
33 #include "rateconv.h"
34 #include "soxdialog.h"
35 #include "pipedialog.h"
36 #include "ringbuf.h"
37 #include "um.h"
38 #include "gettext.h"
39
40 struct driver_data {
41 const gchar *name;
42 const gchar *id;
43 gboolean is_realtime;
44 gboolean prefers_float;
45 gpointer (*new_func)(struct driver_data *driver, gboolean realtime,
46 Dataformat *format, guint32 outrate,
47 int dither_mode);
48 void (*destroy_func)(gpointer convdata);
49 void (*set_outrate_func)(gpointer convdata, guint32 outrate);
50 gint (*write_func)(gpointer convdata, gpointer buf, guint buflen);
51 gint (*read_func)(gpointer convdata, gpointer buf, guint buflen);
52 gboolean (*hasdata_func)(gpointer convdata);
53 };
54
55 struct driver_data *repeat_driver;
56
57 struct convdata_base {
58 struct driver_data *driver;
59 Ringbuf *passthru_buffer;
60 gboolean emptying;
61 guint32 writecount,readcount;
62 guint32 empty_point;
63 guint32 inrate,outrate;
64 };
65
66 static GList *drivers = NULL;
67 static GList *realtime_drivers = NULL;
68
69 static gint sox_read(gpointer convdata, gpointer buf, guint bufsize);
70
71 #ifdef HAVE_LIBSAMPLERATE
72
73 struct convdata_src {
74 struct convdata_base b;
75 Dataformat format;
76 SRC_STATE *state;
77 long maxframes;
78 SRC_DATA data;
79 int dither_mode;
80 };
81
rateconv_src_new(struct driver_data * driver,gboolean realtime,Dataformat * format,guint32 outrate,int dither_mode)82 static gpointer rateconv_src_new(struct driver_data *driver, gboolean realtime,
83 Dataformat *format, guint32 outrate,
84 int dither_mode)
85 {
86 struct convdata_src *cd;
87 long frames;
88 SRC_STATE *state;
89 int i;
90 int src_converter_type;
91 gchar *c;
92
93 /* puts("rateconv_src_new starts"); */
94 src_converter_type = driver->id[3] - '1';
95 state = src_new(src_converter_type, format->channels, &i);
96 if (state == NULL) {
97 c = g_strdup_printf(_("Error initialising sample rate conversion: %s"),
98 src_strerror(i));
99 user_error(c);
100 g_free(c);
101 return NULL;
102 }
103
104 cd = g_malloc(sizeof(*cd));
105 cd->state = state;
106 memcpy(&(cd->format),format,sizeof(Dataformat));
107 frames = 16384;
108 cd->maxframes = frames;
109 cd->data.data_in = g_malloc(frames * sizeof(float) * format->channels);
110 cd->data.input_frames = 0;
111 cd->data.data_out = g_malloc(frames * sizeof(float) * format->channels);
112 cd->data.src_ratio = ((double)outrate)/((double)format->samplerate);
113 cd->data.end_of_input = 0;
114 cd->dither_mode = dither_mode;
115 /* puts("rateconv_src_new ends"); */
116 return cd;
117 }
118
rateconv_src_destroy(gpointer convdata)119 static void rateconv_src_destroy(gpointer convdata)
120 {
121 struct convdata_src *cd = (struct convdata_src *)convdata;
122 src_delete(cd->state);
123 g_free(cd->data.data_in);
124 g_free(cd->data.data_out);
125 g_free(cd);
126 }
127
rateconv_src_write(gpointer convdata,gpointer buf,guint bufsize)128 static int rateconv_src_write(gpointer convdata, gpointer buf, guint bufsize)
129 {
130 struct convdata_src *cd = (struct convdata_src *)convdata;
131 /* puts("rateconv_src_write starts"); */
132 long wf = bufsize / cd->format.samplebytes;
133 long l = cd->maxframes - cd->data.input_frames;
134 if (buf == NULL) {
135 cd->data.end_of_input = 1;
136 return 0;
137 }
138 if (wf > l) wf = l;
139 if (wf == 0) return 0;
140 convert_array(buf, &(cd->format),
141 &(cd->data.data_in[cd->data.input_frames *
142 cd->format.channels]),
143 &dataformat_single, wf * cd->format.channels,
144 cd->dither_mode, NULL);
145 cd->data.input_frames += wf;
146 /* puts("rateconv_src_write ends"); */
147 return wf * cd->format.samplebytes;
148 }
149
rateconv_src_read(gpointer convdata,gpointer buf,guint bufsize)150 static int rateconv_src_read(gpointer convdata, gpointer buf, guint bufsize)
151 {
152 struct convdata_src *cd = (struct convdata_src *)convdata;
153 /* puts("rateconv_src_read starts"); */
154 long rf = bufsize / cd->format.samplebytes;
155 long l = cd->maxframes;
156 int i;
157 gchar *c;
158 if (rf > l) rf = l;
159 cd->data.output_frames = rf;
160 i = src_process(cd->state, &(cd->data));
161 if (i) {
162 c = g_strdup_printf(_("Error converting samplerate: %s\n"),
163 src_strerror(i));
164 console_message(c);
165 g_free(c);
166 return -1;
167 }
168 rf = cd->data.output_frames_gen;
169 if (rf > 0)
170 convert_array(cd->data.data_out, &dataformat_single, buf,
171 &(cd->format), rf * cd->format.channels,
172 cd->dither_mode, NULL);
173 if (cd->data.input_frames_used < cd->data.input_frames) {
174 l = cd->data.input_frames - cd->data.input_frames_used;
175 memmove(cd->data.data_in,
176 &(cd->data.data_in[cd->data.input_frames_used *
177 cd->format.channels]),
178 l*cd->format.channels*sizeof(float));
179 cd->data.input_frames = l;
180 } else
181 cd->data.input_frames = 0;
182 /* puts("rateconv_src_read ends"); */
183 return rf * cd->format.samplebytes;
184 }
185
rateconv_src_hasdata(gpointer convdata)186 static gboolean rateconv_src_hasdata(gpointer convdata)
187 {
188 struct convdata_src *cd = (struct convdata_src *)convdata;
189 return (cd->data.input_frames > 0);
190 }
191
rateconv_src_set_outrate(gpointer convdata,guint32 outrate)192 static void rateconv_src_set_outrate(gpointer convdata, guint32 outrate)
193 {
194 struct convdata_src *cd = (struct convdata_src *)convdata;
195 double new_ratio;
196 int i;
197 gchar *c;
198 new_ratio = ((double)outrate) / ((double)cd->format.samplerate);
199 i = src_set_ratio(cd->state,new_ratio);
200 if (i) {
201 c = g_strdup_printf(_("Error changing samplerate conversion "
202 "ratio: %s\n"),src_strerror(i));
203 console_message(c);
204 g_free(c);
205 } else
206 cd->data.src_ratio = new_ratio;
207 }
208
209
210 #endif
211
212 struct convdata_sox {
213 struct convdata_base b;
214 Dataformat format;
215 gboolean converting;
216 Dataformat convert_from_format;
217 int fds[3];
218 gpointer pipehandle;
219 gchar tmpbuf[32],tmpbuf_in[32];
220 /* 0 = opened, 1 = purge tmpbuf then close, 2 = write closed,
221 3 = read closed */
222 int close_status;
223 int tmpbuf_size,tmpbuf_in_size;
224 int dither_mode;
225 };
226
sox_new(struct driver_data * driver,gboolean realtime,Dataformat * format,guint32 outrate,int dither_mode)227 static gpointer sox_new(struct driver_data *driver, gboolean realtime,
228 Dataformat *format, guint32 outrate, int dither_mode)
229 {
230 struct convdata_sox cd,*cdp;
231 Dataformat fmt;
232 gchar c[512],d[64],e[64];
233 if (format->type == DATAFORMAT_FLOAT || format->samplesize == 3 ||
234 XOR(format->bigendian,IS_BIGENDIAN)) {
235 cd.converting = TRUE;
236 memcpy(&(cd.convert_from_format),format,sizeof(Dataformat));
237 cd.format.type = DATAFORMAT_PCM;
238 cd.format.samplerate = format->samplerate;
239 cd.format.samplesize = 4;
240 cd.format.channels = format->channels;
241 cd.format.sign = FALSE;
242 cd.format.bigendian = IS_BIGENDIAN;
243 cd.format.samplebytes = cd.format.samplesize * cd.format.channels;
244 } else {
245 cd.converting = FALSE;
246 memcpy(&(cd.format),format,sizeof(Dataformat));
247 }
248 sox_dialog_format_string(d,sizeof(d),&(cd.format));
249 memcpy(&fmt,&(cd.format),sizeof(fmt));
250 fmt.samplerate = outrate;
251 sox_dialog_format_string(e,sizeof(e),&fmt);
252 /* driver->id+4 converts driver name to effect name, for example
253 * "sox_resample" to "resample" */
254 g_snprintf(c,sizeof(c),"sox %s - %s - %s",d,e,driver->id+4);
255 /* puts(c); */
256 cd.pipehandle = pipe_dialog_open_pipe(c,cd.fds,TRUE);
257 if (cd.pipehandle == NULL) return NULL;
258 cd.tmpbuf_size = 0;
259 cd.tmpbuf_in_size = 0;
260 cd.close_status = 0;
261 cd.dither_mode = dither_mode;
262 cdp = g_malloc(sizeof(*cdp));
263 memcpy(cdp,&cd,sizeof(struct convdata_sox));
264 return (gpointer)cdp;
265 }
266
sox_destroy(gpointer convdata)267 static void sox_destroy(gpointer convdata)
268 {
269 struct convdata_sox *cd = (struct convdata_sox *)convdata;
270 if (cd->pipehandle != NULL) pipe_dialog_close(cd->pipehandle);
271 g_free(convdata);
272 }
273
sox_purge_tmpbuf(struct convdata_sox * cd)274 static gboolean sox_purge_tmpbuf(struct convdata_sox *cd)
275 {
276 int i,j;
277 if (!fd_canwrite(cd->fds[0])) return FALSE;
278 i = write(cd->fds[0],cd->tmpbuf,cd->tmpbuf_size);
279 if (i <= 0) return TRUE;
280 cd->tmpbuf_size -= i;
281 for (j=0; j<cd->tmpbuf_size; j++)
282 cd->tmpbuf[j] = cd->tmpbuf[j+i];
283 if (cd->close_status == 1 && cd->tmpbuf_size == 0) {
284 pipe_dialog_close_input(cd->pipehandle);
285 cd->close_status = 2;
286 }
287 return FALSE;
288 }
289
sox_write_main(struct convdata_sox * cd,gpointer buf,guint bufsize)290 static gint sox_write_main(struct convdata_sox *cd, gpointer buf,
291 guint bufsize)
292 {
293 int i,j;
294 gchar *c,*p = buf;
295 gboolean purged=FALSE;
296
297 pipe_dialog_error_check(cd->pipehandle);
298
299 bufsize -= bufsize % cd->format.samplebytes;
300
301 if (cd->tmpbuf_size > 0) {
302 if (sox_purge_tmpbuf(cd)) return -1;
303 if (cd->tmpbuf_size > 0) return 0;
304 purged = TRUE;
305 }
306 if (buf == NULL && cd->close_status == 0) {
307 cd->close_status = 1;
308 if (cd->tmpbuf_size == 0) {
309 pipe_dialog_close_input(cd->pipehandle);
310 cd->close_status = 2;
311 }
312 }
313 if (bufsize == 0 || cd->close_status>0 || !fd_canwrite(cd->fds[0]))
314 return purged?cd->format.samplebytes:0;
315 /* puts("sox_write: calling write..."); */
316 #ifdef PIPE_BUF
317 i = write(cd->fds[0],buf,MIN(bufsize,PIPE_BUF));
318 #else
319 i = write(cd->fds[0],buf,MIN(bufsize,fpathconf(cd->fds[0], _PC_PIPE_BUF)));
320 #endif
321 /* printf("tried = %d, got = %d\n",(int)bufsize,i); */
322 if (i == 0) {
323 user_error(_("Unexpected EOF in connection to subprocess"));
324 return -1;
325 }
326 if (i == -1) {
327 c = g_strdup_printf(_("Error writing to subprocess: %s"),
328 strerror(errno));
329 user_error(c);
330 g_free(c);
331 return -1;
332 }
333 j = i % cd->format.samplebytes;
334 if (j > 0) {
335 cd->tmpbuf_size = cd->format.samplebytes - j;
336 memcpy(cd->tmpbuf,p+i,cd->tmpbuf_size);
337 }
338
339 return i-j+(purged?cd->format.samplebytes:0);
340 }
341
sox_write(gpointer convdata,gpointer buf,guint bufsize)342 static gint sox_write(gpointer convdata, gpointer buf, guint bufsize)
343 {
344 struct convdata_sox *cd = (struct convdata_sox *)convdata;
345 if (cd->converting) {
346 gpointer p;
347 guint ns,frames;
348 gint i;
349 frames = bufsize / cd->convert_from_format.samplebytes;
350 ns = frames * cd->format.samplebytes;
351 p = g_malloc(ns);
352 convert_array(buf,&(cd->convert_from_format),
353 p,&(cd->format),frames*cd->format.channels,
354 cd->dither_mode,NULL);
355 i = sox_write_main(cd,p,ns);
356 g_free(p);
357 if (i<=0) return i;
358 return (i / cd->format.samplebytes) *
359 cd->convert_from_format.samplebytes;
360 }
361 return sox_write_main(cd,buf,bufsize);
362 }
363
sox_read_main(struct convdata_sox * cd,gpointer buf,guint bufsize)364 static gint sox_read_main(struct convdata_sox *cd, gpointer buf, guint bufsize)
365 {
366 int i,j;
367 gchar *c, *p = buf;
368
369 if (cd->close_status == 3) return 0;
370
371 pipe_dialog_error_check(cd->pipehandle);
372
373 bufsize -= bufsize % cd->format.samplebytes;
374 if (bufsize == 0) return 0;
375 if (cd->tmpbuf_size > 0) sox_purge_tmpbuf(cd);
376
377
378 if (cd->tmpbuf_in_size > 0) {
379 if (!fd_canread(cd->fds[1]) && cd->close_status < 2) return 0;
380 i = read(cd->fds[1],cd->tmpbuf_in+cd->tmpbuf_in_size,
381 cd->format.samplebytes - cd->tmpbuf_in_size);
382 if (i == -1) {
383 c = g_strdup_printf(_("Error reading from sub process: %s"),
384 strerror(errno));
385 user_error(c);
386 g_free(c);
387 return -1;
388 }
389 if (i == 0) {
390 cd->tmpbuf_in_size = 0;
391 return 0;
392 }
393 cd->tmpbuf_in_size += i;
394 if (cd->tmpbuf_in_size < cd->format.samplebytes) return 0;
395 memcpy(buf,cd->tmpbuf_in,cd->format.samplebytes);
396 cd->tmpbuf_in_size = 0;
397 i = sox_read_main(cd, p+cd->format.samplebytes,
398 bufsize-cd->format.samplebytes);
399 if (i == -1) return -1;
400 return cd->format.samplebytes + i;
401 }
402 if (!fd_canread(cd->fds[1]) && cd->close_status < 2) return 0;
403 i = read(cd->fds[1],buf,bufsize);
404 if (i == -1) {
405 c = g_strdup_printf(_("Error reading from sub process: %s"),
406 strerror(errno));
407 user_error(c);
408 g_free(c);
409 return -1;
410 }
411 if (i == 0) {
412 if (cd->close_status < 2) {
413 user_error(_("SoX closed connection too early!"));
414 return -1;
415 } else {
416 cd->close_status = 3;
417 pipe_dialog_close(cd->pipehandle);
418 cd->pipehandle = NULL;
419 return 0;
420 }
421 }
422 j = i % cd->format.samplebytes;
423 if (j > 0) {
424 cd->tmpbuf_in_size = j;
425 i -= j;
426 memcpy(cd->tmpbuf_in, p+i, j);
427 }
428
429 return i;
430 }
431
sox_read(gpointer convdata,gpointer buf,guint bufsize)432 static gint sox_read(gpointer convdata, gpointer buf, guint bufsize)
433 {
434 struct convdata_sox *cd = (struct convdata_sox *)convdata;
435 if (cd->converting) {
436 gpointer p;
437 guint ns,frames;
438 gint i;
439 frames = bufsize / cd->convert_from_format.samplebytes;
440 ns = frames * cd->format.samplebytes;
441 p = g_malloc(ns);
442 i = sox_read_main(cd,p,ns);
443 if (i > 0) {
444 convert_array(p,&(cd->format),buf,&(cd->convert_from_format),
445 i/cd->format.samplesize, cd->dither_mode, NULL);
446 }
447 g_free(p);
448 if (i<=0) return i;
449 return (i / cd->convert_from_format.samplebytes) *
450 cd->format.samplebytes;
451 }
452 return sox_read_main(cd,buf,bufsize);
453 }
454
sox_hasdata(gpointer convdata)455 static gboolean sox_hasdata(gpointer convdata)
456 {
457 struct convdata_sox *cd = (struct convdata_sox *)convdata;
458 if (cd->tmpbuf_size > 0) sox_purge_tmpbuf(cd);
459 if (cd->close_status == 3) return FALSE;
460 if (cd->close_status == 2) return TRUE;
461 return fd_canread(cd->fds[1]);
462 }
463
464 struct convdata_repeat {
465 struct convdata_base b;
466 Ringbuf *databuf;
467 Dataformat format;
468 gchar cursamp[32];
469 gfloat fracpos, ratio;
470 };
471
repeat_new(struct driver_data * driver,gboolean realtime,Dataformat * format,guint32 outrate,int dither_mode)472 static gpointer repeat_new(struct driver_data *driver, gboolean realtime,
473 Dataformat *format, guint32 outrate,
474 int dither_mode)
475 {
476 struct convdata_repeat *data;
477 data = g_malloc(sizeof(*data));
478 data->databuf = ringbuf_new(realtime ? 1024*format->samplebytes :
479 format->samplerate * format->samplebytes);
480 data->fracpos = 1.0;
481 data->ratio = (format->samplerate) / ((gfloat)outrate);
482 memcpy(&(data->format),format,sizeof(Dataformat));
483 return (gpointer)data;
484 }
485
repeat_destroy(gpointer convdata)486 static void repeat_destroy(gpointer convdata)
487 {
488 struct convdata_repeat *data = (struct convdata_repeat *)convdata;
489 ringbuf_free(data->databuf);
490 g_free(data);
491 }
492
repeat_write(gpointer convdata,gpointer buf,guint bufsize)493 static gint repeat_write(gpointer convdata, gpointer buf, guint bufsize)
494 {
495 struct convdata_repeat *data = (struct convdata_repeat *)convdata;
496 if (buf == NULL) return 0;
497 return (gint)ringbuf_enqueue(data->databuf,buf,bufsize);
498 }
499
repeat_read(gpointer convdata,gpointer buf,guint bufsize)500 static gint repeat_read(gpointer convdata, gpointer buf, guint bufsize)
501 {
502 struct convdata_repeat *data = (struct convdata_repeat *)convdata;
503 gchar *p = (gchar *)buf;
504 guint i;
505 gfloat fracpos,ratio;
506 guint samplebytes;
507
508 bufsize -= bufsize % data->format.samplebytes;
509
510 if (data->format.samplerate == data->b.outrate)
511 return ringbuf_dequeue(data->databuf,buf,bufsize);
512
513 i = bufsize;
514 fracpos = data->fracpos;
515 ratio = data->ratio;
516 samplebytes = data->format.samplebytes;
517
518 while (i > 0) {
519 /* Read new sample data */
520 while (fracpos >= 1.0) {
521 if (ringbuf_dequeue(data->databuf,data->cursamp,samplebytes)
522 < samplebytes)
523 goto breakout;
524 fracpos -= 1.0;
525 }
526 /* Write sample data */
527 memcpy(p,data->cursamp,samplebytes);
528 p += samplebytes;
529 i -= samplebytes;
530 fracpos += ratio;
531 }
532 breakout:
533
534 data->fracpos = fracpos;
535 return bufsize - i;
536 }
537
repeat_hasdata(gpointer convdata)538 static gboolean repeat_hasdata(gpointer convdata)
539 {
540 struct convdata_repeat *data = (struct convdata_repeat *)convdata;
541 return (data->fracpos < 1.0 || ringbuf_available(data->databuf));
542 }
543
repeat_set_outrate(gpointer convdata,guint32 outrate)544 static void repeat_set_outrate(gpointer convdata, guint32 outrate)
545 {
546 struct convdata_repeat *data = (struct convdata_repeat *)convdata;
547 data->ratio = (data->format.samplerate) / ((gfloat)outrate);
548 }
549
register_drivers(void)550 static void register_drivers(void)
551 {
552 static int already_run = 0;
553 struct driver_data *d,d2;
554 #ifdef HAVE_LIBSAMPLERATE
555 const char *c;
556 int i;
557 c = NULL;
558 i = 0;
559 #endif
560 if (already_run) return;
561 already_run++;
562
563 #ifdef HAVE_LIBSAMPLERATE
564
565 d2.is_realtime = TRUE;
566 d2.prefers_float = TRUE;
567 d2.new_func = rateconv_src_new;
568 d2.destroy_func = rateconv_src_destroy;
569 d2.write_func = rateconv_src_write;
570 d2.read_func = rateconv_src_read;
571 d2.hasdata_func = rateconv_src_hasdata;
572 d2.set_outrate_func = rateconv_src_set_outrate;
573
574 for (i=0; 1; i++) {
575 c = src_get_name(i);
576 if (c == NULL) break;
577 d = (struct driver_data *)g_malloc(sizeof(*d));
578 memcpy(d,&d2,sizeof(*d));
579 d->name = c;
580 d->id = g_strdup_printf("src%c",i+'1');
581 drivers = g_list_append(drivers,d);
582 realtime_drivers = g_list_append(realtime_drivers,d);
583 }
584
585 #endif
586
587 if (sox_dialog_first_effect() != NULL || program_exists("sox")) {
588
589 d2.is_realtime = FALSE;
590 d2.prefers_float = FALSE;
591 d2.new_func = sox_new;
592 d2.destroy_func = sox_destroy;
593 d2.write_func = sox_write;
594 d2.read_func = sox_read;
595 d2.hasdata_func = sox_hasdata;
596
597 d = (struct driver_data *)g_malloc(sizeof(*d));
598 memcpy(d,&d2,sizeof(*d));
599 d->name = _("(SoX) Simulated analog filtration");
600 d->id = "sox_resample";
601 drivers = g_list_append(drivers,d);
602
603 d = (struct driver_data *)g_malloc(sizeof(*d));
604 memcpy(d,&d2,sizeof(*d));
605 d->name = _("(SoX) Polyphase interpolation");
606 d->id = "sox_polyphase";
607 drivers = g_list_append(drivers,d);
608
609 }
610
611 d = g_malloc(sizeof(*d));
612 d->name = _("Sample repeat/skip (low quality)");
613 d->id = "repeat";
614 d->is_realtime = TRUE;
615 d->prefers_float = FALSE;
616 d->new_func = repeat_new;
617 d->destroy_func = repeat_destroy;
618 d->write_func = repeat_write;
619 d->read_func = repeat_read;
620 d->hasdata_func = repeat_hasdata;
621 d->set_outrate_func = repeat_set_outrate;
622 drivers = g_list_append(drivers,d);
623 realtime_drivers = g_list_append(realtime_drivers,d);
624
625 repeat_driver = d;
626 }
627
rateconv_driver_count(gboolean realtime)628 int rateconv_driver_count(gboolean realtime)
629 {
630 GList *l;
631 register_drivers();
632 l = realtime ? realtime_drivers : drivers;
633 return g_list_length(l);
634 }
635
rateconv_driver_name(gboolean realtime,int index)636 const gchar *rateconv_driver_name(gboolean realtime, int index)
637 {
638 GList *l;
639 struct driver_data *d;
640 register_drivers();
641 l = realtime ? realtime_drivers : drivers;
642 d = (struct driver_data *)g_list_nth_data(l,index);
643 return d->name;
644 }
645
rateconv_driver_id(gboolean realtime,int index)646 const gchar *rateconv_driver_id(gboolean realtime, int index)
647 {
648 GList *l;
649 struct driver_data *d;
650 register_drivers();
651 l = realtime ? realtime_drivers : drivers;
652 d = (struct driver_data *)g_list_nth_data(l,index);
653 return d->id;
654 }
655
rateconv_driver_index(gboolean realtime,const gchar * driver_id)656 int rateconv_driver_index(gboolean realtime, const gchar *driver_id)
657 {
658 GList *l;
659 int i;
660 struct driver_data *d;
661 l = realtime ? realtime_drivers : drivers;
662 for (i=0; l!=NULL; i++,l=l->next) {
663 d = (struct driver_data *)l->data;
664 if (!strcmp(d->id,driver_id)) return i;
665 }
666 return -1;
667 }
668
rateconv_prefers_float(const gchar * driver_id)669 gboolean rateconv_prefers_float(const gchar *driver_id)
670 {
671 GList *l;
672 struct driver_data *d;
673 for (l=drivers; l!=NULL; l=l->next) {
674 d = (struct driver_data *)l->data;
675 if (!strcmp(d->id,driver_id))
676 return d->prefers_float;
677 }
678 return FALSE;
679 }
680
rateconv_new(gboolean realtime,const char * driver_id,Dataformat * format,guint32 outrate,int dither_mode,gboolean passthru)681 rateconv *rateconv_new(gboolean realtime, const char *driver_id,
682 Dataformat *format, guint32 outrate, int dither_mode,
683 gboolean passthru)
684 {
685 GList *l;
686 struct driver_data *d;
687 struct convdata_base *conv;
688 register_drivers();
689
690 /* If desired sample rate is same as input rate, use the repeat
691 * driver, which has special case for this. */
692 if (format->samplerate == outrate && !realtime)
693 driver_id = "repeat";
694
695 l = realtime ? realtime_drivers : drivers;
696 for (; l!=NULL; l=l->next) {
697 d = (struct driver_data *)l->data;
698 if (!strcmp(d->id,driver_id)) {
699 conv = d->new_func(d,realtime,format,(outrate>0)?outrate:44100,dither_mode);
700 if (conv == NULL) return NULL;
701 conv->driver = d;
702 conv->inrate = format->samplerate;
703 conv->outrate = outrate;
704 if (passthru)
705 conv->passthru_buffer =
706 ringbuf_new(16384 - (16384%format->samplebytes));
707 else
708 conv->passthru_buffer = NULL;
709 conv->emptying = FALSE;
710 conv->readcount = conv->writecount = 0;
711 conv->empty_point = 0;
712 return conv;
713 }
714 }
715 return NULL;
716 }
717
rateconv_write(rateconv * conv,void * data,guint bufsize)718 gint rateconv_write(rateconv *conv, void *data, guint bufsize)
719 {
720 struct convdata_base *convdata = (struct convdata_base *)conv;
721 guint i = 0;
722 gint j;
723 if (convdata->passthru_buffer != NULL &&
724 convdata->inrate == convdata->outrate) {
725 i = ringbuf_freespace(convdata->passthru_buffer);
726 if (i < bufsize) bufsize = i;
727 }
728 j = convdata->driver->write_func(conv,data,bufsize);
729 if (j > 0 && i > 0) {
730 g_assert(j <= i);
731 i = ringbuf_enqueue(convdata->passthru_buffer,data,j);
732 g_assert(i == j);
733 }
734 if (j > 0) convdata->writecount += j;
735 return j;
736 }
737
rateconv_read(rateconv * conv,void * data,guint bufsize)738 gint rateconv_read(rateconv *conv, void *data, guint bufsize)
739 {
740 struct convdata_base *convdata = (struct convdata_base *)conv;
741 gint i;
742
743 if (convdata->outrate == 0) {
744 memset(data,0,bufsize);
745 return bufsize;
746 }
747
748 i = convdata->driver->read_func(conv,data,bufsize);
749
750 if (i > 0) {
751
752 convdata->readcount += i;
753 while (convdata->readcount > convdata->outrate) {
754 convdata->readcount -= convdata->outrate;
755
756 if (convdata->empty_point > convdata->outrate)
757 convdata->empty_point -= convdata->outrate;
758 else
759 convdata->empty_point = 0;
760
761 if (convdata->writecount > convdata->inrate)
762 convdata->writecount -= convdata->inrate;
763 else
764 convdata->writecount = 0;
765
766 }
767
768 if (convdata->emptying &&
769 convdata->readcount >= convdata->empty_point)
770 convdata->emptying = FALSE;
771
772 if (convdata->passthru_buffer != NULL &&
773 convdata->inrate == convdata->outrate && !convdata->emptying)
774 return ringbuf_dequeue(convdata->passthru_buffer,data,i);
775
776 }
777 return i;
778 }
779
rateconv_hasdata(rateconv * conv)780 gboolean rateconv_hasdata(rateconv *conv)
781 {
782 struct convdata_base *convdata = (struct convdata_base *)conv;
783 return convdata->driver->hasdata_func(conv);
784 }
785
rateconv_destroy(rateconv * conv)786 void rateconv_destroy(rateconv *conv)
787 {
788 struct convdata_base *convdata = (struct convdata_base *)conv;
789 return convdata->driver->destroy_func(conv);
790 }
791
792 #define FLOAT(x) ((float)x)
793 #define GUINT32(x) ((guint32)x)
794
rateconv_set_outrate(rateconv * conv,guint32 outrate)795 void rateconv_set_outrate(rateconv *conv, guint32 outrate)
796 {
797 struct convdata_base *convdata = (struct convdata_base *)conv;
798 g_assert(convdata->driver->is_realtime);
799 if (outrate > 0)
800 convdata->driver->set_outrate_func(conv,outrate);
801 convdata->outrate = outrate;
802 if (convdata->passthru_buffer != NULL &&
803 convdata->outrate == convdata->inrate) {
804 ringbuf_drain(convdata->passthru_buffer);
805 convdata->emptying = TRUE;
806 convdata->empty_point = GUINT32(FLOAT(convdata->writecount) *
807 (FLOAT(convdata->outrate) /
808 FLOAT(convdata->inrate)));
809 }
810 }
811