1 /* libSoX repeat effect  Copyright (c) 2004 Jan Paul Schmidt <jps@fundament.org>
2  * Re-write (c) 2008 robs@users.sourceforge.net
3  *
4  * This library is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; either version 2.1 of the License, or (at
7  * your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #include "sox_i.h"
20 
21 typedef struct {
22   unsigned      num_repeats, remaining_repeats;
23   uint64_t      num_samples, remaining_samples;
24   FILE          * tmp_file;
25 } priv_t;
26 
create(sox_effect_t * effp,int argc,char ** argv)27 static int create(sox_effect_t * effp, int argc, char * * argv)
28 {
29   priv_t * p = (priv_t *)effp->priv;
30   p->num_repeats = 1;
31   --argc, ++argv;
32   if (argc == 1 && !strcmp(*argv, "-")) {
33     p->num_repeats = UINT_MAX;
34     return SOX_SUCCESS;
35   }
36   do {NUMERIC_PARAMETER(num_repeats, 0, UINT_MAX - 1)} while (0);
37   return argc? lsx_usage(effp) : SOX_SUCCESS;
38 }
39 
start(sox_effect_t * effp)40 static int start(sox_effect_t * effp)
41 {
42   priv_t * p = (priv_t *)effp->priv;
43   if (!p->num_repeats)
44     return SOX_EFF_NULL;
45 
46   if (!(p->tmp_file = lsx_tmpfile())) {
47     lsx_fail("can't create temporary file: %s", strerror(errno));
48     return SOX_EOF;
49   }
50   p->num_samples = p->remaining_samples = 0;
51   p->remaining_repeats = p->num_repeats;
52   if (effp->in_signal.length != SOX_UNKNOWN_LEN && p->num_repeats != UINT_MAX)
53     effp->out_signal.length = effp->in_signal.length * (p->num_repeats + 1);
54   else
55     effp->out_signal.length = SOX_UNKNOWN_LEN;
56 
57   return SOX_SUCCESS;
58 }
59 
flow(sox_effect_t * effp,const sox_sample_t * ibuf,sox_sample_t * obuf,size_t * isamp,size_t * osamp)60 static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
61     sox_sample_t * obuf, size_t * isamp, size_t * osamp)
62 {
63   priv_t * p = (priv_t *)effp->priv;
64   size_t len = min(*isamp, *osamp);
65   memcpy(obuf, ibuf, len * sizeof(*obuf));
66   if (fwrite(ibuf, sizeof(*ibuf), len, p->tmp_file) != len) {
67     lsx_fail("error writing temporary file: %s", strerror(errno));
68     return SOX_EOF;
69   }
70   p->num_samples += len;
71   *isamp = *osamp = len;
72   return SOX_SUCCESS;
73 }
74 
drain(sox_effect_t * effp,sox_sample_t * obuf,size_t * osamp)75 static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
76 {
77   priv_t * p = (priv_t *)effp->priv;
78   size_t odone = 0, n;
79 
80   *osamp -= *osamp % effp->in_signal.channels;
81 
82   while ((p->remaining_samples || p->remaining_repeats) && odone < *osamp) {
83     if (!p->remaining_samples) {
84       p->remaining_samples = p->num_samples;
85       if (p->remaining_repeats != UINT_MAX)
86         --p->remaining_repeats;
87       rewind(p->tmp_file);
88     }
89     n = min(p->remaining_samples, *osamp - odone);
90     if ((fread(obuf + odone, sizeof(*obuf), n, p->tmp_file)) != n) {
91       lsx_fail("error reading temporary file: %s", strerror(errno));
92       return SOX_EOF;
93     }
94     p->remaining_samples -= n;
95     odone += n;
96   }
97   *osamp = odone;
98   return p->remaining_samples || p->remaining_repeats? SOX_SUCCESS : SOX_EOF;
99 }
100 
stop(sox_effect_t * effp)101 static int stop(sox_effect_t * effp)
102 {
103   priv_t * p = (priv_t *)effp->priv;
104   fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */
105   return SOX_SUCCESS;
106 }
107 
lsx_repeat_effect_fn(void)108 sox_effect_handler_t const * lsx_repeat_effect_fn(void)
109 {
110   static sox_effect_handler_t effect = {"repeat", "[count (1)]",
111     SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY,
112     create, start, flow, drain, stop, NULL, sizeof(priv_t)};
113   return &effect;
114 }
115