Showing posts with label Sound Processing. Show all posts
Showing posts with label Sound Processing. Show all posts

Tuesday, July 25, 2023

Live microphone visualization (waveform) with sounddevice

 *** This post was made by ChatGPT***


Are you interested in visualizing live audio data from your microphone? Do you want to see the waveform of your voice or any other sound in real time? In this blog post, we’ll explore a Python script that utilizes Matplotlib to plot live microphone signals. This script is a useful tool for understanding and analyzing audio input in real time.

Before we begin, make sure you have sounddevice, Matplotlib, and NumPy installed. If not, you can install them using the following command:

pip install matplotlib numpy sounddevice

Now, let’s dive into the code and see how it works.

The Code

#!/usr/bin/env python3
"""Plot the live microphone signal(s) with matplotlib.

Matplotlib and NumPy have to be installed.

"""
import argparse
import queue
import sys

from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import sounddevice as sd

The script starts with the usual shebang (#!/usr/bin/env python3) and a brief docstring explaining the purpose of the code. It also imports the necessary modules: argparse, queue, sys, FuncAnimation from matplotlib.animation, plt (alias for matplotlib.pyplot), numpy, and sounddevice.

Next, the code defines two helper functions and two main functions.

def int_or_str(text):
    """Helper function for argument parsing."""
    try:
        return int(text)
    except ValueError:
        return text


def audio_callback(indata, frames, time, status):
    """This is called (from a separate thread) for each audio block."""
    if status:
        print(status, file=sys.stderr)
    # Fancy indexing with mapping creates a (necessary!) copy:
    q.put(indata[::args.downsample, mapping])

The int_or_str function is a helper used for parsing command-line arguments. It tries to convert the input text to an integer and returns it if successful; otherwise, it returns the input text as it is.

The audio_callback function is called for each audio block received from the microphone. It receives indata (the audio data), frames (the number of frames), time (the timestamp of the audio data), and status (the status of the audio stream). It prints any status messages to the standard error and puts a copy of the audio data (filtered using downsampling and channel mapping) into a queue (q) for processing later.

def update_plot(frame):
    """This is called by matplotlib for each plot update.

    Typically, audio callbacks happen more frequently than plot updates,
    therefore the queue tends to contain multiple blocks of audio data.

    """
    global plotdata
    while True:
        try:
            data = q.get_nowait()
        except queue.Empty:
            break
        shift = len(data)
        plotdata = np.roll(plotdata, -shift, axis=0)
        plotdata[-shift:, :] = data
    for column, line in enumerate(lines):
        line.set_ydata(plotdata[:, column])
    return lines

The update_plot function is called by Matplotlib for each plot update. It retrieves audio data from the queue (q) and shifts the existing data to accommodate the new audio block. The function then updates the y-data of the lines on the plot with the new audio data.

if __name__ == "__main__":
    # ... (continued in the next code block)

The script uses the standard Python if __name__ == "__main__": guard to ensure that the following code is only executed when the script is run directly, not when it’s imported as a module.

    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument(
        '-l', '--list-devices', action='store_true',
        help='show list of audio devices and exit')
    args, remaining = parser.parse_known_args()
    if args.list_devices:
        print(sd.query_devices())
        parser.exit(0)

The code sets up an argument parser with argparse to handle command-line arguments. It allows the user to list available audio devices and exit the program without running the main functionality. If the user specifies the --list-devices flag, the script will print a list of audio devices using sd.query_devices() and then exit.

    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        parents=[parser])
    parser.add_argument(
        'channels', type=int, default=[1], nargs='*', metavar='CHANNEL',
        help='input channels to plot (default: the first)')
    parser.add_argument(
        '-d', '--device', type=int_or_str,
        help='input device (numeric ID or substring)')
    parser.add_argument(
        '-w', '--window', type=float, default=200, metavar='DURATION',
        help='visible time slot (default: %(default)s ms)')
    parser.add_argument(
        '-i', '--interval', type=float, default=30,
        help='minimum time between plot updates (default: %(default)s ms)')
    parser.add_argument(
        '-b', '--blocksize', type=int, help='block size (in samples)')
    parser.add_argument(
        '-sr', '--samplerate', type=float, default=16000, help='sampling rate of audio device')
    parser.add_argument(
        '-n', '--downsample', type=int, default=1, metavar='N',
        help='No downsample (default: %(default)s)')
    args = parser.parse_args(remaining)

