Skip to content

Commit f785535

Browse files
committed
Make sox_delete_effect usable and added sox_add_and_delete_effect for convenience
1 parent 8e133d2 commit f785535

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

src/effects.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ int lsx_effect_set_imin(sox_effect_t * effp, size_t imin)
118118
return SOX_SUCCESS;
119119
}
120120

121+
/* Convenience function to avoid having to explicitly free the effect object
122+
(which is not useable after adding it to an effects chain anyway).
123+
This exists because if libsox is dynamically linked on Windows, effects
124+
returned by sox_create_effect() cannot be freed using free() by the
125+
application since they were allocated in the libsox DLL. sox_delete_effect()
126+
cannot be used in the official libsox distribution because it will lead to a
127+
double free. While that is fixed in this fork, the calling code has no way
128+
of knowing that. This is the rationale for this function: the calling
129+
application can check if sox_add_and_delete_effect() exists and use it in
130+
that case, otherwise it can resort to not freeing the sox_effect_t object
131+
and just letting it leak.
132+
*/
133+
int sox_add_and_delete_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out)
134+
{
135+
int result;
136+
result = sox_add_effect(chain, effp, in, out);
137+
sox_delete_effect(effp);
138+
return result;
139+
}
140+
141+
121142
/* Effects table to be extended in steps of EFF_TABLE_STEP */
122143
#define EFF_TABLE_STEP 8
123144

@@ -133,6 +154,8 @@ int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signali
133154
size_t f;
134155
sox_effect_t eff0; /* Copy of effect for flow 0 before calling start */
135156

157+
assert(effp->priv); /* Effect instances cannot be reused */
158+
136159
effp->global_info = &chain->global_info;
137160
effp->in_signal = *in;
138161
effp->out_signal = *out;
@@ -199,14 +222,16 @@ int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signali
199222
chain->effects[chain->length][f] = eff0;
200223
chain->effects[chain->length][f].flow = f;
201224
chain->effects[chain->length][f].priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
202-
if (start(&chain->effects[chain->length][f]) != SOX_SUCCESS) {
225+
}
203226
free(eff0.priv);
227+
effp->priv = NULL; /* At this point, effp->priv is "owned" by the chain */
228+
229+
for (f = 1; f < effp->flows; ++f) {
230+
if (start(&chain->effects[chain->length][f]) != SOX_SUCCESS)
204231
return SOX_EOF;
205232
}
206-
}
207233

208234
++chain->length;
209-
free(eff0.priv);
210235
return SOX_SUCCESS;
211236
}
212237

@@ -541,6 +566,13 @@ void sox_delete_effect(sox_effect_t *effp)
541566
uint64_t clips;
542567
size_t f;
543568

569+
/* If priv is NULL, it means that ownership has been transfered to
570+
the effect chain and we should only free the actual effect struct. */
571+
if (!effp->priv) {
572+
free(effp);
573+
return;
574+
}
575+
544576
if ((clips = sox_stop_effect(effp)) != 0)
545577
lsx_warn("%s clipped %" PRIu64 " samples; decrease volume?",
546578
effp->handler.name, clips);
@@ -550,7 +582,11 @@ void sox_delete_effect(sox_effect_t *effp)
550582
/* May or may not indicate a problem; it is normal if the user aborted
551583
processing, or if an effect like "trim" stopped early. */
552584
effp->handler.kill(effp); /* N.B. only one kill; not one per flow */
553-
for (f = 0; f < effp->flows; ++f)
585+
586+
/* There is always at least one element */
587+
free(effp->priv);
588+
/* More may have been allocated by sox_add_effect */
589+
for (f = 1; f < effp->flows; ++f)
554590
free(effp[f].priv);
555591
free(effp->obuf);
556592
free(effp);

src/sox.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,13 @@ sox_find_effect(
20482048
/**
20492049
Client API:
20502050
Creates an effect using the given handler.
2051+
The returned handle must be closed with sox_delete_effect().
2052+
This can be done as soon as the effect is added to an effects chain.
2053+
NOTE: in the official libsox fork, sox_delete_effect() is broken and
2054+
cannot be used by client code. There, free() should be called
2055+
instead on the returned effect (which will leak memory if the
2056+
effect is not successfully added to an effects chain).
2057+
Use sox_add_and_delete_effect() if it exists to avoid this issue.
20512058
@returns The new effect, or null if not found.
20522059
*/
20532060
LSX_RETURN_OPT
@@ -2123,6 +2130,21 @@ sox_add_effect(
21232130
LSX_PARAM_IN sox_signalinfo_t const * out /**< Output format. */
21242131
);
21252132

2133+
/**
2134+
Client API:
2135+
Adds an effect to the effects chain, returns SOX_SUCCESS if successful.
2136+
The effect is also automatically freed correctly, regardless of the result.
2137+
@returns SOX_SUCCESS if successful.
2138+
*/
2139+
int
2140+
LSX_API
2141+
sox_add_and_delete_effect (
2142+
LSX_PARAM_INOUT sox_effects_chain_t * chain, /**< Effects chain to which effect should be added . */
2143+
LSX_PARAM_INOUT sox_effect_t * eh, /**< Effect to be added. */
2144+
LSX_PARAM_INOUT sox_signalinfo_t * in, /**< Input format. */
2145+
LSX_PARAM_IN sox_signalinfo_t const * out /**< Output format. */
2146+
);
2147+
21262148
/**
21272149
Client API:
21282150
Runs the effects chain, returns SOX_SUCCESS if successful.

0 commit comments

Comments
 (0)