The library which implements all the routines necessary for loudspeaker beamforming on a computer.
To run and playback processed signals, the minimum you need is a laptop and some standalone speakers. However, to really experience beamforming you need a beamforming array and way to physically output to more than just one audio channel simultaneously. It is recomended to use something like this paired with a USB hub to drive a large amount of speakers.
You need some version of Python 3 to use PyBeam, preferably Python 3.6 or higher. Moreover, PyBeam also has a dependancy on some Python libraries found here.
To install PyBeam, you can run the following commands:
$ git clone https://github.com/smtm1209/PyBeam.git
$ pip install -r ./PyBeam/requirements.txt
Until PyBeam becomes a proper module, add these lines towards the top of any file that need to use PyBeam's routines.
import sys
import os
sys.path.insert(0, os.path.abspath('path/to/PyBeam/'))
import pybeam
Initialization entails creating a speaker mapping. This process entails identifying which PyAudio output stream index corresponds to which physical speaker pair in your beamforming array. A sample routine designed around the speakers mentioned above is here. In order to gain insight into the streams present on your computer, consider looking at this simple script.
The first step in processing an audio signal is to initialize a source point matrix and a verification point matrix using pybeam.get_source_matrix
and pybeam.get_verification_matrix
, following the scheme below as an example.
In this diagram, there are 16 source points centered at the origin in a line parallel to the x-axis. The sources are space out at a distance of two centimeters. There are also 37 verification points, all at a radius of 3 meters from the origin, with five degrees between each point. The point in the very center is the bright point, or the point where the signal will be beamformed to. The code generate this scheme is here.
# source matrix creation
Y = pybeam.get_source_matrix(dim=(16, 1), delta=(0.02, 0))
# verification matrix creation
X = pybeam.get_verification_matrix(R=3, dim=(37, 1), b=(90, 90))
The next step is to load the .wav
file that we want to process using pybeam.read_wav_file
.
signal, samp_freq, dtype = pybeam.read_wav_file('path/to/wav/file.wav')
From here, we're able to generate the filters we will use to process the data. PyBeam has two routines for this sort of computation: pybeam.get_DAS_filters
and pybeam.get_PM_filters
. These two functions have the same type of output, and only really differ in the algorithm used to come to that result, delay and sum and pressure matching, respectively. Those algorithms, and the more theoretical components of this project, are detailed here.
To calculate the filters with pressure matching, you would use this code.
Q = pybeam.get_PM_filters(X=X, Y=Y,
E_max=pybeam.get_max_energy(Y=Y, sigma=25, R=3),
p_hat=pybeam.get_target_sound_pressures(X=X, onval=1, offval=0),
samp_freq=samp_freq, samples=1024, modeling_delay=0, verbose=False)
On the other hand, to calculate the filters with delay and sum, use this code.
Q = pybeam.get_DAS_filters(X=X, Y=Y,
samp_freq=samp_freq, samples=1024, modeling_delay=0)
The next step is to map the filters we just calculated onto the signal from the .wav
file we read in earlier. To do this, we use the pybeam.map_filters
function. The code to use this function is here.
output = pybeam.map_filters(Q, signal)
The final step is writing the output as a directory of .wav
files with a mapping pickle file so that it can be played back later. This functionality is contained in the pybeam.write_wav_dir
function. Here's some sample code for interfacing with this function.
mapping = pkl.load(open('path/to/mastermap.pkl', 'rb'))
pybeam.write_wav_dir('path/to/output_directory', output, mapping, samp_freq)
To playback, all you have to do is invoke the pybeam.playback_wav_dir
function.
pybeam.playback_wav_dir('path/to/output_directory')
A powerful feature of PyBeam is the ability to generate visualizations using a built-in function. Visualizations can be generated using the pybeam.visualize
function.
This code, using filters generated by pybeam.get_PM_filters
...
pybeam.visualize(Q, X, Y,
onval=1, R=3, test_index=40, dpu=60,
sample_size=1024, rate=samp_freq, verbose=False)
...generates this plot using matplotlib
.
On the other hand, using filters generated by pybeam.get_DAS_filters
and simply substituting Q
in the above function call, this plot is generated.