README.osx wasn't easily readable in Finder. Revert back to
[sox.git] / src / pad.c
blob4107fb05c149e7ad450c148c19aa5346ebb44912
1 /* libSoX effect: Pad With Silence (c) 2006 robs@users.sourceforge.net
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #include "sox_i.h"
20 typedef struct {
21 unsigned npads; /* Number of pads requested */
22 struct {
23 char * str; /* Command-line argument to parse for this pad */
24 size_t start; /* Start padding when in_pos equals this */
25 size_t pad; /* Number of samples to pad */
26 } * pads;
28 size_t in_pos; /* Number of samples read from the input stream */
29 unsigned pads_pos; /* Number of pads completed so far */
30 size_t pad_pos; /* Number of samples through the current pad */
31 } priv_t;
33 static int parse(sox_effect_t * effp, char * * argv, sox_rate_t rate)
35 priv_t * p = (priv_t *)effp->priv;
36 char const * next;
37 unsigned i;
39 for (i = 0; i < p->npads; ++i) {
40 if (argv) /* 1st parse only */
41 p->pads[i].str = lsx_strdup(argv[i]);
42 next = lsx_parsesamples(rate, p->pads[i].str, &p->pads[i].pad, 't');
43 if (next == NULL) break;
44 if (*next == '\0')
45 p->pads[i].start = i? SOX_SIZE_MAX : 0;
46 else {
47 if (*next != '@') break;
48 next = lsx_parsesamples(rate, next+1, &p->pads[i].start, 't');
49 if (next == NULL || *next != '\0') break;
51 if (i > 0 && p->pads[i].start <= p->pads[i-1].start) break;
53 if (i < p->npads)
54 return lsx_usage(effp);
55 return SOX_SUCCESS;
58 static int create(sox_effect_t * effp, int argc, char * * argv)
60 priv_t * p = (priv_t *)effp->priv;
61 --argc, ++argv;
62 p->pads = lsx_calloc(p->npads = argc, sizeof(*p->pads));
63 return parse(effp, argv, 1e5); /* No rate yet; parse with dummy */
66 static int start(sox_effect_t * effp)
68 priv_t * p = (priv_t *)effp->priv;
69 unsigned i;
71 parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */
72 p->in_pos = p->pad_pos = p->pads_pos = 0;
73 for (i = 0; i < p->npads; ++i)
74 if (p->pads[i].pad)
75 return SOX_SUCCESS;
76 return SOX_EFF_NULL;
79 static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
80 sox_sample_t * obuf, size_t * isamp, size_t * osamp)
82 priv_t * p = (priv_t *)effp->priv;
83 size_t c, idone = 0, odone = 0;
84 *isamp /= effp->in_signal.channels;
85 *osamp /= effp->in_signal.channels;
87 do {
88 /* Copying: */
89 for (; idone < *isamp && odone < *osamp && !(p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start); ++idone, ++odone, ++p->in_pos)
90 for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = *ibuf++;
92 /* Padding: */
93 if (p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start) {
94 for (; odone < *osamp && p->pad_pos < p->pads[p->pads_pos].pad; ++odone, ++p->pad_pos)
95 for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = 0;
96 if (p->pad_pos == p->pads[p->pads_pos].pad) { /* Move to next pad? */
97 ++p->pads_pos;
98 p->pad_pos = 0;
101 } while (idone < *isamp && odone < *osamp);
103 *isamp = idone * effp->in_signal.channels;
104 *osamp = odone * effp->in_signal.channels;
105 return SOX_SUCCESS;
108 static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
110 priv_t * p = (priv_t *)effp->priv;
111 static size_t isamp = 0;
112 if (p->pads_pos != p->npads && p->in_pos != p->pads[p->pads_pos].start)
113 p->in_pos = SOX_SIZE_MAX; /* Invoke the final pad (with no given start) */
114 return flow(effp, 0, obuf, &isamp, osamp);
117 static int stop(sox_effect_t * effp)
119 priv_t * p = (priv_t *)effp->priv;
120 if (p->pads_pos != p->npads)
121 lsx_warn("Input audio too short; pads not applied: %u", p->npads-p->pads_pos);
122 return SOX_SUCCESS;
125 static int lsx_kill(sox_effect_t * effp)
127 priv_t * p = (priv_t *)effp->priv;
128 unsigned i;
129 for (i = 0; i < p->npads; ++i)
130 free(p->pads[i].str);
131 free(p->pads);
132 return SOX_SUCCESS;
135 sox_effect_handler_t const * lsx_pad_effect_fn(void)
137 static sox_effect_handler_t handler = {
138 "pad", "{length[@position]}", SOX_EFF_MCHAN|SOX_EFF_LENGTH|SOX_EFF_MODIFY,
139 create, start, flow, drain, stop, lsx_kill, sizeof(priv_t)
141 return &handler;