The script creates another argument parser, this time with a description based on the script’s docstring. It defines several command-line arguments:

  • channels: The channels to plot. If not specified, it will default to the first channel.
  • device: The input audio device to use. It can be specified either by a numeric ID or a substring of the device name.
  • window: The visible time slot in milliseconds. This controls how much of the audio history is displayed on the plot.
  • interval: The minimum time between plot updates in milliseconds.
  • blocksize: The block size (number of samples) for audio processing. If not specified, the default block size of the audio stream will be used.
  • samplerate: The sampling rate of the audio device. If not specified, it will default to 16000 Hz.
  • downsample: The factor by which the audio data is downsampled. By default, no downsampling is applied.

The parse_args method is called to parse the remaining command-line arguments (remaining) after handling the --list-devices option.

    if any(c < 1 for c in args.channels):
        parser.error('argument CHANNEL: must be >= 1')
    mapping = [c - 1 for c in args.channels]  # Channel numbers start with 1
    q = queue.Queue()

The code checks if any of the specified channels are less than 1. If so, it raises an error with an appropriate message. It then creates a mapping list for the channel indices, as the channel numbers in args.channels start from 1.

Full code is listed below. Actually, it is based on an example from sounddevice documentation [1].
#!/usr/bin/env python3
"""Plot the live microphone signal(s) with matplotlib.

Matplotlib and NumPy have to be installed.

"""
import argparse
import queue
import sys

from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import sounddevice as sd


def int_or_str(text):
    """Helper function for argument parsing."""
    try:
        return int(text)
    except ValueError:
        return text


def audio_callback(indata, frames, time, status):
    """This is called (from a separate thread) for each audio block."""
    if status:
        print(status, file=sys.stderr)
    # Fancy indexing with mapping creates a (necessary!) copy:
    q.put(indata[::args.downsample, mapping])


def update_plot(frame):
    """This is called by matplotlib for each plot update.

    Typically, audio callbacks happen more frequently than plot updates,
    therefore the queue tends to contain multiple blocks of audio data.

    """
    global plotdata
    while True:
        try:
            data = q.get_nowait()
        except queue.Empty:
            break
        shift = len(data)
        plotdata = np.roll(plotdata, -shift, axis=0)
        plotdata[-shift:, :] = data
    for column, line in enumerate(lines):
        line.set_ydata(plotdata[:, column])
    return lines


