Merge branch 'ew/pipesz' into pu
[sox/ew.git] / src / delay.c
blob14da6ac112239cf68c7fe4f0ef7462c6a4d14fb0
1 /* libSoX effect: Delay one or more channels (c) 2008 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"
19 #include <string.h>
21 typedef struct {
22 size_t argc;
23 struct { char *str; uint64_t delay; } *args;
24 uint64_t *max_delay;
25 uint64_t delay, pre_pad, pad;
26 size_t buffer_size, buffer_index;
27 sox_sample_t * buffer;
28 sox_bool drain_started;
29 } priv_t;
31 static int lsx_kill(sox_effect_t * effp)
33 priv_t * p = (priv_t *)effp->priv;
34 unsigned i;
36 for (i = 0; i < p->argc; ++i)
37 free(p->args[i].str);
38 free(p->args);
39 free(p->max_delay);
40 return SOX_SUCCESS;
43 static int create(sox_effect_t * effp, int argc, char * * argv)
45 priv_t * p = (priv_t *)effp->priv;
46 unsigned i;
48 --argc, ++argv;
49 p->argc = argc;
50 p->args = lsx_calloc(p->argc, sizeof(*p->args));
51 p->max_delay = lsx_malloc(sizeof(*p->max_delay));
52 for (i = 0; i < p->argc; ++i) {
53 char const * next = lsx_parseposition(0., p->args[i].str = lsx_strdup(argv[i]), NULL, (uint64_t)0, (uint64_t)0, '=');
54 if (!next || *next) {
55 lsx_kill(effp);
56 return lsx_usage(effp);
59 return SOX_SUCCESS;
62 static int stop(sox_effect_t * effp)
64 priv_t * p = (priv_t *)effp->priv;
65 free(p->buffer);
66 return SOX_SUCCESS;
69 static int start(sox_effect_t * effp)
71 priv_t * p = (priv_t *)effp->priv;
72 uint64_t max_delay = 0, last_seen = 0, delay;
73 uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ?
74 effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN;
76 if (effp->flow == 0) {
77 unsigned i;
78 if (p->argc > effp->in_signal.channels) {
79 lsx_fail("too few input channels");
80 return SOX_EOF;
82 for (i = 0; i < p->argc; ++i) {
83 if (!lsx_parseposition(effp->in_signal.rate, p->args[i].str, &delay, last_seen, in_length, '=') || delay == SOX_UNKNOWN_LEN) {
84 lsx_fail("Position relative to end of audio specified, but audio length is unknown");
85 return SOX_EOF;
87 p->args[i].delay = last_seen = delay;
88 if (delay > max_delay) {
89 max_delay = delay;
92 *p->max_delay = max_delay;
93 if (max_delay == 0)
94 return SOX_EFF_NULL;
95 effp->out_signal.length = effp->in_signal.length != SOX_UNKNOWN_LEN ?
96 effp->in_signal.length + max_delay * effp->in_signal.channels :
97 SOX_UNKNOWN_LEN;
98 lsx_debug("extending audio by %" PRIu64 " samples", max_delay);
101 max_delay = *p->max_delay;
102 if (effp->flow < p->argc)
103 p->buffer_size = p->args[effp->flow].delay;
104 p->buffer_index = p->delay = p->pre_pad = 0;
105 p->pad = max_delay - p->buffer_size;
106 p->buffer = lsx_malloc(p->buffer_size * sizeof(*p->buffer));
107 p->drain_started = sox_false;
108 return SOX_SUCCESS;
111 static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
112 sox_sample_t * obuf, size_t * isamp, size_t * osamp)
114 priv_t * p = (priv_t *)effp->priv;
115 size_t len = *isamp = *osamp = min(*isamp, *osamp);
117 if (!p->buffer_size)
118 memcpy(obuf, ibuf, len * sizeof(*obuf));
119 else for (; len; --len) {
120 if (p->delay < p->buffer_size) {
121 p->buffer[p->delay++] = *ibuf++;
122 *obuf++ = 0;
123 } else {
124 *obuf++ = p->buffer[p->buffer_index];
125 p->buffer[p->buffer_index++] = *ibuf++;
126 p->buffer_index %= p->buffer_size;
129 return SOX_SUCCESS;
132 static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
134 priv_t * p = (priv_t *)effp->priv;
135 size_t len;
136 if (! p->drain_started) {
137 p->drain_started = sox_true;
138 p->pre_pad = p->buffer_size - p->delay;
139 /* If the input was too short to fill the buffer completely,
140 flow() has not yet output enough silence to reach the
141 desired delay. */
143 len = *osamp = min(p->pre_pad + p->delay + p->pad, *osamp);
145 for (; p->pre_pad && len; --p->pre_pad, --len)
146 *obuf++ = 0;
147 for (; p->delay && len; --p->delay, --len) {
148 *obuf++ = p->buffer[p->buffer_index++];
149 p->buffer_index %= p->buffer_size;
151 for (; p->pad && len; --p->pad, --len)
152 *obuf++ = 0;
153 return SOX_SUCCESS;
156 sox_effect_handler_t const * lsx_delay_effect_fn(void)
158 static sox_effect_handler_t handler = {
159 "delay", "{position}", SOX_EFF_LENGTH | SOX_EFF_MODIFY,
160 create, start, flow, drain, stop, lsx_kill, sizeof(priv_t)
162 return &handler;