AC4IC is an audio compression algorithm that leverages frame-wise processing and the Fast Fourier Transform (FFT) to remove perceptually redundant information.
Here's how the algorithm generally works. We start by splitting up the input audio samples into tiny frames (e.g. 50 milliseconds each). Then, we apply a window function to each frame so it fades in and out smoothly and to minimize spectral leakage (caused by discontinuities when extending the frame periodically for the FFT). There's also some overlap between frames.
Next, we perform a Fast Fourier Transform on every frame to get its frequency content, after which the top N (e.g. 300) strongest frequencies are selected (while optionally giving more weight to higher frequencies). We then remove frequencies that are too quiet to be heard against the other, stronger frequencies, or frequencies with a magnitude lower than a certain absolute threshold.
We're now left with three arrays, one containing frequencies, the other storing the phases for those frequencies in the same order, and the last one storing their magnitudes.
We sort these arrays by decreasing magnitude, so the magnitude array becomes monotonically decreasing, which means it follows a strictly downwards trend. This is where we can be a little clever and downsample the magnitudes, since our ears don't notice it if the magnitudes aren't exactly precise. Although, in reality, we keep the first few magnitudes intact and only downsample the rest.
To store these values in binary files, we need to encode them. The code contains
several functions for encoding integers, floats, or lists of floats in efficient
ways. Check out encoding.hpp for more details.
The final piece of the puzzle is decompression, which takes in the compressed frames and turns them back into audio samples. It's similar to an Inverse Fourier Transform but works with unordered data. We also need to blend between frames using the window function and normalize according to the sum of the window functions of each frame.
The implementation makes use of parallel loops to distribute frame processing across multiple threads, which massively speeds up compression and decompression on multicore CPUs. The compiler also helps a lot with its auto-vectorization and other low-level optimizations.
At the moment, even old compression algorithms like MP3 are more efficient than AC4IC, but there's no reason it should stay that way. If you have any ideas to improve the algorithm, you are more than welcome to contribute to the project or open issues to suggest better methods.
This project uses CMake as its build system.
Make sure you've installed Git (version control), CMake, the Ninja build system, a text editor or an IDE (like Visual Studio Code), and proper C++ compilers.
On Windows, you can use MSYS2 which comes with the MinGW compilers and a whole lot of other useful tools and libraries.
Note
A basic knowledge of Linux commands is required (cd, mkdir, rm, relative
paths, etc.).
-
Open up a terminal and switch to your development directory. On Windows, you can use Git Bash which is automatically installed when you install Git for Windows.
-
Clone the repository and switch the working directory to it.
git clone https://github.com/bean-mhm/ac4ic.git
cd ac4ic- Create a
builddirectory andcdto it.
# delete if it already exists
rm -rf ./build
mkdir build
cd build- Generate CMake configuration files with Ninja.
# debug mode
cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
# or release mode
cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Release ..You only need to regenerate this in certain cases, like when you add or remove
source files, modify CMakeLists.txt, or switch between debug and release
builds.
- Build & Run.
cmake --build .
./bin/ac4ic