PHP-SoX: A Server-Side Audio Effects Processing Extension For PHP Using Libsox/Sound eXchange

For images, we've had ImageMagick; for video, we've had FFMPEG. But never anything for audio editing or filtering. How do you mix audio files, add echo, trim silence, or normalize volume? How can you do server-side editing to allow web development with music and speech?

The full source code for the extension compiled against PHP 8.1 - unstable alpha - is available on Github: https://github.com/devilslane-com/php-sox

What is Sound eXchange (SoX)?

it's not sexy, but it doesn't matter.

SoX, or Sound eXchange, is a powerful command-line utility for Linux, macOS, and Windows that allows you to convert, process, and play audio files. It supports a wide range of audio formats and offers numerous audio processing capabilities. SoX is often referred to as the "Swiss Army knife of audio manipulation" due to its versatility.

Here's an overview of the key aspects of SoX:

  1. Format conversion: SoX can convert audio files between various formats, such as WAV, MP3, Ogg Vorbis, FLAC, and AIFF, among others. It allows you to change parameters like sample rate, bit depth, and number of channels during conversion.

    Full list: 8svx aif aifc aiff aiffc al amb amr-nb amr-wb anb au avr awb caf cdda cdr cvs cvsd cvu dat dvms f32 f4 f64 f8 fap flac fssd gsm gsrt hcom htk ima ircam la lpc lpc10 lu mat mat4 mat5 maud mp2 mp3 nist ogg paf prc pvf raw s1 s16 s2 s24 s3 s32 s4 s8 sb sd2 sds sf sl sln smp snd sndfile sndr sndt sou sox sph sw txw u1 u16 u2 u24 u3 u32 u4 u8 ub ul uw vms voc vorbis vox w64 wav wavpcm wv wve xa xi.
  2. Audio processing: SoX provides a wide range of audio processing features, including volume adjustments, equalization, filtering, compression, and normalization. You can chain multiple processing operations together to achieve complex audio transformations.

    Full list: allpass band bandpass bandreject bass bend biquad chorus channels compand contrast dcshift deemph delay dither divide+ downsample earwax echo echos equalizer fade fir firfit+ flanger gain highpass hilbert input# ladspa loudness lowpass mcompand noiseprof noisered norm oops output# overdrive pad phaser pitch rate remix repeat reverb reverse riaa silence sinc spectrogram speed splice stat stats stretch swap synth tempo treble tremolo trim upsample vad vol
  3. Audio effects: SoX includes numerous built-in audio effects, such as reverb, chorus, pitch shifting, and time stretching. These effects can be applied to audio files to enhance or modify their sound characteristics.
  4. Playback and recording: SoX can play audio files and record audio from various input sources like a microphone or line input. It can also be used as an audio player for scripts or in conjunction with other command-line utilities.
  5. Scripting: Since SoX is a command-line tool, you can use it in shell scripts or batch files to automate audio processing tasks. It can be combined with other command-line utilities to create powerful audio processing pipelines.
  6. Platform compatibility: SoX is available for multiple platforms, including Linux, macOS, and Windows, making it a versatile tool for users working across different operating systems.

libSoX is a library that provides the core functionality of the SoX (Sound eXchange) command-line utility. It allows developers to incorporate SoX's audio processing and conversion capabilities directly into their applications, providing a powerful and flexible API for working with audio data.

Here's an overview of libSoX for someone new to the topic:

Installation: To install libSoX, you can use your platform's package manager. For example, on Ubuntu or Debian-based systems, you can install libsox using the following command:

sudo apt-get install sox libsox-dev

On CentOS or Fedora-based systems, you can use:

sudo yum install sox libsox-devel

For macOS, you can use Homebrew:

brew install sox libsox

