This repository contains a simple audio synthesiser using numpy and PyAudio to play various waveforms.
Also included is a visualisation UI using pyqtgraph and PyQt5. Add together multiple sine waves with individually configureable frequency and volume, and see and hear the resulting waveform.
Make sure you have python 3.6 and pipenv installed.
Download or clone this repository, navigate inside and run:
pipenv install
Run the UI using:
pipenv run ui
Press the '+' button to add a new sinewave, use the text input or the slider to change the frequency and the dial to change the local volume. Press the '-' button next to a frequency selector to remove it.
To see some preset examples, try any of the following:
pipenv run ui full # show the full harmonic series
pipenv run ui odd # show the odd harmonic series
pipenv run ui square # show a square wave approximation
pipenv run ui triangle # show a triangle wave approximation
pipenv run ui sawtooth # show a sawtooth wave approximation# the default fundamental of the above is 100Hz.# combine any preset with a frequency to change this, e.g.
pipenv run square 250You can also use the synthesiser on its own, without the UI, as follows:
fromsynthimportSynth# Specify notes as a list of sinewave frequencies in Hznotes= [100, 150, 250]
# Specify volumes for each note as a list between 0 and 1volumes= [1, 0.75, 0.5]
update_rate=1# how many audio frames generated per second# A high value will let the notes change more frequently,# but might cause "popping" sounds for complex waveforms.# A low value tends to have fewer "popping" sounds, but# won't update to a new note as quickly# initialise the synth with specific notessynth=Synth(notes, volumes, update_hz=update_rate)
# start the continuous playbacksynth.start()
# change the notes dynamicallyinput('Press Enter to change chord')
synth.notes= [150, 200, 350]
# control the main output volume scalingsynth.master_volume=0.75# prevent the application from terminatinginput('Press Enter to end')
# close the audio thread and end the programsynth.stop()