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