The purpose of the looping function was to create an effect that a DJ could implement, in real time, in the form of a transition from one song to another or to utilize a repeating beat to create new audio. With looping, a steady hard-hitting base or snare that can be repeated and overlaid with other sounds and audio that builds into a full track that will surely get the party rocking! The features of the looping function are simple as demonstrated by the demo shown. The user has control over options such as their audio file input, cutoff frequency, chunk size, and loop interval to observe how these affect the audio output.
Initial Python Setup
In the beginning, there was a learning curve with setting up a working Python environment and deciphering which Python libraries to learn about and how to integrate into my program. Searching through online stack overflow posts discussing which libraries were suitable for audio manipulation, Pydub was a popular choice due to the plethora of functions they offered. Once my Python environment was setup my next goal was to successfully play audio. Initially, I had attempted to use the playAudio function and pass in my parameters: file_path (hard coded), the number of times to loop.
Getting Audio to Play
This iteration was a failure as I had not accounted for the format of my input WAV file. I learned that there are two types of WAV audio, stereo and mono with the difference being the quality of the outputted sound. With stereo, there are two channels suited for a more realistic listening environment taking advantage of the spatial effect. On the other hand, in mono, the sound originates from one channel causing the output to sound like it is playing from one isolated source. Being that most audio files are mixed in stereo, I needed to convert to mono. By setting the input audio channels to 1, I limited myself to handling only mono files. Doing some research, I learned that playback for mono audio was much simpler than stereo because there was no need to split audio into left and right channels.
Looping Audio But Going in Circles
After fixing the issues with the input audio file, I created functions to control processing audio based on user input. I prompted the user to manually input the start time, segment duration, number of loops, and cutoff frequencies. Within the process_wave_file function, I set conditions for these input values and utilized low pass filtering to achieve cut-off frequencies to allow for more dynamic listening at different frequencies. I struggled with figuring out how to output audio without getting playback errors and cited online code with similar programs to see their approach, threading which allowed me to play the modified audio without being blocked by the original
Drawbacks of Initial Implementation
With this initial iteration of the looping function came many limitations in its usability. Ultimately, the main goal of this effect, among all others for our project, was to implement real-time effects that can be altered during audio streaming. My initial setup was static in its functionality, prompting the user to specify all input values beforehand. The goal of my improved iteration was to create a GUI to allow for better usability and offer a more dynamic experience.
Shown to the left is a demonstration of the updated looping function for a given audio file. I implemented a GUI and modified my program to better simulate more real-time effects. The looping remains static in that you need to input times rather than adjust through a slider. Other parts such as the cutoff frequency and looping sliders, play, and stop buttons allow you to have more control of the outputted audio without having to specify prior to running the input audio file.
Modifications I made to the looping function include an additional check to verify the input audio's file properties before continuing with audio processing. I changed the parameters passed into this function such as cutoff_slider_values and loop_slider_values to achieve the realtime audio manipulation of the user's inputs. In addition, I added conditional statements to account for valid changes to the looping values, denoted by the start_pos and end_pos variables.
This is my main window which implements the conditionals based on the GUI slider, buttons, and entry field inputs. I included error checking to ensure valid input and initiated the buttons' functionality using threading and other PyDub functions. In addition, the main window calls the threading functions to allow for the playback audio to work properly with the additional realtime effect values such as cutoff and loop parameters.
This is the main layout of the program's GUI. I define each parameter's interface type and the specifications that control the file type, sizing and location of elements that appear in the popup window. Example is the field titled "Input Audio File" which has key="File" as its expected input type and "WAV Files" and "*.wav" file types deemed acceptable for continuing with the program.
Windowing
For the looping function, windowing was implemented to specify start and end points for the outputted audio segment. A user was able to determine these start and stop times, and the windowing allowed for relatively smooth transitions between each looped iteration.
Filtering
Low pass filtering was implemented on the input audio to control the cutoff frequencies in real time while playing the output audio. This was implemented through the Python Scipy library's butter and lfilter functions for utilization in the playing_looping_audio function.
Audio Buffering
The chunks value in my code represented the total number of segments the audio was divided into and combined to rebuild the audio for seamless output. As seen in the demo, as the chunk size increased, the quality of the output was a better replication of the unlooped original audio. However, at lower chunk size values, the audio sounded choppy and there was an increase in latency causing a more choppy output.
Overall, the implementation of the updated audio looping effect is an improvement over its initial design. There were issues with the usability of the looping function and its features, especially without a GUI included. The goal of real-time effects was achieved to an extent but not fully successful. The issue I faced while updating my looping function, was being able to figure out the sliders to respond to the simultaneous audio for the cutoff and looping parameters. With the help of my teammates, I was able to learn how to improve the functions for these values and integrate them into sliders in the GUI. As stated previously, threading was relied on for being able to export the audio while updating it as the user plays with the looping controls. The issue with processing the individual chunks resulted in issues with audio continuity. One way to improve this issue is to use FIR filtering as a better alternative to low-pass filtering. To prevent added delay, algorithms such as implementing the Fast Fourier Transform (FFT) could help with faster audio processing.
I had difficulty with delays in my output when a user tried to use looping which can be heard in the demo video shown above where there is an audible glitch between changing the loop parameters. This is a big issue when looping audio and relying on it to be constant with the beat rather than increasingly lagging due to minimal delay in each iteration. The cutoff frequency slider was successful but also faced similar issues with slight delays that can be heard when one attempts to shift the cutoff frequency values. There are limitations mainly in the integration with the other effects such as pitch modulation which is common for looping to utilize as a form of crossfading and making seamless cuts within the same audio file or multiple audio files. One way of improvement could be to set a boundary preventing the loop_start slider from being greater than the loop_end slider to prevent any further confusion for the user. Additionally exploring smoother transition techniques such as crossfade smoothing would be a preventative measure against the glitches.