if __name__ == "__main__":

    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument(
        '-l', '--list-devices', action='store_true',
        help='show list of audio devices and exit')
    args, remaining = parser.parse_known_args()
    if args.list_devices:
        print(sd.query_devices())
        parser.exit(0)
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        parents=[parser])
    parser.add_argument(
        'channels', type=int, default=[1], nargs='*', metavar='CHANNEL',
        help='input channels to plot (default: the first)')
    parser.add_argument(
        '-d', '--device', type=int_or_str,
        help='input device (numeric ID or substring)')
    parser.add_argument(
        '-w', '--window', type=float, default=200, metavar='DURATION',
        help='visible time slot (default: %(default)s ms)')
    parser.add_argument(
        '-i', '--interval', type=float, default=30,
        help='minimum time between plot updates (default: %(default)s ms)')
    parser.add_argument(
        '-b', '--blocksize', type=int, help='block size (in samples)')
    parser.add_argument(
        '-sr', '--samplerate', type=float, default=16000, help='sampling rate of audio device')
    parser.add_argument(
        '-n', '--downsample', type=int, default=1, metavar='N',
        help='No downsample (default: %(default)s)')
    args = parser.parse_args(remaining)
    if any(c < 1 for c in args.channels):
        parser.error('argument CHANNEL: must be >= 1')
    mapping = [c - 1 for c in args.channels]  # Channel numbers start with 1
    q = queue.Queue()

    try:
        if args.samplerate is None:
            device_info = sd.query_devices(args.device, 'input')
            args.samplerate = device_info['default_samplerate']

        length = int(args.window * args.samplerate / (1000 * args.downsample))
        plotdata = np.zeros((length, len(args.channels)))

        fig, ax = plt.subplots()
        lines = ax.plot(plotdata)
        if len(args.channels) > 1:
            ax.legend([f'channel {c}' for c in args.channels],
                      loc='lower left', ncol=len(args.channels))
        ax.axis((0, len(plotdata), -1, 1))
        ax.set_yticks([0])
        ax.yaxis.grid(True)
        ax.tick_params(bottom=False, top=False, labelbottom=False,
                       right=False, left=False, labelleft=False)
        ax.text(0.01, 0.99, f'Sample rate: {args.samplerate/args.downsample} Hz', transform=ax.transAxes, va='top', ha='left')

        fig.tight_layout(pad=0)

        stream = sd.InputStream(
            device=args.device, channels=max(args.channels),
            samplerate=args.samplerate, callback=audio_callback)
        ani = FuncAnimation(fig, update_plot, interval=args.interval, blit=True)
        with stream:
            plt.show()
            
    except Exception as e:
        parser.exit(type(e).__name__ + ': ' + str(e))
Save it as sd_plot_input.py (or whatever name.py) and run it with the following commands. See the video above for the sample output.
$ python3 sd_plot_input.py


Reference: 

  1. https://python-sounddevice.readthedocs.io/en/0.4.6/examples.html#plot-microphone-signal-s-in-real-time

Sunday, November 22, 2015

Acoustic & Sound Engineer Training 2015

ASET (Acoustic and Sound Engineering Training) merupakan salah satu agenda diantara beberapa kegiatan ITB insight 2015. Materi ASET 2015 ini adalah sebagai berikut:
  1. Hearing Music
  2. Hearing Music in Different Environment
  3. Small Room Acoustics
  4. Music Production
Bagian keempat inilah sebenarnya esensi dari ASET 2015 ini. Pak Jack dari UPH Jakarta yang juga seorang praktisi sound engineer menjelaskan dengan gamblang tentang proses produksi music mulai dari gambaran proses produksi, pra produksi, produksi/recording dan paska produksi. Gambar 1 atas adalah screenshot software Reaper, sebuah DAW (digital audio work station) yang digunakan dalam ASET kali ini. Berikut adalah resume singkat tentang keempat tahapan produksi tersebut.

Screenshot Reaper 5.1, DAW yang digunakan pada ASET 2015

1. Gambaran proses produksi suara

Saturday, May 23, 2015

Interaural Time Difference (ITD)

ITD merupakan kepanjangan dari interaural time difference,  yakni perbedaan waktu tempuh sumber suara ke telinga kiri dan telinga kanan. Apa pentingnya ITD ini? Penting sekali, dengan ITD kita bisa memperkirakan dan mengetahui sumber suara tanpa melihatnya. Coba tutup mata anda, dan dengarkan suara yang ada, kemudian perkirakan di mana letak sumber suara tersebut. Sekarang buka mata anda, dan crosscheck posisi sumber suara yang anda perkirakan tadi, persis dengan perkiraan anda.

Ilustrasi 1: Sumber suara pada 0 derajat dan 30 derajat. Pada 0 derajat ITD adalah 0, sedang pada 30 derajat ITD dapat dicari pada gambar/grafik 3 (sumber: Thesis BT Atmaja [1], dok pribadi)

