Package: graph2sound
graph2soundThis 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.InstallationUsepip install graph2soundto install the module.Alternatively, downloadgraph2sound.pyand save it in your working directory.Dependenciesnumpyfor array creation and modification.scipyfor signal modification and interpolation.sounddeviceis required for playback. However, as the wav + samplerate can be extracted withgraph2wav, it is not strictly needed.UsageDepending on what you want to do, g2s may be called as a single function. These functions acutally 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=])DemoTest g2s byg2s.graph2sound(). Plays a demo sound.Single y seriesAt 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 seriesIf 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 apposed to a logarithmic increase in frequency.Two-dimensional y seriesIf 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 examplesimport 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.Keywordsg2s.graph2soundtakes multiple optional keywords:t = float,intDefault: 2 seconds. Determines the length of the tone played.r = intDefault: 44100. Sample rate. Determines the samples per second which are fed into the audio library.s = intDefault: 100*t. The number of segments the tone is divided in. Essentially: how many frequency changes the tone has.l = floatDefault: 130.813 Hz. C3. This is the lowest tone the y series will be mapped to.h = floatDefault: 2093.005 Hz. C7. This is the highest tone the y series will be mapped to.w =sineOutputs a sine waveform (default).squareOutputs a square waveform.sawtoothOutputs a sawtooth waveform.f =fifthAdds a perfect fifth overtone.yaranaikaHARMONYMATLABplays the sound like ye olde days.\Low-level functionsRead the docs (TODO) to use the underlying functions.wave,samplerate = g2s.graph2wavetakes 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 amidi 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.SupportShit's broken? Merge requests are open.LicenseMITWhy?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, 2018Obviously, 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 anacademic shitpostTMof genuine Dutch quality.1: You can actually listen to what it sounded like by passing the MATLAB filter keywordf=MATLAB.TODOAdd a small amount of filters to modify the waveformsRewrite the synth function, some of the arguments are redundantAdd an LFOAdd a sound library checkerAdd proper data sanitationAdd multi-dimensional sounds(Never ever) Rewrite this as a matplotlib backendKnown bugsThe 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.