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
21 unsigned npads
; /* Number of pads requested */
23 char * str
; /* Command-line argument to parse for this pad */
24 uint64_t start
; /* Start padding when in_pos equals this */
25 uint64_t pad
; /* Number of samples to pad */
28 uint64_t in_pos
; /* Number of samples read from the input stream */
29 unsigned pads_pos
; /* Number of pads completed so far */
30 uint64_t pad_pos
; /* Number of samples through the current pad */
33 static int parse(sox_effect_t
* effp
, char * * argv
, sox_rate_t rate
)
35 priv_t
* p
= (priv_t
*)effp
->priv
;
38 uint64_t last_seen
= 0;
39 const uint64_t in_length
= argv
? 0 :
40 (effp
->in_signal
.length
!= SOX_UNKNOWN_LEN
?
41 effp
->in_signal
.length
/ effp
->in_signal
.channels
: SOX_UNKNOWN_LEN
);
43 for (i
= 0; i
< p
->npads
; ++i
) {
44 if (argv
) /* 1st parse only */
45 p
->pads
[i
].str
= lsx_strdup(argv
[i
]);
46 next
= lsx_parsesamples(rate
, p
->pads
[i
].str
, &p
->pads
[i
].pad
, 't');
47 if (next
== NULL
) break;
49 p
->pads
[i
].start
= i
? UINT64_MAX
: 0;
51 if (*next
!= '@') break;
52 next
= lsx_parseposition(rate
, next
+1, argv
? NULL
: &p
->pads
[i
].start
,
53 last_seen
, in_length
, '=');
54 if (next
== NULL
|| *next
!= '\0') break;
55 last_seen
= p
->pads
[i
].start
;
56 if (p
->pads
[i
].start
== SOX_UNKNOWN_LEN
)
57 p
->pads
[i
].start
= UINT64_MAX
; /* currently the same value, but ... */
60 /* Do this check only during the second pass when the actual
61 sample rate is known, otherwise it might fail on legal
64 if the rate is, e.g., 48k. */
65 if (i
> 0 && p
->pads
[i
].start
<= p
->pads
[i
-1].start
) break;
69 return lsx_usage(effp
);
73 static int create(sox_effect_t
* effp
, int argc
, char * * argv
)
75 priv_t
* p
= (priv_t
*)effp
->priv
;
78 p
->pads
= lsx_calloc(p
->npads
, sizeof(*p
->pads
));
79 return parse(effp
, argv
, 1e5
); /* No rate yet; parse with dummy */
82 static int start(sox_effect_t
* effp
)
84 priv_t
* p
= (priv_t
*)effp
->priv
;
87 /* Re-parse now rate is known */
88 if (parse(effp
, 0, effp
->in_signal
.rate
) != SOX_SUCCESS
)
91 if ((effp
->out_signal
.length
= effp
->in_signal
.length
) != SOX_UNKNOWN_LEN
) {
92 for (i
= 0; i
< p
->npads
; ++i
)
93 effp
->out_signal
.length
+=
94 p
->pads
[i
].pad
* effp
->in_signal
.channels
;
96 /* Check that the last pad position (except for "at the end")
99 if (i
> 0 && p
->pads
[i
-1].start
== UINT64_MAX
)
102 p
->pads
[i
-1].start
* effp
->in_signal
.channels
103 > effp
->in_signal
.length
)
105 lsx_fail("pad position after end of audio");
110 p
->in_pos
= p
->pad_pos
= p
->pads_pos
= 0;
111 for (i
= 0; i
< p
->npads
; ++i
)
117 static int flow(sox_effect_t
* effp
, const sox_sample_t
* ibuf
,
118 sox_sample_t
* obuf
, size_t * isamp
, size_t * osamp
)
120 priv_t
* p
= (priv_t
*)effp
->priv
;
121 size_t c
, idone
= 0, odone
= 0;
122 *isamp
/= effp
->in_signal
.channels
;
123 *osamp
/= effp
->in_signal
.channels
;
127 for (; idone
< *isamp
&& odone
< *osamp
&& !(p
->pads_pos
!= p
->npads
&& p
->in_pos
== p
->pads
[p
->pads_pos
].start
); ++idone
, ++odone
, ++p
->in_pos
)
128 for (c
= 0; c
< effp
->in_signal
.channels
; ++c
) *obuf
++ = *ibuf
++;
131 if (p
->pads_pos
!= p
->npads
&& p
->in_pos
== p
->pads
[p
->pads_pos
].start
) {
132 for (; odone
< *osamp
&& p
->pad_pos
< p
->pads
[p
->pads_pos
].pad
; ++odone
, ++p
->pad_pos
)
133 for (c
= 0; c
< effp
->in_signal
.channels
; ++c
) *obuf
++ = 0;
134 if (p
->pad_pos
== p
->pads
[p
->pads_pos
].pad
) { /* Move to next pad? */
139 } while (idone
< *isamp
&& odone
< *osamp
);
141 *isamp
= idone
* effp
->in_signal
.channels
;
142 *osamp
= odone
* effp
->in_signal
.channels
;
146 static int drain(sox_effect_t
* effp
, sox_sample_t
* obuf
, size_t * osamp
)
148 priv_t
* p
= (priv_t
*)effp
->priv
;
149 static size_t isamp
= 0;
150 if (p
->pads_pos
!= p
->npads
&& p
->in_pos
!= p
->pads
[p
->pads_pos
].start
)
151 p
->in_pos
= UINT64_MAX
; /* Invoke the final pad (with no given start) */
152 return flow(effp
, 0, obuf
, &isamp
, osamp
);
155 static int stop(sox_effect_t
* effp
)
157 priv_t
* p
= (priv_t
*)effp
->priv
;
158 if (p
->pads_pos
!= p
->npads
)
159 lsx_warn("Input audio too short; pads not applied: %u", p
->npads
-p
->pads_pos
);
163 static int lsx_kill(sox_effect_t
* effp
)
165 priv_t
* p
= (priv_t
*)effp
->priv
;
167 for (i
= 0; i
< p
->npads
; ++i
)
168 free(p
->pads
[i
].str
);
173 sox_effect_handler_t
const * lsx_pad_effect_fn(void)
175 static sox_effect_handler_t handler
= {
176 "pad", "{length[@position]}", SOX_EFF_MCHAN
|SOX_EFF_LENGTH
|SOX_EFF_MODIFY
,
177 create
, start
, flow
, drain
, stop
, lsx_kill
, sizeof(priv_t
)