Easiest way to produce guitar chords in linux and/or python
Asked Answered
A

3

14

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 the 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.

Anabelle answered 13/7, 2011 at 22:44 Comment(0)
L
14

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.

Laurinda answered 14/6, 2012 at 12:43 Comment(4)
nice. i'll give this a go. the current solution is pretty hacky and i've found if you run it over and over it can break down, but it sounds ok as long as you do it slowly. - ill try this and get back in the next few weeks.Anabelle
awesome ! i'll move the accepted answer to be this, because it really does sound alot better. :-) thanks !Anabelle
Have you got an idea how to do sharps/flats using the pl synth subcommand?Darreldarrell
@Darreldarrell you can simply use # and b for it. For example G#4 is a high G sharp.Vanpelt
S
7

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 plays 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.

Sensible answered 13/7, 2011 at 23:11 Comment(2)
that for loop seems to work, allbeit with some clipping due to the amplitude, but its a good start, thanks :-) -- I'd mostly discounted midi as an option as it'll sound different on each end user's machine. I'll see where the for loop gets me.Anabelle
fixed with the "vol" specifier. This looks like workable solution, thanks ! :-)Anabelle
O
4

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.

Outlay answered 13/7, 2011 at 22:50 Comment(1)
I'll try this tonight, but im on fedora (and i assume users of my clients will be on fedora or ubuntu mostly) but im using pulseaudio. I thought of the & trick last night, but when i tried it no sound played until i brought the process back to the foreground, which kind of defeated the point. Regarding B) im wondering what sox does, because i tried every instrument in tuxguitar with midi and it sounded like garbage, but sox sounds ok to me. Maybe its an illusion.Anabelle

© 2022 - 2024 — McMap. All rights reserved.