Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing streaming sounds in python from frequency, chords

Tags:

python

audio

I'm working on an application that converts guitar chords to banjo chords, and as I'm building the objects, I'd also like to make sort of an audio "print statement" that quickly plays the chord I've tabbed/written.

I find myself very confused about how to play multiple sounds simultaneously using Python without some kind of mixing effort, or the inclusion of all of pygame, or writing to file.

What I'm looking for is something that can...

  1. Take frequencies--like 440 to produce an A, 880 to produce an octave of that---as an iterable
  2. Play them without writing to disk, maybe through a midi instrument.

I have functions in place that can convert from frets to frequencies, given instrument tunings, and based on those, I'd like to say:

fretboard.play([440, 880])

and hear tones. Or if I could specify time...

fretboard.play([(440,1), (880,1)])

to hear each simultaneously for a second.

What is the best approach to get this kind of sound simply, and hopefully in a way that would let me sequence several of these if I wanted to create some primitive melodies?

Additionally, if this is just a totally different kind of programming and if it seems like my question is naive ("Hey mittenchops, you need to learn more about channels!"), please let me know, especially if you can direct me to good learning resources.

like image 920
Mittenchops Avatar asked Oct 20 '22 21:10

Mittenchops


2 Answers

While looking for sound analysis for Python earlier, I stumbled on this site PythonInMusic, which has a bunch of music software links for Python.

Looking back at that again, I think the first thing I would try to use to output midi notes in real time is called PyFluidSynth. It's a midi synth for python. Here is some example code from their site:

import time
import fluidsynth

fs = fluidsynth.Synth()
fs.start()

sfid = fs.sfload("example.sf2")
fs.program_select(0, sfid, 0, 0)

fs.noteon(0, 60, 30)
fs.noteon(0, 67, 30)
fs.noteon(0, 76, 30)

time.sleep(1.0)

fs.noteoff(0, 60)
fs.noteoff(0, 67)
fs.noteoff(0, 76)

time.sleep(1.0)

fs.delete()

Hope that helps point you in the right direction!

like image 128
user1475777 Avatar answered Oct 29 '22 15:10

user1475777


If you are on windows, you could get something like this using the method used on old consoles that couldn't play many notes at the same time - instead of playing, for instance, C, E and G simultaneously, play C then E then G very fast, possibly holding on somewhat on the final note (preferably the tonic). This gives the effect of chords, but if you want to demonstrate how different chords on a guitar or banjo sound (including differences between different ways to play the same chord) it might not be good enough. However, this method is possible (on windows at least) without using anything from outside the standard library.

Example code:

import winsound
import time

def chord(root_frequency):
winsound.Beep(int(root_frequency), 60)
winsound.Beep(int(root_frequency*1.25), 60)
winsound.Beep(int(root_frequency*1.5), 60)
winsound.Beep(int(root_frequency*2), 100)

while True:
    chord(261.626)
    time.sleep(0.35)
    chord(261.626)
    time.sleep(0.05)
    chord(233.082)
    time.sleep(0.35)
    chord(233.082)
    time.sleep(0.05)
    chord(207.652)
    time.sleep(0.35)
    chord(207.652)
    time.sleep(0.05)
    chord(195.998)
    time.sleep(0.35)
    chord(195.998)
    time.sleep(0.05)
like image 37
rlms Avatar answered Oct 29 '22 13:10

rlms