Quefumas / gensound

Pythonic audio processing and generation framework
Apache License 2.0
80 stars 6 forks source link

Documentation for how to create sequences of arbitrary frequencies #26

Closed klei22 closed 2 years ago

klei22 commented 2 years ago

This is really cool! Looks like there is a lot of documentation for how to create parallel sequences of notes, but would be awesome if there would be a way to do the same with arbitrary frequencies (is this possible)?

Quefumas commented 2 years ago

Thanks!

I'm not sure I understood your question - oscillators support reading arbitrary frequencies directly (i.e. Sine(435.875, 1e3)), but I guess you're referring to the Melodic Shorthand Notation. This notation also supports arbitrary frequencies, but they are not specified in Hz but rather in cents (1/100th of a semi-tone, a ratio of 2^(1/1200)), like this: Sine("C#-25", 1e3), which generates a Sine wave with a frequency 25 cents lower than a C#. This is usually preferable to specifying frequency in Hz, as this corresponds much better with how we perceive pitch (a difference of 2 Hz can be very little or very much, depending how high the starting pitch is).

Either way, I'd love to hear suggestions for new use cases or examples.

klei22 commented 2 years ago

Thanks @Quefumas for reaching out!

So I'm interested in creating a sequence of frequencies in parallel, very much similar to the chorale example in the documentation:

from gensound import Sine, Triangle, Square, Pan

sig = Triangle # Sine? Square?

beat = 0.5e3 # 120 bpm
fermata = 0.1 # make fermatas in the melody slightly longer
pause = 0.6 # and breathe for a moment before starting the next phrase

S = sig(f"r D5 D=2 C#=1 B-13=2 A=1 D E=2 F#-13={2+fermata} r={pause} F#=1 F#=2 F#=1 E=2 F#-13=1 G F#-13=2 E={2+fermata} r={pause} "
        f"D+16=1 E=2 F#-13=1 E=2 D+16=1 B-13 C#=2 D+9={2+fermata} r={pause} A'=1 F#-13=2 D+16=1 E=2 G=1 F#-13 E=2 D=3", beat)
A = sig(f"r A4 B=2 A+16=1 G=2 F#-13=1 F# B-13 A A={2+fermata} r={pause} C#=1 B=2 B=1 B A A A D A A={2+fermata} r={pause} "
        f"B=1 A=2 A=1 B-13 A=0.5 G F#=1 B-13 B A#-13 B={2+fermata} r={pause} A=1 A=2 B=1 A=2 A=1 A B-13 A F#-13=3", beat)
T = sig(f"r F#4-13 F#=2 F#=1 D=2 D=1 D D C#-13 D={2+fermata} r={pause} C#=1 D+16=2 D+16=1 D C#-13 D E A, D C#-13={2+fermata} r={pause} "
        f"F#=1 E=2 D=1 D C#-13 D+16 D G+5 F# F#={2+fermata} r={pause} E=1 F#-13=2 F#=1 E=2 C#-13=1 A B C#-13 D=3", beat)
B = sig(f"r D3 B-16 D F# G B-13 D B-16 G A D,={2+fermata} r={pause} A#'-13=1 B=2 A=1 G#-13 A F#-13 C#-13 D F#-13 A={2+fermata} r={pause} "
        f"B=1 C#-13=2 D=1 G, A B G E F# B,={2+fermata} r={pause} C#'-13=1 D C# B C#-13 B A D G, A D,=3", beat)

chorale = S*Pan(25) + B*Pan(-25) + T*Pan(80) + A*Pan(-80) # position the voices in the stereo field
chorale.play() # can you spot the parallel octaves?

Currently, not sure how to do this with Sine(freq, duration) (was thinking it could be possible to make an array for each melody, adding the frequencies and queuing them up to be played -- however hoping there might already be a way envisioned to do this with the direct frequency inputs?)

Thanks again for your help

Quefumas commented 2 years ago

Hey @klei22, I guess this makes sense. Since it combines easily with existing code, I just went ahead and implemented this capability (you may have to pip install gensound --upgrade first). The notation syntax remains the same, except that any pitch name is now replaceable by an int or float indicating frequency.

BTW, there is an undocumented function freq_to_pitch (from gensound.musicTheory) that converts any frequency into the corresponding pitch name. Also, you may wish to play around with this example, although that is much more complex and doesn't yet have such a convenient interface.

Have fun!

P.S. I'm still curious what is the use case here. In most cases, pitch names are easier to work with and think about, but maybe I'm disregarding some possible usages.

klei22 commented 2 years ago

Just tried this out and works really well (trying it out right now in combination with the Synth features and sounds really good)

The portamento example was intriguing too, thinking about some interesting soundscapes can try out with these features.

Thanks!