Easiest way to produce guitar chords in linux and/or python
What i'm trying to achieve is playing a guitar chord from my python application. I know (or can calculate) the frequencies in the chord if needed.
I'm thinking that even if I do th开发者_如何学Goe low level leg work of producing multiple sine waves at the right frequencies it wont sound right due to the envelope needing to be correct also, else it wont sound like a guitar but more of a hum.
Tantilisingly, the linux sox command play can produce a pretty convincing individual note with:
play -n synth 0 pluck E3
So really what i'm asking is,
a) is it possible to shoehorn the play command to do a whole chord (ideally with slightly differing start times to simulate the plectrum string stroke) -- i've not been able to do this but maybe theres some bash fairydust that'll fork a process or such so it sounds right. If this is possible i'd settle for just calling out to a bash command from my code (I dont like reinventing the wheel).
b) (even better) is there a way in python of achieving this (a guitar chord sound) ? I've seen a few accessable python midi librarys but frankly midi isn't a good fit for the sound I want, as far as i can tell.
The manual gives this example:
play -n synth pl G2 pl B2 pl D3 pl G3 pl D4 pl G4 \
delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1
This creates 6 simultaneous instances of synth (as separate audio channels), delays 5 of the channels by slightly increasing times, then mixes them down to a single channel.
The result is a pretty convincing guitar chord; you can of course change the notes or the delays very easily. You can also play around with the sustain and tone of the 'guitar', or add an overdrive effect—see the manual for details.
a) The hackish way is to spawn a background subprocess to run each play
command. Since a background subprocess doesn't make the shell wait for it to finish, you can have multiple play
s running at once. Something like this would work:
for p in "C3" "E3" "G3"; do ( play -n synth 3 pluck $p & ); done
I see that ninjagecko posted basically the same thing as I'm writing this.
b) The key point to realize about MIDI data is that it's more like a high-level recipe for producing a sound, not the sound itself. In other words, each MIDI note is expressed as a pitch, a dynamic level, start and stop times, and assorted other metadata. The actual sound is produced by a synthesizer, and different synthesizers do the job with different levels of quality. If you don't like the sound you're getting from your MIDI files, it's not a problem with MIDI, it's a problem with your synthesizer, so you just need to find a better one. (In practice, that usually takes $$$; most free or cheap synthesizers are pretty bad.)
An alternative would be to actually dig under the hood, so to speak, and implement an algorithm to create your own guitar sound. For that you'd want to look into digital signal processing, in particular something like the Karplus-Strong algorithm (one of many ways to create a synthetic plucked string sound). It's a fascinating subject, but if your only exposure to sound synthesis is at the level of play
and creating MIDI files, you'd have a bit of learning to do. Additionally, Python probably isn't the best choice of language, since execution speed is pretty critical.
If you're curious about DSP, you might want to download and play with ChucK.
a) is it possible to shoehorn the play command to do a whole chord... ?
If your sound architecture supports it, you can run multiple commands that output audio at the same time. If you're using ALSA, you need dmix or other variants in your ~/.asoundrc
. Use subprocess.Popen
to spawn many child processes. If this were hypothetically a bash script, you could do:
command1 &
command2 &
...
b) (even better) is there a way in python of achieving this (a guitar chord sound)?
Compile to MIDI and output via a software synthesizer like FluidSynth.
精彩评论