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
23 struct { char *str
; uint64_t delay
; } *args
;
25 uint64_t delay
, pre_pad
, pad
;
26 size_t buffer_size
, buffer_index
;
27 sox_sample_t
* buffer
;
28 sox_bool drain_started
;
31 static int lsx_kill(sox_effect_t
* effp
)
33 priv_t
* p
= (priv_t
*)effp
->priv
;
36 for (i
= 0; i
< p
->argc
; ++i
)
43 static int create(sox_effect_t
* effp
, int argc
, char * * argv
)
45 priv_t
* p
= (priv_t
*)effp
->priv
;
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, '=');
56 return lsx_usage(effp
);
62 static int stop(sox_effect_t
* effp
)
64 priv_t
* p
= (priv_t
*)effp
->priv
;
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) {
78 if (p
->argc
> effp
->in_signal
.channels
) {
79 lsx_fail("too few input channels");
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");
87 p
->args
[i
].delay
= last_seen
= delay
;
88 if (delay
> max_delay
) {
92 *p
->max_delay
= max_delay
;
95 effp
->out_signal
.length
= effp
->in_signal
.length
!= SOX_UNKNOWN_LEN
?
96 effp
->in_signal
.length
+ max_delay
* effp
->in_signal
.channels
:
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
;
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
);
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
++;
124 *obuf
++ = p
->buffer
[p
->buffer_index
];
125 p
->buffer
[p
->buffer_index
++] = *ibuf
++;
126 p
->buffer_index
%= p
->buffer_size
;
132 static int drain(sox_effect_t
* effp
, sox_sample_t
* obuf
, size_t * osamp
)
134 priv_t
* p
= (priv_t
*)effp
->priv
;
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
143 len
= *osamp
= min(p
->pre_pad
+ p
->delay
+ p
->pad
, *osamp
);
145 for (; p
->pre_pad
&& len
; --p
->pre_pad
, --len
)
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
)
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
)