Teori Duplex
Teori tentang ITD ini pertama kali dikemukakan oleh Lord Rayleigh (1907) yang menyatakan bahwa perbedaan suara yang sampai pada telinga dapat dicari/dihitung,
provided evidence that timing differences between the ears were detectable
Teori duplex Lord Rayleigh ini mengandung dua dasar pengukuran sensitivitas pada ILD (Interaural level difference, "beda level") dan sensitivitas pada ITD ("beda waktu") sebagai berikut.

Tuesday, November 18, 2014

Pemisahan sumber-sumber suara tercampur berdasarkan penelusuran frekuensi dasar pada sinyal wicara dan musik

Sound source separation is challenging problem in acoustics area. The problem comes from the cocktail party, presence of multi talker and the ability of human ear to focus and separate voice from many sources. Some approaches have been developed to separate mixed sound from sources. The estimation of fundamental frequency is one of approach to decompose mixture sounds into its components based on its harmonics. The idea is by grouping the components which has the same harmonics from the mixture sound by pitch and common amplitude modulation and harmonic selection technique. The estimation of fundamental frequency itself is challenging problem which in progress as well as sound separation problem. The result of those methods clearly shown that F0-based sound separation works efficiently, especially in musical sounds. However, the method needs to be improved in other conditions such as noisy and reverberant.

Full paper (in Indonesian language) can be downloaded here.
Matlab source code can be obtained from here.

Sunday, October 21, 2012

Installing Octave 3.6.1 in Ubuntu 12.04

Step-by-step:
  1. Add the following ppa to your repository 
  2. $ sudo add-apt-repository ppa:picaso/octave
  3. Update and Install the octave
  4. $ sudo apt-get update && sudo apt-get install octave
  5. Run the following command to update the package
  6. sudo apt-get install liboctave-dev
  7. Need additional packages? Here are the examples. You can find other packages depend on your needs.
  8. $ sudo apt-get install octave-control octave-audio octave-signal octave-plot
  9. Run Octave
  10. $ octave -q 
For GNU Octave 4.0, and 4.0.1 you can follow the following procedure.

Thursday, February 23, 2012

PESQ and its implementation in Octave/Matlab

PESQ stands for ‘Perceptual Evaluation of Speech Quality’ and is an enhanced perceptual measurement for voice quality in telecommunications. If you want a Mean Opinion Score value (or MOS), then PESQ will give it to you. The new PESQ option will be especially relevant for engineers working in telecom, handsets, and handsfree accessories. Because it becomes standard in telecommunication industry, it is very important to measure of speech processing output with this standar. A figure of overview of PESQ system can be seen in Fig.1.

