---
title: Posts tagged Command Line Application
canonical: https://0110.be/tags/Command%20Line%20Application
markdown_url: https://0110.be/tags/Command%20Line%20Application.md
page: 0
posts_per_page: 30
total_posts: 10
filters:
  tag: Command Line Application
previous:
next:
---

# Posts tagged Command Line Application

## [A Python wrapper for Olaf - Acoustic fingerprinting in Python](https://0110.be/posts/A_Python_wrapper_for_Olaf_-_Acoustic_fingerprinting_in_Python.md)

- Published: 2023-09-22T00:00:00Z
- Updated: 2023-09-26T08:38:34Z
- Author: Joren
- ID: 526
- Canonical: https://0110.be/posts/A_Python_wrapper_for_Olaf_-_Acoustic_fingerprinting_in_Python

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [UGent](https://0110.be/tags/UGent.md)

<div style="float:right; width:15%;margin-left:10px;margin-bottom:10px">
<center>
<img src="https://0110.be/files/attachments/526/python-wrapping-c.webp" alt="python wrapper" style="width:90%;box-shadow: 0 3px 5px rgba(0, 0, 0, 0.4);" ><br><small>Fig: *Python wrapping C*.</small>

</center>
</div>
I have just released a Python wrapper for the Olaf acoustic fingerprinting library. Olaf is a scalable audio search system based on indexing . Olaf is programmed in C but a wrapper now makes its functionality available in Python.

The python wrapper should make it more accessible for developers to get started with it and makes it compatible with other Python libraries. A few notable libraries are the *[librosa python package for music and audio analysis](https://librosa.org/doc/latest/index.html__),*[nnAudio, A fast GPU audio processing toolbox](https://nnaudio.readthedocs.io/en/latest/intro.html__) and other more general plotting, data processing and machine learning libraries. Despite Python's many flaws, its rich library ecosystem is unmatched.

The associated [GitHub repository](https://github.com/JorenSix/Olaf) contains [documentation on how to use the Olaf python wrapper](https://github.com/JorenSix/Olaf/tree/master/python-wrapper) and also contains examples. The first shows how to index a song into the database and subsequently query the database. The second visualises the event points extracted by Olaf. The figure below shows shows the resulting event points, extracted with Olaf, plotted on a magnitude spectrogram, calculated with Olaf. The spectrogram on top is calculated using librosa and is meant to be very similar to Olaf.

<center>
<img src="https://0110.be/files/attachments/526/olaf-power-spectrum.webp"  alt="Power spectrum" style="width:65%;box-shadow: 0 3px 5px rgba(0, 0, 0, 0.4);" >\
<br><small>Fig: *A power spectrum from librosa and one from Olaf, with event points marked*.</small>

</center>
The wrapper was made with [Python CFFI](https://cffi.readthedocs.io/en/latest/) which works reasonably well. The automatically generated wrapper library support a large part of the C language but it needs a compilation step for each platform. Currently, the instructions assume a POSIX-like system, but technically, the wrapper can also function on Windows, albeit with the potential need for Windows-equivalent instructions in place of certain POSIX ones. The wrapper is wrapped in an easy to use python class called `Olaf.py`:

\`\`\`python\
from olaf import Olaf, OlafCommand\
import librosa

1.  Store the first ten seconds of an audio file\
    audio_file = librosa.ex('choice')\
    Olaf(OlafCommand.STORE,audio_file).do(duration=10.0)

<!-- -->

1.  Query for a part of the same file (with an offset of 7 seconds), but change volume\
    y, sr = librosa.load(audio_file,mono=True, sr=16000,duration=10,offset=7.0)\
    y = y \* 0.8 #change the volume\
    results = Olaf(OlafCommand.QUERY,audio_file).do(y=y)

<!-- -->

1.  We expect a match between the stored and partially overlapping query\
    print(results)\
    \`\`\`


---

## [Is a frequency present in a signal? A C implementation. ](https://0110.be/posts/Is_a_frequency_present_in_a_signal%3F_A_C_implementation._.md)

- Published: 2023-07-27T00:00:00Z
- Updated: 2025-11-29T14:12:30Z
- Author: Joren
- ID: 520
- Canonical: https://0110.be/posts/Is_a_frequency_present_in_a_signal%3F_A_C_implementation._

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [UGent](https://0110.be/tags/UGent.md)

This post is an efficient way to determine whether a predefined frequency is present in a signal. If such an algorithm can be found, it can serve as a basis for a modem. With a modem data is <b>mo</b>dulated and <b>dem</b>odulated at the receiving side. The modulation allows data to be send over a transmission channel.

With the ability to detect the presence of audible frequencies a modem can transform symbols into a combination of frequencies and send data over sound. This is exactly what happens with [DTMF](https://nl.wikipedia.org/wiki/DTMF) in the sound below. DTMF is also used in [the dailup sound](https://www.windytan.com/2012/11/the-sound-of-dialup-pictured.html).

<center>
<audio controls src="https://0110.be/files/attachments/520/DTMF_dialing.ogg" style="width:50%">
</audio>
<small>Audio: dail tone sequence: which numbers are pressed?</small>

</center>
Typically, determining the presence of frequencies in a signal is done with an FFT: an FFT divides a signal into e.g. 512 linearly spaced frequency bands and determines the magnitude of each of these frequencies. The annoying thing is that a probe frequency can be right in between two bands: sample rate, FFT size and the frequency to look for need to be carefully chosen to reliably detect a frequency. Also, it is computationally inefficient to calculate the magnitudes for all frequency bands if *only one band* is actually needed.

Luckily there is an alternative approach which looks like the calculating the FFT but for only one predetermined frequencies. This algorithm is known as the [Goertzel algorithm](https://en.wikipedia.org/wiki/Goertzel_algorithm) and is used in [DTMF dail tone encoding and decoding](https://nl.wikipedia.org/wiki/DTMF). With the standard Goertzel algorithm it is still needed to consider sample rate and the frequency of interest.

Finally there is the "Generalized Goertzel": algorithm. In this version of the algorithm employs a couple of tricks to allow an arbitrary frequency and sample rate while still respecting the [Kotelnikov frequency limit, better known as the Nyquist frequency](https://iopscience.iop.org/article/10.1070/PU2006v049n07ABEH006160/pdf).

Recenlty I needed a piece of ANSI c code to detect the magnitude of an arbitrary frequency for a project. The following is a C implementation of this algorithm. It uses the C support for complex numbers in the `complex.h` header:

````c
#include <math.h>
#include <stddef.h>
#include <complex.h>

float detect_frequency(float frequency_to_detect,
                       float audio_sample_rate,
                       float *audio_block,
                       float *window,
                       size_t audio_block_size) {
    float audio_block_sizef = (float)audio_block_size;
    float indvec = frequency_to_detect / audio_sample_rate * audio_block_sizef;
    float pik_term = 2 * M_PI * indvec / audio_block_sizef;
    float cos_pik_term2 = cosf(pik_term) * 2;

    float s0 = 0;
    float s1 = 0;
    float s2 = 0;

    for (size_t i = 0; i < audio_block_size; i++) {
        // potential improvement: expect windowed samples
        float windowed_audio_sample = window[i] * audio_block[i];
        s0 = windowed_audio_sample + cos_pik_term2 * s1 - s2;
        s2 = s1;
        s1 = s0;
    }

    s0 = cos_pik_term2 * s1 - s2;

    float complex cc = cexpf(0 + -1.0f * pik_term * I);
    float complex neg_s1 = -s1 + 0 * I;
    float complex pos_s0 = s0 + 0 * I;
    float power = cabsf(cc * neg_s1 + pos_s0);

    return power;
}
````

## Demo

Below you can try out the algorithm. You can choose a frequency to detect and a playback frequency. The magnitude of the frequency is reported via the slider. The demo uses a javascript translation of the code above.

<iframe src="https://0110.be/attachment/cors/2023.07.freq_detect/index.html" style="border:none;width:100%">
</iframe>

## Dual-tone Multi-Frequency - DTMF

<div style="float:right">
<iframe src="https://0110.be/attachment/cors/2023.07.freq_detect/dtmf.html" style="border:none;width:23em;height:10em">
</iframe>
<center>
<small>DTMF in the browser.</small>

</center>
</div>
On the right you can find a demo of dual tone frequency modulation and demodulation. A combination of frequencies is played and immediately detected.

The green bars show which frequencies have been detected. If for example 1209 Hz is detected together with 770 Hz then this means that we are looking for the symbol in the first column on the second row. Both the first column and the second row are highlighted in green. At that spot we see `4` so we can decode a `4`. By using 2 combinations of four frequencies a total number of 16 symbols can be encoded.

Note that this code does not simply highlight the button press directly but encodes the symbol in audio, feeds it into an Web Audio API format and decodes audio, the result of the decoding step highlights the row and column detected.


---

## [Olaf: a lightweight, portable audio search system](https://0110.be/posts/Olaf%3A_a_lightweight%2C_portable_audio_search_system.md)

- Published: 2023-07-04T00:00:00Z
- Updated: 2023-07-12T09:52:54Z
- Author: Joren
- ID: 519
- Canonical: https://0110.be/posts/Olaf%3A_a_lightweight%2C_portable_audio_search_system

- Tags: [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [Music Information Retrieval](https://0110.be/tags/Music%20Information%20Retrieval.md), [Research papers](https://0110.be/tags/Research%20papers.md), [UGent](https://0110.be/tags/UGent.md)

<div style="float:right; margin: 8px; width:20%">
<img src="https://0110.be/files/attachments/519/OIG.webp" style="object-fit:contain; width: 100%;" /><small>Fig: Some AI imagining audio search.</small>

</div>
Recently I have published a paper titled [*'Olaf: a lightweight, portable audio search system'*](https://joss.theoj.org/papers/10.21105/joss.05459) in the Journal of Open Source Software (JOSS). The journal is [a 'hack' to circumvent the focus on citable papers](https://www.arfon.org/announcing-the-journal-of-open-source-software) in the academic world: getting recognition for publishing software as a researcher is not straightforward.

Both Ghent University's research output tracking system and Flanders FWO academic profile do not allow to enter software as research output. The focus is still solely on papers, even when custom developed research software has become a fundamental aspect in many research areas. My role is somewhere between that of a 'pure' researcher and that of a [research software engineer](https://www.nature.com/articles/d41586-022-01516-2) which makes this focus on papers quite relevant to me.

The paper aims to make the recent development on [Olaf](https://github.com/JorenSix/Olaf) *'count'*. Thanks to the JOSS review process the Olaf software was improved considerably: CI, unit tests, documentation, containerization,... The paper was a good reason to improve on all these areas which are all too easy to neglect. The paper itself is a short, rather general overview of Olaf:

> "*Olaf stands for **Overly Lightweight Acoustic Fingerprinting** and solves the problem of finding short audio fragments in large digital audio archives. The content-based audio search algorithm implemented in Olaf can identify a short audio query in a large database of thousands of hours of audio using an acoustic fingerprinting technique.*"


---

## [Identifying memory leaks in C](https://0110.be/posts/Identifying_memory_leaks_in_C.md)

- Published: 2023-06-29T00:00:00Z
- Updated: 2025-11-29T14:15:58Z
- Author: Joren
- ID: 517
- Canonical: https://0110.be/posts/Identifying_memory_leaks_in_C

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [UGent](https://0110.be/tags/UGent.md)

<div style="float:right; width:25%;margin-left:10px;margin-bottom:10px">
<center>
<img src="https://0110.be/files/photos/517/memory_leaks.jpeg" alt="Memory leaks" style="width:100%" ><br><small>Fig: Memory leaks.</small>

</center>
</div>
The C programming language is deceptively simple. The syntax is straightforward, C has a limited amount of keywords and a small standard library. The first edition of the classic book 'The C Programming Language' is only about 200 pages. And yet, when programming in C, it is hard to avoid the many exiting footguns: integer type conversions, unchecked indexes and memory leaks can all cause subtle problems. This is part of the appeal of C: shooting yourself in the foot does make you feel alive. Here I want to focus on ways to check for memory leaks for C programs.

Memory leaks come about when memory is claimed but is never released again. If this is done in a loop or during a long running program, the claimed memory adds up and eventually the system may run out of memory. A memory leak is less a problem if a program forgets to free a small amount of memory it only claims once: after program shut down, the operating system reclaims all memory anyhow. However, it does feels very dirty to not clean up after oneself. And I for one, am not a dirty boy.

Another reason to look for memory use and leaks is when you are programming for embedded devices. For these systems memory is very limited: in that world 500kB RAM is considered a massive amount of memory. I have been busy programming a scalable [audio search system called Olaf](https://github.com/JorenSix/Olaf) which targets both traditional computers, embedded systems and browsers (via WebAssembly). It is clear that memory use --- and memory leaks --- need to be kept in check to pull this of.

Now, these memory leaks might not be easy to spot by inspecting the code. There are tools which help to spot memory management problems. One of these is [valgrind](https://valgrind.org/) which is currently not easy to use on Apple system with ARM processors. Luckily there is an alternative which is probably already installed on macOS via the *XCode Command Line Tools* a command line tool aptly called `leaks`. To quote the [apple documentation on leaks](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingLeaks.html), leaks reports:

-   the address of the leaked memory

-   the size of the leak (in bytes)

-   the contents of the leaked buffer

The most straightforward use of `leaks` is to run a program and generate a report after program shutdown. See below to run a memory leak inspection, in this case for the `bin/olaf_c` program which indexes an audio file in a key-value store. For [CI](https://en.wikipedia.org/wiki/Continuous_integration) purposes it is practical to know that `leaks` has an exit status of zero only when no leaks have been found. The exit status can be used in an automated test script to break a build if a leak is detected. The `--quiet` option can be practical in such setting.

```bash
leaks --atExit -- bin/olaf_c store audio.raw audio
```

In the case of Olaf I made a classic mistake: I had called `free()` on hash table but I needed to call the hash table destructor: `hash_table_destroy()` which freed not only the hash table itself but also all memory associated with the hash table entries. After a quick fix the `leaks` command showed no more leaks!

```
leaks Report Version: 4.0, multi-line stacks
Process 35293: 2200395 nodes malloced for 135146 KB
Process 35293: 2200171 leaks for 138371200 total leaked bytes.

STACK OF 1 INSTANCE OF 'ROOT LEAK: ':
5 dyld 0x1a16dbf28 ...
4 olaf_c 0x100db145c main ...
3 olaf_c 0x100db53c8 olaf_...
2 olaf_c 0x100db4400 olaf_...
1 olaf_c 0x100da5788 hash_...
0 libsystem_malloc.dylib 0x1a1874d88 _mall...

2200171 (132M) ROOT LEAK:  [64]
2200170 (132M)  [50348032]
2 (80 bytes)  [32]
1 (48 bytes)  [48]
```

<center style="margin-top:-1.5em">
<small>Output of the `leaks` command which shows where a memory leak can be found.</small>

</center>
<br>

## General takaways

-   `leaks` is an easy to use memory leak inspector provided by Apple. It is an alternative for valgrind.

-   Memory leaks can be checked automatically using the `leaks` exit status in a CI-script. This makes spotting leaks timely and more straightforward to fix.

-   Programmers should at least once try to target embedded devices. It makes you conscious of the wealth of resources available when targeting modern computing devices.

<br><br>


![Memory leeks](https://0110.be/files/photos/517/memory_leaks.jpeg)

![Programming in C](https://0110.be/files/photos/517/programming_in_c.jpeg)

![Programming on C](https://0110.be/files/photos/517/programming_on_c.jpeg)

---

## [Optimizing C code with profiling, algorithmic optimizations and 'ChatGPT SIMD'](https://0110.be/posts/Optimizing_C_code_with_profiling%2C_algorithmic_optimizations_and_%27ChatGPT_SIMD%27.md)

- Published: 2023-06-26T00:00:00Z
- Updated: 2025-11-29T14:17:26Z
- Author: Joren
- ID: 518
- Canonical: https://0110.be/posts/Optimizing_C_code_with_profiling%2C_algorithmic_optimizations_and_%27ChatGPT_SIMD%27

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [Music Information Retrieval](https://0110.be/tags/Music%20Information%20Retrieval.md), [UGent](https://0110.be/tags/UGent.md)

This post details how I went about optimizing a C application. This is about an audio search system called [Olaf](https://github.com/JorenSix/Olaf) which was made about **10 times faster** but contains some generally applicable steps for optimizing C code or even other systems. Note that it is not the aim to provide a detailed how-to: I want to provide the reader with a more high-level understanding and enough keywords to find a good how-to for the specific tool you might want to use. I see a few general optimization steps:

<ol start="0">
<li>
The zeroth step of optimization is to properly **question the need** and balance the potential performance gains against added code complexity and maintainability.

</li>
<li>
Once ensured of the need, the first step is to **measure the systems performance**. Every optimization needs to be measured and compared with the original state, having automazation helps.

</li>
<li>
Thirdly, the second step is to **find performance bottle necks**, which should give you an idea where optimizations make sense.

</li>
<li>
The third step is to **implement and apply** an optimization and measuring its effect.

</li>
<li>
Lastly, **repeat** steps zero to three until optimization targets are reached.

</li>
</ol>
More specifically, for the [Olaf audio search system](https://github.com/JorenSix/Olaf) there is a need for optimization. Olaf indexes and searches through years of audio so a small speedup in indexing really adds up. So going for the next item on the list above: measure the performance. Olaf by default reports how quickly audio is indexed. It is expressed in the audio duration it can process in a single second: so if it reports `156 times realtime`, it means that 156 seconds of audio can be indexed in a second.

The next step is to find performance bottlenecks. A profiler is a piece of software to find such bottle necks. There are many options [gprof](https://en.wikipedia.org/wiki/Gprof) is a command line solution which is generally available. I am developing on macOS and have XCode available which includes the "Instruments - Time Profiler". Whichever tool used, the result of a profiling session should yield the time it takes to run each functions. For Olaf it is very clear which function needs optimization:

<center>
<img src="https://0110.be/files/attachments/518/olaf_profiler_pre.png" style="width:60%">\
<small>Fig: The results of profiling Olaf in XCode's time profiler. Almost all time is spend in a single function which is the prime target for optimization.</small>

</center>
The function is a *max filter* which is ran many, many times. The implementation is using a naive approach to max filtering. There are more efficient algorithms available. In this case looking into the literature and implementing a more efficient algorithm makes sense. A very practical [paper by Lemire](https://arxiv.org/pdf/cs/0610046.pdf) lists several contenders and the 'van Herk' algorithm hits the sweet spot between being easy to implement and needing only a tiny extra amount of memory. The Lemire paper even comes with [example c max-filters](https://github.com/lemire/runningmaxmin). With only a slight change, [the code fits in Olaf](https://github.com/JorenSix/Olaf/blob/master/src/olaf_max_filter_perceptual_van_herk.c).

After implementing the change two checks need to be done: is the implementation correct and is it faster. Olaf comes with a number of functional and unit checks which provide some assurance of correctness and a built in performance indicator. Olaf improved from processing audio 156 times realtime to 583 times: a couple of times faster.

After running the profiler again, another method came up as the slowest:

````c
//Naive implementation
float olaf_ep_extractor_max_filter_time(float *array, size_t array_size) {
    float max = -10000000;
    for (size_t i = 0; i < array_size; i++) {
        if (array[i] > max) max = array[i];
    }
    return max;
}
````

<small style="display:block;text-align:center;margin-top: -1.5em;">src: naive implementation of finding the max value of an array.</small>

This is another part of the 2D max filter used in Olaf. Unfortunately here it is not easy to improve the algorithmic complexity: to find the maximum in a list, each value needs to be checked. It is however a good contender for [SIMD](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data) optimization. With SIMD multiple data elements are processed in a single CPU instruction. With 32bit floats it can be possible to process 4 floats in a single step, potentially leading to a 4x speed increase - without including overhead by data loading.

Olaf targets microcontrollers which run an ARM instruction set. The SIMD version that makes most sense is the ARM Neon set of instructions. Apple Sillicon also provides support for ARM Neon which is a nice bonus. I asked ChatGPT to provide a ARM Neon improved version and it came up with the code below. Note that these type of simple functions are ideal for ChatGPT to generate since it is easily testable and there must be many similar functions in the ChatGPT training set. Also there are less ethical issues with 'trivial' functions: more involved code has a higher risk of plagiarization and improper attribution. The new average audio indexing speed is 832 times realtime.


````c
#if defined(__ARM_NEON)
#include <arm_neon.h>
// ARM NEON implementation
float olaf_ep_extractor_max_filter_time(float *array, size_t array_size) {
    assert(array_size % 4 == 0);
    float32x4_t vec_max = vld1q_f32(array);
    for (size_t j = 4; j < array_size; j += 4) {
        float32x4_t vec = vld1q_f32(array + j);
        vec_max = vmaxq_f32(vec_max, vec);
    }
    float32x2_t max_val = vpmax_f32(vget_low_f32(vec_max), vget_high_f32(vec_max));
    max_val = vpmax_f32(max_val, max_val);
    return vget_lane_f32(max_val, 0);
}
#else
//Naive implementation
#endif
````

<small style="display:block;text-align:center;margin-top: -1.5em;">src: a ARM Neon SIMD implementation of a function finding the max value of an array, generated by ChatGPT, licence unknown, informed consent unclear, correct attribution impossible.</small>

Next, I asked ChatGPT for an SSE SIMD version targeting the x86 processors but this resulted in noticable *slowdown*. This might be related to the time it takes to load small vectors in SIMD registers. I did not pursue the SIMD SSE optimization since it is less relevant to Olaf and the first performance optimization was the most significant.

Finally, I went over the code again to see whether it would be possible exit a loop and simply skip calling `olaf_ep_extractor_max_filter_time` in most cases. I found a **condition which prevents most of the calls** without affecting the total results. This proved to be the most significant speedup: almost doubling the speed from about 800 times realtime to around 1500 times realtime. This is actually what I should have done before resorting to SIMD.

In the end Olaf was made about **ten times faster** with only two local, testable, targeted optimizations.

<br>

## General takeways

-   Only think about optimization **if there is a need** and set a target: otherwise it is infinite.

-   Try to **find a balance** between complexity, maintainability and performance.

-   Changing **a naive algorithm to a more intelligent one** can have a significant performance increase. Check the literature for inspiration.

-   Check for conditions to skip hot code paths **before trying fancy optimization** techniques.

-   **Profilers** are crucial to identify where to optimize your code. Applying optimizations blindly is a waste of time.

-   Try to keep optimizations **local and testable**. Sprinkling your code with small, hard to test performance oriented improvements might not be worthwile.

-   **SIMD generated by ChatGPT** can be a very quick way to optimize critical, hot code paths. I would advise to only let ChatGPT generate small, common, easily testable code: e.g. finding the maximum in an array.

-   Having only localized 'trivial' ChatGPT parts means you can **take them out** once it is clear that [you have copied code without proper attribution or licensing](https://www.reuters.com/technology/google-one-ais-biggest-backers-warns-own-staff-about-chatbots-2023-06-15/).

-   The **use of SIMD can slow down** your code if you are not careful, measure the effects of your 'optimizations'!

<br>


![Pre optimization, a single method takes most of the time.](https://0110.be/files/photos/518/olaf_profiler_pre.png)

![After optimization, a new method takes most time.](https://0110.be/files/photos/518/olaf_profiler_post.png)

---

## [An audio focused ffmpeg build for the web](https://0110.be/posts/An_audio_focused_ffmpeg_build_for_the_web.md)

- Published: 2022-02-24T00:00:00Z
- Updated: 2025-11-29T14:24:41Z
- Author: Joren
- ID: 488
- Canonical: https://0110.be/posts/An_audio_focused_ffmpeg_build_for_the_web

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [UGent](https://0110.be/tags/UGent.md)

I have prepared **an audio focused ffmpeg build for the web** which facilitates browser based audio applications. I have prepared three demos:

1.  [Audio transcoding and playback demo](https://0110.be/attachment/cors/ffmpeg.audio.wasm/transcode.html): converts any media file into audio compatible with the Web Audio API for in-browser playback or analysis.
2.  [High quality time-stretching or pitch-shifting](https://0110.be/attachment/cors/ffmpeg.audio.wasm/pitch_speed_tempo_mod.html): demonstrates how pitch and tempo can be modified independently thanks to the [Rubber Band Library](https://breakfastquay.com/rubberband/audio).
3.  [Basic media info](https://0110.be/attachment/cors/ffmpeg.audio.wasm/basic_media_info.html): gives information about the streams and encodings used in a media file.

<center>
<img src="https://0110.be/files/attachments/488/screen_recording_small.apng" /><br>
<small>Fig: [audio transcodinging in the browser](https://0110.be/attachment/cors/ffmpeg.audio.wasm/transcode.html). A `wav` file is converted to an `mp3`.</small>

</center>
A bit more about the rationale behind this effort: Browsers have become practical platforms for audio processing applications thanks to the combination of [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) , performant Javascript environment and [WebAssembly](https://webassembly.org/). Have a look, for example, at [essentia.JS](https://mtg.github.io/essentia.js).

However, browsers only support a small subset of audio formats and container formats. Dealing with many (legacy) audio formats is often a rather painful experience since there are so many media container formats which can contain a surprising variation of audio (and video) encodings. In short, decoding audio for in-browser analysis or playback is often problematic.

Luckily there is [FFmpeg](https://ffmpeg.org) which claims to be *'a complete, cross-platform solution to record, convert and stream audio and video'*. It is, indeed, capable to decode almost any audio encoding known to man from about any container. Additionally, it also contains tools to filter, manipulate, resample, stretch, ... audio. FFmpeg is a must-have when working with audio. It would be ideal to have FFmpeg running in a browser...

Thanks to [WebAssembly](https://webassembly.org/) ffmpeg can be compiled for use in the browser. There have been [efforts](https://github.com/ffmpegwasm/ffmpeg.wasm-core) [to](https://github.com/ffmpegwasm/ffmpeg.wasm) [get](https://github.com/wide-video/ffmpeg-wasm) ffmpeg working in the browser. These efforts have been focusing on the complete ffmpeg suite. Now I have prepared **an audio focused ffmpeg build for the web** based on these efforts. I have selected only audio parts which makes the resulting .wasm binary four to five times smaller (from \~20MB to \~5MB). I also provided a simplified Javascript wrapper. The project brings audio decoding to the browser but also audio filtering, transcoding, pitch-shifting, sample rate conversions, audio channel manipulation, and so forth. It is also capable to extract audio streams from video container formats.

Next to the pure functionality of ffmpeg there are general advantages to run audio analysis software in the browser at client-side:

-   **Ease-of-use**: no software needs to be installed. The runtime comes with a compatible browser.
-   **Privacy**: Since media files are not transferred it is impossible for the system running the service to make unauthorised copies of these files. There is no need to trust the service since all processing happens locally, in the browser.
-   **Speed**: Downloading and especially uploading large media files takes a while. When files are kept locally, processing can start immediately and no time is wasted sending bytes over the internet. This results in a snappy user experience.
-   **Computational load**: the computational load of transcoding is distributed over the clients and not centralised on a (single) server. The server does not do any computing and only serves static files, so it can handle as many concurrent clients as its bandwidth allows.

Check out the [audio focused ffmpeg build for the web](https://github.com/JorenSix/ffmpeg.audio.wasm) on GitHub.


---

## [ISMIR 2020 - Virtual Conference](https://0110.be/posts/ISMIR_2020_-_Virtual_Conference.md)

- Published: 2020-10-20T00:00:00Z
- Updated: 2025-11-29T14:33:11Z
- Author: Joren
- ID: 477
- Canonical: https://0110.be/posts/ISMIR_2020_-_Virtual_Conference

- Tags: [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [Presentation](https://0110.be/tags/Presentation.md), [UGent](https://0110.be/tags/UGent.md)

<img style="float:right;margin:5px" alt="ISMIR 2020 Logo" src="https://0110.be/files/attachments/477/ISMIR2020-logo.png">

From 11-16 October 2020 the latest instalment of the ISMIR conference series was held. Due to the pandemic, the 21st ISMIR conference was the first virtual one. As usual, participants and presenters from around the world joined the conference. For the first time, however, not all participants synchronised their circadian rhythm. By repeating most events with 12h in between, the organisers managed to put together a schedule befitting nearly all participants.

The virtual format had some clear advantages: travel was not needed, so (environmental) cost was low. Attendance fees were lower than usual since no spaces or catering was needed. This democratised the conference experience and attendance reached a record high.

The scientific program of the conference was impressive and varied. It is At the conferences Late Breaking/Demo session I presented [Olaf: Overly Lightweight Acoustic Fingerprinting](https://program.ismir2020.net/lbd_418.html).


<center>
<iframe width="480" height="280" src="https://www.youtube.com/embed/wP29RaQicwE" frameborder="0" allow="picture-in-picture" allowfullscreen>
</iframe>
</center>



---

## [Pitch Shifting - Implementation in Pure Java with Resampling and Time Stretching](https://0110.be/posts/Pitch_Shifting_-_Implementation_in_Pure_Java_with_Resampling_and_Time_Stretching.md)

- Published: 2012-11-05T00:00:00Z
- Updated: 2020-11-17T09:07:53Z
- Author: Joren
- ID: 370
- Canonical: https://0110.be/posts/Pitch_Shifting_-_Implementation_in_Pure_Java_with_Resampling_and_Time_Stretching

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [HoGent](https://0110.be/tags/HoGent.md), [Java](https://0110.be/tags/Java.md), [TarsosDSP](https://0110.be/tags/TarsosDSP.md), [WSOLA](https://0110.be/tags/WSOLA.md), [featured](https://0110.be/tags/featured.md)

The DSP library for Taros, aptly named TarsosDSP, now includes an implementation of a *pitch shifting algorithm* (as of version 1.4). The goal of pitch shifting is to change the pitch of a piece of audio without affecting the duration. The algorithm implemented is a combination of resampling and time stretching. Resampling changes the pitch of the audio, but affects the total duration. Consecutively, the duration of the audio is stretched to the original (without affecting pitch) with time stretching. The result is very similar to [phase vocoding](http://en.wikipedia.org/wiki/Phase_vocoder).

The example application below shows how to pitch shift input from the microphone in real-time, or pitch shift a recorded track with the TarsosDSP library.

<div align="center">
<a href="https://0110.be/releases/TarsosDSP/TarsosDSP-1.4/TarsosDSP-1.4-Examples/PitchShift-1.4.jar"><img src="https://0110.be/files/attachments/370/pitch-shift-in-java.png" alt="Pitch shifting in Java"/></a>

</div>
To test the application, download and execute the [PitchShift.jar](https://0110.be/releases/TarsosDSP/TarsosDSP-latest/TarsosDSP-latest-Examples/PitchShift-latest.jar) file and load an audio file. For the moment only 44.1kHz mono wav is allowed. To get started you can try "this piece of audio":\[08.\_Ladrang_Kandamanyura_10s-20s.wav\].

There is also a command line interface, the following command lowers the pitch of `in.wav` by two semitones.

    java -jar in.wav out.wav -200

    ----------------------------------------------------
     _______                       _____   _____ _____  
    |__   __|                     |  __ \ / ____|  __ \ 
       | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
       | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
       | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
       |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     

    ----------------------------------------------------
    Name:
        TarsosDSP Pitch shifting utility.
    ----------------------------------------------------
    Synopsis:
        java -jar PitchShift.jar source.wav target.wav cents
    ----------------------------------------------------
    Description:
        Change the play back speed of audio without changing the pitch.

            source.wav  A readable, mono wav file.
            target.wav  Target location for the pitch shifted file.
            cents       Pitch shifting in cents: 100 means one semitone up, 
                    -100 one down, 0 is no change. 1200 is one octave up.

The resampling feature was implemented with libresample4j by Laszlo Systems. libresample4j is a Java port of Dominic Mazzoni's libresample 0.1.3, which is in turn based on Julius Smith's Resample 1.7 library.


- [pitch-shift-in-java.png](https://0110.be/files/attachments/370/pitch-shift-in-java.png)

- [08.\_Ladrang\_Kandamanyura\_10s-20s.wav](https://0110.be/files/attachments/370/08._Ladrang_Kandamanyura_10s-20s.wav)

---

## [TarsosDSP Release 1.0](https://0110.be/posts/TarsosDSP_Release_1.0.md)

- Published: 2012-04-24T14:25:32Z
- Updated: 2013-12-05T18:19:15Z
- Author: Joren
- ID: 352
- Canonical: https://0110.be/posts/TarsosDSP_Release_1.0

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [HoGent](https://0110.be/tags/HoGent.md), [Java](https://0110.be/tags/Java.md), [Music Information Retrieval](https://0110.be/tags/Music%20Information%20Retrieval.md), [TarsosDSP](https://0110.be/tags/TarsosDSP.md), [WSOLA](https://0110.be/tags/WSOLA.md), [featured](https://0110.be/tags/featured.md)

After about a year of development and several revisions TarsosDSP has enough features and is stable enough to slap the 1.0 tag onto it. A 'read me', manual, API documentation, source and binaries can be found on the [TarsosDSP release directory](http://tarsos.0110.be/releases/TarsosDSP/). The source is present in the\
What follows below is the information that can be found in the read me file:

<p>
TarsosDSP is a collection of classes to do simple audio processing. It features an implementation of a percussion onset detector and two pitch detection algorithms: Yin and the Mcleod Pitch method. Also included is a Goertzel <acronym title="Dual tone multi frequency"><span class="caps">DTMF</span></acronym> decoding algorithm and a time stretch algorithm (<span class="caps">WSOLA</span>).

</p>
<p>
Its aim is to provide a simple interface to some audio (signal) processing algorithms implemented in pure <span class="caps">JAVA</span>. Some <a href="http://tarsos.0110.be/tag/TarsosDSP">TarsosDSP example applications</a> are available.

</p>
<p>
The following example filters a band of frequencies of an input file <code>testFile</code>. It keeps the frequencies form <code>startFrequency</code> to <code>stopFrequency</code>.

</p>
    <code>AudioInputStream inputStream = AudioSystem.getAudioInputStream(testFile);
    AudioDispatcher dispatcher = new AudioDispatcher(inputStream,stepSize,overlap);
    dispatcher.addAudioProcessor(new HighPass(startFrequency, sampleRate, overlap));
    dispatcher.addAudioProcessor(new LowPassFS(stopFrequency, sampleRate, overlap));
    dispatcher.addAudioProcessor(new FloatConverter(format));
    dispatcher.addAudioProcessor(new WaveformWriter(format,stepSize, overlap, "filtered.wav"));
    dispatcher.run();
    </code>

<h3>
Quickly Getting Started with TarsosDSP

</h3>
<p>
Head over to the <a href="http://tarsos.0110.be/releases/TarsosDSP/">TarsosDSP release repository</a> and download the latest <a href="http://tarsos.0110.be/releases/TarsosDSP/TarsosDSP-1.0.jar">TarsosDSP library</a>. To get up to speed quickly, check the <a href="http://tarsos.0110.be/releases/TarsosDSP/TarsosDSP-1.0-Examples/">TarsosDSP Example applications</a> for inspiration and consult the <a href="http://tarsos.0110.be/releases/TarsosDSP/TarsosDSP-1.0-Documentation/"><span class="caps">API</span> documentation</a>. If you, for some reason, want to build from source, you need <a href="http://ant.apache.org/">Apache Ant</a> and <a href="http://git-scm.com/">git</a> installed on your system. The following commands fetch the source and build the library and example jars: <br />

    <code>git clone https://JorenSix@github.com/JorenSix/TarsosDSP.git
    cd TarsosDSP/build
    ant tarsos_dsp_library #Builds the core TarsosDSP library
    ant build_examples #Builds all the TarsosDSP examples
    ant javadoc #Creates the documentation in TarsosDSP/doc
    </code>

<br />\
When everything runs correctly you should be able to run all example applications and have the latest version of the TarsosDSP library for inclusion in your projects. Also the Javadoc documentation for the <span class="caps">API</span> should be available in TarsosDSP/doc. Drop me a line if you use TarsosDSP in your project. Always nice to hear how this software is used.

</p>
<h3>
Source Code Organization and Examples of TarsosDSP

</h3>
<p>
The source tree is divided in three directories:

</p>
<ul>
<li>
<code>src</code> contains the source files of the core <span class="caps">DSP</span> libraries.

</li>
<li>
<code>test</code> contains unit tests for some of the <span class="caps">DSP</span> functionality.

</li>
<li>
<code>build</code> contains <span class="caps">ANT</span> build files. Either to build Java documentation or runnable <span class="caps">JAR</span>-files for the example applications.

</li>
<li>
<code>examples</code> contains a couple of example applications with a Java Swing user interface:

<ul>
<li>
<a href="http://tarsos.0110.be/artikels/lees/TarsosDSP%253A_a_small_JAVA_audio_processing_library">SoundDetector</a> show how you loudness calculations can be done. When input sound is over a defined limit an event is fired.

</li>
<li>
<a href="http://tarsos.0110.be/artikels/lees/TarsosDSP%253A_a_small_JAVA_audio_processing_library">PitchDetector</a> this demo application shows real-time pitch detection. When pitch is detected the hertz value is printed together with a probability.

</li>
<li>
<a href="http://tarsos.0110.be/artikels/lees/TarsosDSP%253A_a_small_JAVA_audio_processing_library">PercussionDetector</a> show the percussion (onset) dectection. Clapping your hands causes an event. This demo application also shows the influence of the two parameters on the algorithm.

</li>
<li>
<a href="http://tarsos.0110.be/artikels/lees/TarsosDSP_sample_application%253A_Utter_Asterisk">UtterAsterisk</a> a game with the goal to sing as close to a melody a possible. Technically it shows real-time pitch detection with <span class="caps">YIN</span> or <span class="caps">MPM</span>.

</li>
<li>
<a href="http://tarsos.0110.be/artikels/lees/Spectrogram_in_Java_with_TarsosDSP">Spectrogram in Java</a> shows a spectrogram and detected pitch, either live or from an audio file. It is interesting to see which frequencies are picked as fundamentals.

</li>
<li>
<a href="http://tarsos.0110.be/artikels/lees/Dual-Tone_Multi-Frequency_%2528DTMF%2529_Decoding_with_the_Goertzel_Algorithm_in_Java">Goertzel <acronym title="Dual tone multi frequency"><span class="caps">DTMF</span></acronym> decoding</a> an implementation of the Goertzel Algorithm. A fancy user interface shows what goes on under the hood.

</li>
<li>
<a href="http://tarsos.0110.be/artikels/lees/Audio_Time_Stretching_-_Implementation_in_Pure_Java_Using_WSOLA">Audio Time Stretching -- Implementation in Pure Java Using <span class="caps">WSOLA</span></a> an implementation of a time stretching algorithm. <acronym title="Waveform Similarity Overlap Add"><span class="caps">WSOLA</span></acronym> makes it possible to change the play back speed of audio without changing the pitch. The play back speed can be changed at any moment, even when there is audio playing.

</li>
</ul>
</li>
</ul>


---

## [Tarsos CLI:  Detect Pitch](https://0110.be/posts/Tarsos_CLI%3A__Detect_Pitch.md)

- Published: 2012-02-03T15:00:06Z
- Updated: 2013-12-05T18:19:15Z
- Author: Joren
- ID: 390
- Canonical: https://0110.be/posts/Tarsos_CLI%3A__Detect_Pitch

- Tags: [Code](https://0110.be/tags/Code.md), [Command Line Application](https://0110.be/tags/Command%20Line%20Application.md), [HoGent](https://0110.be/tags/HoGent.md), [Java](https://0110.be/tags/Java.md), [Music Information Retrieval](https://0110.be/tags/Music%20Information%20Retrieval.md), [Tarsos](https://0110.be/tags/Tarsos.md)

<img src="http://tarsos.0110.be/attachment/cons/210/tarsos_logo_small.png"  alt="Tarsos Logo" style="float:right;margin-left:5px;"/>Tarsos contains a couple of useful command line applications. They can be used to execute common tasks on lots of files. [Dowload Tarsos](http://tarsos.0110.be/attachment/tarsos.jar) and call the applications using the following format:

`java -jar tarsos.jar command [argument...] [--option [value]...]`

The first part `java -jar tarsos.jar` tells the Java Runtime to start the correct application. The first argument for Tarsos defines the command line application to execute. Depending on the command, required arguments and options can follow.

`java -jar tarsos.jar detect_pitch in.wav --detector TARSOS_YIN`

To get a list of available commands, type `java -jar tarsos.jar -h`. If you want more information about a command type `java -jar tarsos.jar command -h`

## Detect Pitch

Detects pitch for one or more input audio files using a pitch detector. If a directory is given it traverses the directory *recursively*. It writes CSV data to standard out with five columns. The first is the start of the analyzed window (seconds), the second the estimated pitch, the third the saillence of the pitch. The name of the algorithm follows and the last column shows the original filename.

    Synopsis
    --------
    java -jar tarsos.jar detect_pitch [option] input_file...

    Option                                  Description                            
    ------                                  -----------                            
    -?, -h, --help                          Show help                              
    --detector <PitchDetectionMode>         The detector to use [VAMP_YIN |        
                                              VAMP_YIN_FFT |                       
                                              VAMP_FAST_HARMONIC_COMB |            
                                              VAMP_MAZURKA_PITCH | VAMP_SCHMITT |  
                                              VAMP_SPECTRAL_COMB |                 
                                              VAMP_CONSTANT_Q_200 |                
                                              VAMP_CONSTANT_Q_400 | IPEM_SIX |     
                                              IPEM_ONE | TARSOS_YIN |              
                                              TARSOS_FAST_YIN | TARSOS_MPM |       
                                              TARSOS_FAST_MPM | ] (default:        
                                              TARSOS_YIN) 

The output of the command looks like this:

    Start(s),Frequency(Hz),Probability,Source,file
    0.52245,366.77039,0.92974,TARSOS_YIN,in.wav
    0.54567,372.13873,0.93553,TARSOS_YIN,in.wav
    0.55728,375.10638,0.95261,TARSOS_YIN,in.wav
    0.56889,380.24854,0.94275,TARSOS_YIN,in.wav


---