Alternatively, you can download the source code from the SoX official website (http://sox.sourceforge.net/) and compile it manually.

  • sox_init(): Initializes the libSoX library. This function must be called before using any other libSoX functions.
  • sox_quit(): Cleans up resources allocated by the library. Call this function when you are done using libSoX.
  • sox_open_read(): Opens an audio file for reading, initializing a sox_format_t structure to represent the file.
  • sox_open_write(): Opens an audio file for writing, initializing a sox_format_t structure to represent the file.
  • sox_read(): Reads samples from an open audio file into a buffer.
  • sox_write(): Writes samples to an open audio file from a buffer.
  • sox_close(): Closes an open audio file and releases associated resources.
  • sox_create_effects_chain(): Creates an effects chain to process audio data.
  • sox_add_effect(): Adds an effect to an effects chain, specifying any required options.
  • sox_flow_effects(): Processes an audio stream through an effects chain, reading from an input file, applying effects, and writing to an output file.
  • sox_delete_effects_chain(): Deletes an effects chain and releases associated resources.

Reference manual: https://sox.sourceforge.net/libsox.html

These functions are the core building blocks for working with audio data using libSoX. There are also many other functions available for specific tasks or to provide additional functionality.

To start using libSoX in your project, include the appropriate header file (sox.h) and link against the libSoX library.

PHP Extensions: Why Not A Package?

In most instances, Composer packages are the way to go. If you wanted to do that with SoX, you'd have to use the same kind of approach as you would with FFMPEG, and fork an external process. That's not scalable.

SoX exposes its functionality through a C library (libsox), and the fastest and easiest way to hook into it is that, rather than using something like Symfony Process.

PHP extensions are written in C.

Install the PHP Development Libraries

First, we need the PHP development headers, which provide tools like phpize you might be familiar with if you've compiled extensions before.

Install a compiler:

  • On Linux, install the build-essential package. For example, on Ubuntu or Debian, use the following command:sudo apt-get install build-essential
  • On Windows, install Visual Studio (e.g., Visual Studio Community Edition) with the C/C++ development components.

Install PHP and its development libraries:

  • On Linux, install the PHP development package using the package manager. For example, on Ubuntu or Debian, use the following command:sudo apt-get install php-dev
  • On Windows, download the PHP binaries and development files from the PHP website (https://windows.php.net/download/). Extract the files to a suitable location on your system.

Install other required libraries and tools, such as autoconf (Linux only), pkg-config, and libtool. On Linux, you can typically use the package manager to install these tools. For example, on Ubuntu or Debian, use the following command:sudo apt-get install gdb autoconf pkg-config libtool

Header File

We start with a standard header file named as we like, such as php_my_extension.h.

#ifndef PHP_MY_EXTENSION_H
#define PHP_MY_EXTENSION_H

#include "php.h"

#define PHP_MY_EXTENSION_VERSION "0.1.0"

extern zend_module_entry my_extension_module_entry;
#define phpext_my_extension_ptr &my_extension_module_entry

#endif // PHP_MY_EXTENSION_H

Configuration Files

To know how to compile it we need an m4 (make) file for Linux, and a w32 file for Windows.

Example config.m4:

PHP_ARG_ENABLE(my_extension, Whether to enable my_extension support,
[  --enable-my-extension           Enable my_extension support])

if test "$PHP_MY_EXTENSION" != "no"; then
  PHP_NEW_EXTENSION(my_extension, my_extension.c, $ext_shared)
fi

Example config.w32:

// Check if the extension is enabled
ARG_ENABLE("my_extension", "Enable my_extension support", "no");

if (PHP_MY_EXTENSION == "yes") {
  EXTENSION("my_extension", "my_extension.c");

  // Add any additional dependencies, include paths, or libraries here
  // ADD_EXTENSION_DEP('my_extension', 'another_extension');
  // ADD_FLAG('CFLAGS_MY_EXTENSION', '/I path/to/include');
  // ADD_FLAG('LDFLAGS_MY_EXTENSION', '/LIBPATH:path/to/lib');
}

Layout Of A Typical PHP Extension

In general, extensions are written in pure C and follow a template mandated by Zend's engine.

Skeleton Structure

#include "php.h" // Include the PHP API header to access PHP functions and macros.

#include "php_my_extension.h" // Include the custom extension's header file.

// Define the extension's functions.
static function_entry my_extension_functions[] = {
    PHP_FE(my_function, NULL) // Declare the extension's functions.
    {NULL, NULL, NULL}        // End of the function list.
};

// Define the module entry.
zend_module_entry my_extension_module_entry = {
    STANDARD_MODULE_HEADER,      // Use the standard module header.
    "my_extension",              // Extension name.
    my_extension_functions,      // Pointer to the function list.
    PHP_MINIT(my_extension),     // MINIT function: called when the extension is loaded.
    PHP_MSHUTDOWN(my_extension), // MSHUTDOWN function: called when the extension is unloaded.
    NULL,                        // RINIT function: called when a request starts.
    NULL,                        // RSHUTDOWN function: called when a request ends.
    NULL,                        // MINFO function: called to display extension information.
    NO_VERSION_YET,              // Extension version.
    STANDARD_MODULE_PROPERTIES   // Use standard module properties.
};

// Declare the ZEND_GET_MODULE macro to export the module entry.
ZEND_GET_MODULE(my_extension)

// MINIT function: called when the extension is loaded.
PHP_MINIT_FUNCTION(my_extension)
{
    // Perform any necessary module initialization.
    return SUCCESS; // Return SUCCESS if the module was initialized successfully.
}

// MSHUTDOWN function: called when the extension is unloaded.
PHP_MSHUTDOWN_FUNCTION(my_extension)
{
    // Perform any necessary module cleanup.
    return SUCCESS; // Return SUCCESS if the module was shut down successfully.
}

// Implement the custom extension's functions.
PHP_FUNCTION(my_function)
{
    // Function implementation goes here.
}

A brief description of each part:

  1. #include "php.h": Include the PHP API header to access PHP functions and macros.
  2. #include "php_my_extension.h": Include the custom extension's header file.
  3. static function_entry my_extension_functions[]: Define an array of function_entry structures that list the extension's functions.
  4. zend_module_entry my_extension_module_entry: Define the module entry, which contains information about the extension, such as its name, version, and functions.
  5. ZEND_GET_MODULE(my_extension): Declare the ZEND_GET_MODULE macro to export the module entry.
  6. PHP_MINIT_FUNCTION(my_extension): Define the MINIT function, which is called when the extension is loaded.
  7. PHP_MSHUTDOWN_FUNCTION(my_extension): Define the MSHUTDOWN function, which is called when the extension is unloaded.
  8. PHP_FUNCTION(my_function): Define the custom extension's functions.

Integrating Other External Libraries As Global Functions

An example integration with Libsox would look something like this, including a fictional argument (foo = bar) to demonstrate how params work:

#ifndef PHP_SOX_H
#define PHP_SOX_H

#include "php.h"
#include "sox.h"

// Declare functions
PHP_FUNCTION(sox_get_version);

// Declare module entry
extern zend_module_entry sox_module_entry;
#define phpext_sox_ptr &sox_module_entry

#endif
#include "php.h" // Include the PHP API header.
#include "sox.h" // Include the libsox header.

#include "php_libsox.h" // Include the custom extension's header file.

// Define the argument information for the PHP function.
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_libsox_version, 0, 0, IS_STRING, 0)
    ZEND_ARG_TYPE_INFO(0, foo, IS_STRING, 0)
ZEND_END_ARG_INFO()

// Define the extension's functions.
static const zend_function_entry libsox_functions[] = {
    PHP_FE(libsox_version, arginfo_libsox_version) // Declare the extension's functions.
    PHP_FE_END                                       // End of the function list.
};

// Define the module entry.
zend_module_entry libsox_module_entry = {
    STANDARD_MODULE_HEADER,      // Use the standard module header.
    "libsox",                    // Extension name.
    libsox_functions,            // Pointer to the function list.
    PHP_MINIT(libsox),           // MINIT function: called when the extension is loaded.
    PHP_MSHUTDOWN(libsox),       // MSHUTDOWN function: called when the extension is unloaded.
    NULL,                        // RINIT function: called when a request starts.
    NULL,                        // RSHUTDOWN function: called when a request ends.
    NULL,                        // MINFO function: called to display extension information.
    NO_VERSION_YET,              // Extension version.
    STANDARD_MODULE_PROPERTIES   // Use standard module properties.
};

// Declare the ZEND_GET_MODULE macro to export the module entry.
ZEND_GET_MODULE(libsox)

// MINIT function: called when the extension is loaded.
PHP_MINIT_FUNCTION(libsox)
{
    // Perform any necessary module initialization.
    return SUCCESS; // Return SUCCESS if the module was initialized successfully.
}

// MSHUTDOWN function: called when the extension is unloaded.
PHP_MSHUTDOWN_FUNCTION(libsox)
{
    // Perform any necessary module cleanup.
    return SUCCESS; // Return SUCCESS if the module was shut down successfully.
}

// Implement the custom extension's functions.
PHP_FUNCTION(libsox_version)
{
    char *foo = "bar";
    size_t foo_len = sizeof("bar") - 1;

    // Parse the optional argument.
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &foo, &foo_len) == FAILURE) {
        return;
    }

    const char *version = sox_version();
    php_printf("foo: %s\n", foo);
    RETURN_STRING(version);
}