Fig. 1 : Overview of PESQ System[ [1]
Perceptual audio tests measure how people perceive sound quality. While useful for evaluating both small differences in high-quality music, and larger differences in lower-quality voice material, this article focuses on doing the latter using PESQ (Perceptual Evaluation of Speech Quality).

Friday, February 17, 2012

DSEE Sony Vs DNSe Samsung

DSEE (Digital Sound Enhancement Engine) by Sony

Listen to the music like it was meant to be. Degraded sounds of compressed audio are now improved and the high-frequency range restored, reproducing natural, high-quality sounds as close to the original source as can be.  DSSE Sony is meant to restore sounds back to original.

Digital Sound Enhancement Engine (DSEE) is Sony’s originally developed audio bandwidth enhancement technology. DSEE is a technology to enhance the sound quality of compressed audio files by restoring high-range sound removed by the compression process.When original music source is compressed with MP3 (or AAC/WMA), high-frequency part of music source will be lost. The technology of DSEE enables to restore high-frequency part and reproduces high-quality sound which is close to the original CD sound source. By activating the [DSEE(Sound Enhance)]feature, you can hear a rich and natural sound almost exactly like the original source. 

DSEE Technology

DNSe (Digital Natural Sound engine) by Samsung

DNSe or the Digital Natural Sound engine is a DSP audio enhancement technology developed by Samsung in 2003 and further on implemented throughout many of their product lineups - from TVs and DVD players to portable music players and lately - mobile phones.

Wednesday, December 07, 2011

The Acoustics Branch: Time-Space Representation

The Acoustics and Its branch in space-time representation [1]

Acoustics science has many branch, one of interest point is analyze sound wave from space-time point of view. A research group in EPFL, Switzerlan, has studied Nonparametric representations of acoustic wave fields obtained by observing the sound pressure along a straight line using a microphone array contain implicit information of the surrounding acoustic scene, both in terms of spatial arrangement of the sources and their respective temporal evolution.

For more information, please visit the reference source below.

Reference:
[1] http://lcav.epfl.ch/research/space_time_frequency

Wednesday, November 30, 2011

On Performance of Two-Sensor Sound Separation Methods Including Binaural Processors

Human beings have binaural inputs to separate and localize sound sources. Those two functions of binaural hearing can not be easily transformed to the computational methods. In this paper, three conventional methods to separate target signal from interfering noise are compared. Those methods include a binaural model, an independent component analysis (ICA) and a time-frequency masking applied to ICA. Performances were compared by means of spectrograms as well as coherence.

Above is abstract of my paper presented in ASJ Kyushu Chapter, November 25, 2011, in Oita - Japan. You can see the poster below (click to enlarge).

Full paper is available by request.

Tuesday, October 25, 2011

High-Quality Resample (Downsample/Upsample) Sound File (.wav)

In this occasion let me show how to resample (Downsample/Upsample) sound file such as .wav in high-quality format directly on your Operating System.

The software/program that I used is libsamplerate (SRC). You can download here. Follow the instruction and the "README" text, and install it manually (if you used Unix-based OS, I think it just a simple job:) ). How to use it ? Just choose one of two options below,
sndfile-resample -to  newsamplereate [-c number] inputfile.ext outputfile.ext

sndfile-resample -by  amount [-c number] inputfile.ext outputfile.ext
The optional -c argument allows the converter type to be chosen from the following list :  
  • 0 : Best Sinc Interpolator
  • 1 : Medium Sinc Interpolator (default)
  • 2 : Fastest Sinc Interpolator
  • 3 : ZOH Interpolator
  • 4 : Linear Interpolator

For example, I resampled my input file namely female02_44k.wav which has 44100 Hz of sampling rate to be 8000 Hz with output name is female.wav. So, I use the following command,
sndfile-resample -to 8000 female02_44.wav female.wav
After that, I will get the result as the following,
Resample Result Using libsamplerete
So, what is libsamplerate?

Thursday, October 13, 2011

Convolution of Two .wav Sound Files in Linux and Matlab

Convolution is the very basic and main operation in Signal Processing. My professor said that Convolution is the heart of signal processing. If we has two .wav sound files how to convolute them?

In Linux, first download the bash file here. Then follow the instruction below,

1. Ubuntu and other distribution> Unzip and untar the download by typing 
    $ gunzip fconv.tar.gz
    $ tar -xvf fconv.tar
    
2. If you are in the same directory as the program, it will run. Just type "fconv" at the command line. SLACKWARE INSTALLATION:

Tuesday, October 11, 2011

Menyimpan data .wav/.mat dalam format ASCII di Matlab / Octave

ASCII - American Standard Code for Information Interchange merupakan format standar data yang berupa text yang akan memudahkan kita untuk memprosesnya dalam program dan OS apapun. Nah, bagaimana menyimpan data kita dalam format ASCII ? Caranya adalah dengan menyimpan anda dalam workspace Matlab atau Octave, kemudian simpan sebagai file format ASCII dengan perintah berikut ini. (Mungkin juga berlaku untuk selain data .wav dan .mat, yakni data berekstensi lain .xml dll, sekali lagi load dulu ke workspace-nya matlab/Octave).

Dalam Matlab,
x=wavread('nama_file.wav');                      % load file wav anda

save namafiletxt x -ASCII


jika data anda berupa .mat

load data

save namafiletxt x -ASCII                           % load file mat


Dalam Octave, ganti -ASCII menjadi -ascii, sehingga menjadi sebagai berikut: