Read the latest Real Python tutorials
Project description
graph2sound
This is a Python library for adding some auditory feedback to your graphs. Alternatively, this library has capabilities such as creating smooth variable-frequency waveforms or playing simple MIDI-tones.
Installation
Use pip install graph2sound
to install the module.
Alternatively, download graph2sound.py
and save it in your working directory.
Dependencies
numpy
for array creation and modification.
scipy
for signal modification and interpolation.
sounddevice
is required for playback. However, as the wav + samplerate can be extracted with graph2wav
, it is not strictly needed.
Usage
Depending on what you want to do, g2s may be called as a single function. These functions actually chain some subroutines together to assemble and play the final tone.
The general syntax is as follows:
import graph2sound as g2s
g2s.graph2sound(y[,x],[t=,r=,s=,l=,h=,w=,f=])
Demo
Test g2s by g2s.graph2sound()
. Plays a demo sound.
Single y series
At the very least, g2s requires a single data series consisting of two points or more.
y = [i**2 for i in range(10)]
g2s.graph2sound(y)
This will play a tone which increases in frequency quadratically. Every point in the series is played for an equal amount of time (linear time mapping).
Single x y series
If you have an associated time series, for example a result from an ODE solver, you may also map your data points to time. Note: the lengths of the two series must be equal.
import numpy as np
t = np.logspace(0.1,1,100)
y = np.sin(t)
g2s.graph2sound(y,t)
This will play a sound which steadily increases in frequency, as opposed to a logarithmic increase in frequency.
Two-dimensional y series
If you have a series of y data which is 2D, g2s will automatically convert all rows to wavs and adds them.
y = [[i*j for i in range(5)] for j in range(5)]
g2s.graph2sound(y)
This will play the normalized summed waveforms, row major.
Keyword use and more examples
import pandas as pd
d = {'x':[0,0.1,0.2,3],'y':[0,0,0,1]}
df = pd.DataFrame(d)
g2s.graph2sound(df['y'],df['x'],t=1.5,l=440,h=880,w='sawtooth')
Plays from a DataFrame. Has a 1.5 second duration, the lowest/highest tones are 440 and 880 and the synth uses a sawtooth wave.
from scipy import signal
import numpy as np
x = np.linspace(0,20)
y = signal.square(x)
g2s.graph2sound(y,x,w='square')
This is what a square square wave sounds like.
Keywords
g2s.graph2sound
takes multiple optional keywords:
t = float,int
Default: 2 seconds. Determines the length of the tone played.
r = int
Default: 44100. Sample rate. Determines the samples per second which are fed into the audio library.
s = int
Default: 100*t. The number of segments the tone is divided in. Essentially: how many frequency changes the tone has.
l = float
Default: 130.813 Hz. C3. This is the lowest tone the y series will be mapped to.
h = float
Default: 2093.005 Hz. C7. This is the highest tone the y series will be mapped to.
w =
sine
Outputs a sine waveform (default).
square
Outputs a square waveform.
sawtooth
Outputs a sawtooth waveform.
f =
fifth
Adds a perfect fifth overtone.
yaranaika
HARMONY
MATLAB
plays the sound like ye olde days.
Low-level functions
Read the docs (TODO) to use the underlying functions.
wave,samplerate = g2s.graph2wave
takes in the arguments mentioned above and converts it to the required waveform. Assembles it into a ready-to-play array. Returns the waveform and the samplerate used.
g2s.wave2sound(wave,samplerate)
takes the arguments of the previous function and plays them back.
y,x = g2s.argskwargcleanup(*args,**kwargs)
verifies the x/y data format to it can be used in the rest of the functions.
f_list = g2s.freqlist(y,x,frequency_low,frequency_high,segments)
creates a frequency table which is required to synthesize the desired tone.
wave,samplerate = g2s.synth(time,samplerate,segments,frequency_list,**kwargs)
is the meat and potatoes of this module. Given information on how the samplerate and the segments look like, synthesizes a continuous waveform with the desired samplerate.
freq = g2s.midi2freq(mnn)
takes in a midi note number (not from MIDI.org, needs login) and returns the frequency. A4 = 69 = 440 Hz.
mnn = g2s.freq2midi(freq)
takes in a frequency and returns the midi note number as specified above.
mnn = g2s.midi2midi(mnn,delta_freq=0)
changes the midi number by a given frequency. Does not output ints or check if the number is a real note or not.
freq = g2s.freq2freq(freq,delta_mnn=0)
changes the frequency by a midi note interval.
Support
Shit's broken? Merge requests are open.
License
MIT
Why?
In one of my bachelors' courses (control theory), I was fucking around with MATLAB (hallowed be thy name) and at a certain point, I thought to myself:
"This graph needs sound"
- Crossed Omega, 2018
Obviously, this Lovecraftian horror of an idea took digital form rather quickly. After ample time, the first iteration was done - which sounded pretty horrible1. For the next three years, it remained untouched, left stewing, the entity itself anticipating a return. As I learnt Python, one of the first things I did, after giving the IT department a major headache, was rewrite graph2sound to be used as a Python library. Alas, my attempt to do so was not thwarted and thus stands before you an academic shitpostTM of genuine Dutch quality.
1: You can actually listen to what it sounded like by passing the MATLAB filter keyword f=MATLAB
.
TODO
Add a small amount of filters to modify the waveformsRewrite the synth function, some of the arguments are redundant- Add an LFO
Add a sound library checkerAdd proper data sanitationAdd multi-dimensional sounds- (Never ever) Rewrite this as a matplotlib backend
Known bugs
- The synth function bugs out at some edge cases: for a function with the highest point at t=end, the final frequency is never played. Requires changes to the frequency list function.
- The data validation misses lists such as [1,[1,2,3]] as a check for raggedness. This development is a pain in the bum.
- The raggedness of arrays is still not handled perfectly, as ragged arrays cause all kinds of different errors.
- The returned datatype of the ...2midi functions is a float; this should be an int and checked for if the frequency is actually a midi note.
- The generated wav may start and end with a non-zero loudness. This can cause "popping", which could be fixed by ramping the amplitude up and down by either adding a ramp before and after or multiplying the beginning and ending of the wav with an exponential curve.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file graph2sound-1.1.4.tar.gz
.
File metadata
- Download URL: graph2sound-1.1.4.tar.gz
- Upload date:
- Size: 9.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e0a4c8e281f2ae714639307fb3db4d904151a6ce767b119d0673683df23266d1 |
|
MD5 | fab58013d27b8010e6028122c4200af6 |
|
BLAKE2b-256 | c8fc634d8cd93a61587e6216a3091f42c47663cd37c498ba8920be00184d5e0c |
File details
Details for the file graph2sound-1.1.4-py3-none-any.whl
.
File metadata
- Download URL: graph2sound-1.1.4-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3d97caba4daf37f436683e669661cab474461b68e6dc2a71f7eb63f19128ccc1 |
|
MD5 | a859f0b31c85491c1e724c3675114e85 |
|
BLAKE2b-256 | 1d5e034ee83f7842ac24b0eb41de6d24792625d52f6f89e5192e7607cbd0f990 |