The libsox_version function accepts an optional string argument foo with a default value of "bar". The arginfo_libsox_version structure has been added to specify the optional argument and its type. The zend_parse_parameters function is used to parse the optional argument in the PHP_FUNCTION(libsox_version) implementation. The optional argument value is then printed using php_printf before returning the libsox version.

From within PHP, once compiled, we could then call this global function like so:

<?php

// Call the libsox_version() function without any argument.
// It will use the default value 'bar' for the optional parameter $foo.

$version = libsox_version();
echo "LibSoX version: $version\n";

// Call the libsox_version() function with a custom value for the optional parameter $foo.

$custom_foo = "custom_value";
$version = libsox_version($custom_foo);
echo "LibSoX version: $version\n";

Using Classes To Create Objects And Methods

But what if we didn't want global functions, and wanted classes to instantiate? No problem.

#ifndef PHP_SOX_H
#define PHP_SOX_H

#include "php.h"
#include "sox.h"

// Class entry
extern zend_class_entry *sox_ce;

// Declare methods
PHP_METHOD(Sox, getVersion);

// Declare module entry
extern zend_module_entry sox_module_entry;
#define phpext_sox_ptr &sox_module_entry

#endif
// Including necessary headers
#include "php.h"
#include "sox.h"

// Define the class entry
static zend_class_entry *sox_ce;

// Forward declarations for custom object and object handlers
typedef struct _php_sox_object {
    zend_object std;
} php_sox_object;

static zend_object_handlers sox_object_handlers;

// Class methods
PHP_METHOD(Sox, getVersion)
{
    // Fetch the libsox version
    const char *libsox_version = sox_version_info();
    RETURN_STRING(libsox_version);
}

// Define the class methods
static const zend_function_entry sox_methods[] = {
    PHP_ME(Sox, getVersion, NULL, ZEND_ACC_PUBLIC)
    PHP_FE_END
};

// Custom object creation function
static zend_object *sox_object_new(zend_class_entry *ce)
{
    php_sox_object *obj = ecalloc(1, sizeof(php_sox_object) + zend_object_properties_size(ce));
    zend_object_std_init(&obj->std, ce);
    object_properties_init(&obj->std, ce);
    obj->std.handlers = &sox_object_handlers;
    return &obj->std;
}

// Extension initialization and shutdown functions
PHP_MINIT_FUNCTION(sox)
{
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "Sox", sox_methods);
    sox_ce = zend_register_internal_class(&ce);
    sox_ce->create_object = sox_object_new;
    memcpy(&sox_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(sox)
{
    return SUCCESS;
}

PHP_RINIT_FUNCTION(sox)
{
    return SUCCESS;
}

PHP_RSHUTDOWN_FUNCTION(sox)
{
    return SUCCESS;
}

PHP_MINFO_FUNCTION(sox)
{
    php_info_print_table_start();
    php_info_print_table_header(2, "sox support", "enabled");
    php_info_print_table_end();
}

// Module entry
zend_module_entry sox_module_entry = {
    STANDARD_MODULE_HEADER,
    "sox",
    NULL,
    PHP_MINIT(sox),
    PHP_MSHUTDOWN(sox),
    PHP_RINIT(sox),
    PHP_RSHUTDOWN(sox),
    PHP_MINFO(sox),
    PHP_SOX_VERSION,
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_SOX
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(sox)
#endif

Then, to access it from PHP, we would do like so:

<?php

// Create a new Sox object
$sox = new Sox();

// Call the getVersion() method on the Sox object to get the current libsox version
$version = $sox->getVersion();
echo "LibSoX version: $version\n";

Compiling & Installing

From within the directory:

phpize
./configure --enable-sox
make
sudo make install

That will create a .so or .dll file in the new "modules" folder and copy it to your PHP extensions directory specified in php.ini. Simple enable the new extension with extension=sox.so like normal.

Structuring PHP Access To SoX

SoX is a huge program. The documentation is huge:

So the first thing to do is plan and define the functions you are going to create., using the documentation.

PHP_METHOD(Sox, __construct);
PHP_METHOD(Sox, analyze);
PHP_METHOD(Sox, bass);
PHP_METHOD(Sox, chorus);
PHP_METHOD(Sox, compressor);
PHP_METHOD(Sox, concatenate);
PHP_METHOD(Sox, convert);
PHP_METHOD(Sox, delay);
PHP_METHOD(Sox, dither);
PHP_METHOD(Sox, echo);
PHP_METHOD(Sox, eq);
PHP_METHOD(Sox, extract_left);
PHP_METHOD(Sox, extract_right);
PHP_METHOD(Sox, fade);
PHP_METHOD(Sox, filter);
PHP_METHOD(Sox, formats);
PHP_METHOD(Sox, gain);
PHP_METHOD(Sox, load);
PHP_METHOD(Sox, loudness);
PHP_METHOD(Sox, metadata);
PHP_METHOD(Sox, mix);
PHP_METHOD(Sox, noise);
PHP_METHOD(Sox, normalize);
PHP_METHOD(Sox, pad);
PHP_METHOD(Sox, phaser);
PHP_METHOD(Sox, pitch);
PHP_METHOD(Sox, repeat);
PHP_METHOD(Sox, reverb);
PHP_METHOD(Sox, reverse);
PHP_METHOD(Sox, sample_rate);
PHP_METHOD(Sox, sample_size);
PHP_METHOD(Sox, save);
PHP_METHOD(Sox, segment);
PHP_METHOD(Sox, speed);
PHP_METHOD(Sox, splice);
PHP_METHOD(Sox, stretch);
PHP_METHOD(Sox, swap);
PHP_METHOD(Sox, tempo);
PHP_METHOD(Sox, to_mono);
PHP_METHOD(Sox, to_stereo);
PHP_METHOD(Sox, treble);
PHP_METHOD(Sox, tremolo);
PHP_METHOD(Sox, trim);
PHP_METHOD(Sox, vad);
PHP_METHOD(Sox, version);
PHP_METHOD(Sox, visualize);
PHP_METHOD(Sox, volume);

For each of these, you need to define the list of arguments it will receive:

ZEND_BEGIN_ARG_INFO(arginfo_sox_flanger, 0)
    ZEND_ARG_TYPE_INFO(0, delay, IS_DOUBLE, 0)
    ZEND_ARG_TYPE_INFO(0, depth, IS_DOUBLE, 0)
    ZEND_ARG_TYPE_INFO(0, regen, IS_DOUBLE, 0)
    ZEND_ARG_TYPE_INFO(0, width, IS_DOUBLE, 0)
    ZEND_ARG_TYPE_INFO(0, speed, IS_DOUBLE, 0)
    ZEND_ARG_TYPE_INFO(0, shape, IS_STRING, 0)
    ZEND_ARG_TYPE_INFO(0, phase, IS_DOUBLE, 0)
    ZEND_ARG_TYPE_INFO(0, interpolation, IS_STRING, 0)
ZEND_END_ARG_INFO()

And then tell the Zend engine to expose those methods:

static const zend_function_entry sox_methods[] = {
    PHP_ME(Sox, compressor, arginfo_sox_compressor, ZEND_ACC_PUBLIC)
    // etc etc
}

Then for each of the functions, write them out in full:

/********************************************************************************************************************
  NORMALIZE (float $decibels = -1)
********************************************************************************************************************/
PHP_METHOD(Sox, normalize)
{
    double decibels;

    ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_DOUBLE(decibels)
    ZEND_PARSE_PARAMETERS_END();

    php_sox_object *obj = Z_SOX_P(getThis());

    if (!obj->input_file) {
        zend_throw_exception(zend_ce_exception, "No audio file has been loaded.", 0);
        RETURN_FALSE;
    }

    sox_effect_t *eff = sox_create_effect(sox_find_effect("norm"));

    char decibels_str[50];
    snprintf(decibels_str, sizeof(decibels_str), "%lf", decibels);
    char *argv[] = {decibels_str};
    sox_effect_options(eff, 1, argv);
    chain_add_effect(obj, eff);
}

Debugging The Extension

There's no two ways around it, debugging C in general, and particularly PHP's C code, is hell. The Zend engine is useless at providing helpful error messages.

You can use PHP-specific debugging extensions, such as Xdebug or Zend Debugger (https://www.jetbrains.com/help/phpstorm/configuring-zend-debugger.html), to gain insights into the execution of your PHP file. These extensions can provide useful information about function calls, variable values, and execution paths, which can help you identify issues in your PHP extension.

strace

strace is a powerful debugging tool that traces system calls and signals for a given process. It is especially useful for finding issues related to file I/O, network, and inter-process communication. To use strace with your PHP script, run the following command:

strace /usr/local/php-debug/bin/php your_script.php

By default, strace outputs the system calls and their results. You can customize the output using various command-line options. For example, -o to save the output to a file, -e to filter system calls, -t to show timestamps, and -f to follow child processes.

ltrace

ltrace is similar to strace but traces library calls instead of system calls. This tool can be helpful for debugging issues related to library functions used by your PHP extension. To use ltrace with your PHP script, run the following command:

ltrace /usr/local/php-debug/bin/php your_script.php

Like strace, ltrace offers various command-line options to customize the output, such as -o to save the output to a file, -e to filter library calls, and -f to follow child processes.

GNU Debugger (gdb)

To start, you'll need a PHP build with debug symbols enabled. You can either download a debug build or compile PHP from source. To compile PHP from source with debug symbols enabled, use the following commands:

git clone https://github.com/php/php-src.git
cd php-src
./buildconf --force
./configure --enable-debug --disable-inline-optimization --enable-maintainer-zts --prefix=/usr/local/php-debug
make -j$(nproc)
sudo make install

This will install PHP with debug symbols in /usr/local/php-debug.

Compile your PHP extension with debug symbols:

Ensure that your extension also includes debug symbols. Typically, you can achieve this by adding the -g flag to the compiler flags in your extension's configuration or Makefile.

Install gdb:

Ensure that gdb is installed on your system. You can install it using your package manager. For example, on Ubuntu:

sudo apt-get install gdb

Prepare your PHP:

Create a PHP anything that reproduces the issue you're trying to debug with the extension.

Run PHP with gdb:

Start PHP with gdb using the following command, replacing your_script.php with the name of your script:

gdb -ex r --args /usr/local/php-debug/bin/php your_script.php

PHP Implementation & Docs

The full source code for the extension compiled against PHP 8.1 - unstable alpha - is available on Github: https://github.com/devilslane-com/php-sox

Loading & Saving

   // Create a new Sox instance
   $sox = new Sox();

   // Load an audio file
   $sox->load(string $file_path = "path/to/your/input_audio_file.wav");

   // Or load a list to combine together
   $sox->concatenate(array $chunks = ['path/to/audio1.wav', 'path/to/audio2.wav']);

   // Save the processed audio to a file
   $sox->save(string $save_path = "path/to/your/output_audio_file.wav");

Utility Functions

   // Create a new Sox instance
   $sox = new Sox();

   $sox->formats(); // array of supported formats
   $sox->version(); // string of libsox version

   // Load an audio file
   $sox->load(string $file_path = "path/to/your/input_audio_file.wav");

   $sox->analyze(); // array of data from the stat() function in libsox
   $sox->visualize(string $export_image_path = "path/to/your/spectrogram_image.png", int $width = 1024, int $height = 768, array $rgb_values = [100, 20, 56]); // generate a spectrogram with RGB colour values

Chainable Processing

   // Create a new Sox instance
   $sox = new Sox();

   // Load an audio file
   $sox->load(string $file_path = "path/to/your/input_audio_file.wav");

   $sox->bass(float $decibels = 1.0, float $frequency_hz = 400, float $width_hz = 100);
   $sox->chorus(float $gain_in = 1.0, float $gain_out = 0, float $delay_ms = 0, float $decay_ms = 0, float $speed_ms = 0, float $depth_ms = 0);
   $sox->compressor(float $input_gain = 0, float $threshold = 12, float $ratio = 5, float $attack_ms = 10, float $release_ms = 50, string $knee = "soft|hard");
   $sox->concatenate(array $chunks = ['path/to/audio1.wav', 'path/to/audio2.wav']);
   $sox->convert(string $format = "mp3", int $bitrate = 256);
   $sox->delay(float $position_ms = 200, float $delay_time_ms = 500, int $repetitions = 5);
   $sox->dither();
   $sox->echo(float $gain_in = 0, float $gain_out = 0, float $delay_ms = 0, float $decay_ms = 0);
   $sox->eq(float $frequency_hz = 1500, float $width_hz = 100, float $decibels = -3.5);
   $sox->extract_left();
   $sox->extract_right();
   $sox->fade(string $type = "in|out", int $length = 10);
   $sox->filter(string $type = "allpass|bandpass|bankreject|lowpass|highpass", float $frequency_hz = 1000, float $width_hz = 100); 
   $sox->flanger(float $delay_ms = 0, float $depth_ms = 0, float $regeneration_percent = 0, float $width_percent = 0, float $speed_hz = 0, string $shape = "sine|triangle", string $phase_percent, string $interpolation ="linear|quadratic");
   $sox->gain(float $decibels = 1.0);
   $sox->loudness(float $gain = 1.0, float $reference = 0.5);
   $sox->metadata(string $comment = "");
   $sox->mix(array $files = ['audio1.wav', 'audio2.wav']);
   $sox->noise(int $sample_from_ms = 0, int $sample_duration_ms = 10000, float $sensitivity = 0.21);
   $sox->normalize(int $decibels = 0);
   $sox->pad(float $start = 0, float $end = 400);
   $sox->phaser(float $gain_in = 0, float $gain_out = 0, float $delay_ms = 0, float $decay_ms = 0, float $speed_ms = 0);
   $sox->pitch(float $frequency_hz = -31);
   $sox->repeat(int $count = 5);
   $sox->reverb(float $reverberance_percent = 100, float $hf_damping_percent = 100, float $room_scale_percent = 100, float $stereo_depth_percent = 100, float $pre_delay_ms = 0, float $wet_gain_decibels = 0);
   $sox->reverse();
   $sox->sample_rate(int $hertz = 48000);
   $sox->sample_size(int $bits = 16);
   $sox->segment(float $start = 0, float $duration = 10);
   $sox->speed(float $factor = 1.2);
   $sox->splice(float $position = 20);
   $sox->stretch(float $factor = 1.0);
   $sox->swap(); // left/right channels
   $sox->tempo(float $factor = 1.0);
   $sox->to_mono();
   $sox->to_stereo();
   $sox->treble(float $decibels = 2.0, float $frequency_hz = 3500, float $width_hz = 100);
   $sox->tremolo(float $speed_ms = 0, float $depth_ms = 0);
   $sox->trim(float $start = 50, float $duration = 5);
   $sox->vad(float $initial_trim = 0, float $trigger_level = 0.71);
   $sox->volume(float $factor = 1.5);