Propellamin - Need help from those familiar with music + audio programming
Hi, I'm new to the forums and just started working with the propeller, and have a few questions for my first project.
First a little about the project . . .
Currently dubbed the propellamin, the device will be a propeller-controlled theremin-like instrument, using sonar (PING) rather than radio-freqency as input for frequency and volume.
I have many ideas that will be able to take advantage of a digitized version of this instrument, and the first is programming a specific pitch to a range, allowing the musician to easily play in any key. With the help of forum member Casslan, I have tied an average (AVG) of ping readings to an existing pitch-generator program with a table linking range to pitch, but I cannot seem to play frequencies that are not a whole number. I am able to get very close to an actual scale, but especially at lower frequencies this is very limiting. Below is the code I currently have for playing this instrument in C Maj.
Below is how the table should read:
My first questions for the forum are these:
**How can I get the pitch generator to generate a pitch that is not a whole number?
Does anyone have an idea for the code that would allow the pitch to slide smoothly from one specific note to the next while playing?
Is there a way to control the volume for the pitch generator with programming? If not I plan on using a digital potentiometer to control the signal coming from the generator.
Thanks for your help. I will try to keep progress updated, and if anyone has any other ideas for this project I am happy to hear any advice!
First a little about the project . . .
Currently dubbed the propellamin, the device will be a propeller-controlled theremin-like instrument, using sonar (PING) rather than radio-freqency as input for frequency and volume.
I have many ideas that will be able to take advantage of a digitized version of this instrument, and the first is programming a specific pitch to a range, allowing the musician to easily play in any key. With the help of forum member Casslan, I have tied an average (AVG) of ping readings to an existing pitch-generator program with a table linking range to pitch, but I cannot seem to play frequencies that are not a whole number. I am able to get very close to an actual scale, but especially at lower frequencies this is very limiting. Below is the code I currently have for playing this instrument in C Maj.
VAR
long range
long Samples, AVG, SUM
byte counter
long Frequency
byte numofsamples
OBJ
Term : "FullDuplexSerialPlus"
ping : "ping"
Synth : "Synth"
PUB Start
Term.StartPST(115200)
numofsamples:= 5
repeat
Term.CursorHome
repeat counter from 0 to numofsamples ' Repeat Forever
Samples[noparse][[/noparse]counter+1] := Samples[noparse][[/noparse]Counter]
Samples[noparse][[/noparse]0] := ping.Ticks(PING_Pin) ' Position Cursor ' Print Fractional Part
'waitcnt(clkfreq / 10 + cnt) ' Pause 1/10 Second
SUM:=0
repeat counter from 0 to numofsamples
SUM := SUM + Samples[noparse][[/noparse]counter]
AVG := (SUM/numofsamples)
AVG := AVG -100
case AVG
0..100: Frequency := 131 'C3
101..200: Frequency := 147 'D3
201..300: Frequency := 165 'E3
301..400: Frequency := 175 'F3
401..500: Frequency := 196 'G3
501..600: Frequency := 220 'A3
601..700: Frequency := 245 'B3
701..800: Frequency := 262 'C4
801..900: Frequency := 294 'D4
901..1000: Frequency := 330 'E4
1001..1100: Frequency := 349 'F4
1101..1200: Frequency := 392 'G4
1201..1300: Frequency := 440 'A4
1301..1400: Frequency := 494 'B4
1401..1500: Frequency := 523 'C5
Synth.Synth("A", 10, Frequency)
Term.Str(String("AVG-100: "))
Term.dec(AVG)
Term.str(string(" ")) ' Print Inches
Term.CarriageReturn
Term.Str(String("FRE: "))
Term.dec(Frequency)
Term.str(string(" ")) ' Print Inches
Term.CarriageReturn
Below is how the table should read:
0..100: Frequency := 130.81 'C3
101..200: Frequency := 146.83 'D3
201..300: Frequency := 164.81 'E3
301..400: Frequency := 174.61 'F3
401..500: Frequency := 196 'G3
501..600: Frequency := 220 'A3
601..700: Frequency := 246.94 'B3
701..800: Frequency := 261.63 'C4
801..900: Frequency := 293.66 'D4
901..1000: Frequency := 329.63 'E4
1001..1100: Frequency := 349.23 'F4
1101..1200: Frequency := 392 'G4
1201..1300: Frequency := 440 'A4
1301..1400: Frequency := 493.88 'B4
1401..1500: Frequency := 523.25 'C5
My first questions for the forum are these:
**How can I get the pitch generator to generate a pitch that is not a whole number?
Does anyone have an idea for the code that would allow the pitch to slide smoothly from one specific note to the next while playing?
Is there a way to control the volume for the pitch generator with programming? If not I plan on using a digital potentiometer to control the signal coming from the generator.
Thanks for your help. I will try to keep progress updated, and if anyone has any other ideas for this project I am happy to hear any advice!

Comments
You may want to look at the counters as a method to generate high res frequencies. Then take those hi frequencies and divide them down to a usable frequency for the real world. This way you can move from note to note (gliss) in large numbers (up to 32 bits, but the output is divided down to notes in a usable range. So for every counter pulse, you output a counter value divided by X (maybe even 10, 100, or 1000).
Someone else may know a way to divide the counter output, but two ideas that come to mind:
1. Output a counter at frequency X on a pin that represents a hi res note value (i.e. A440 would be counter freq of 440,000, send back to an input, divide the input by some fixed value to produce usable musical frequencies and output the result.
or
2. Operate a counter at a frequency, divide the counter with some means internally. My counter experience is limited but there is an app note on the Prop info areathat is very informative.
Either method should allow sliding between notes once you get it sorted out. The hi res frequency can be easily added to or subtracted from to.
Using low res (real world frequencies) as you are dong in your code will not allow for any smooth transitions between whole or half notes.
The Ping input could be the controlling factor for the counters frequency, and you could change the counters output in real time with the Ping. You could also quantize the output with case statements.
As for the the smooth transition, it would be a math function... you could try this: Frequency := -56036 / AVG + 560
I think I did that right.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
HSS
I will be releasing my code for my musical device, along with the schematics, and with it you can eaisly attach a theremin.
And it would be very easy to program a theremin input on it and have it represent one of many sound waveform modifiers.
I do it with my prop fx/sequencer.
I don't have a theremin, or its schematics, but im sure if I looked into it, it would be easy to make it be a frequency modifier.
The same could be done with a 1-axis accelerometer. 3 axis would get fun.
I have the one below and plan to program it to do whatever i want.
http://www.parallax.com/Store/Sensors/AccelerationTilt/tabid/172/CategoryID/47/List/0/Level/a/ProductID/97/Default.aspx?SortField=ProductName,ProductName
Post Edited (Clock Loop) : 7/22/2009 9:38:38 PM GMT
What you need is a DDS Tone Generator (DDS=Direct Digital Synthesis) with a PWM modulated output to control
the volume.
There are some objects for the Hydra (i.e. the HSS that ClockLoop suggested). They normally need to be coded
in Assembly, but for a simple Test (and to show the concept) it's also possible within Spin:
{{ DDS Synth example }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 NULL = $8000_0000 DAC = 10 '<-- Audio Out Pin VAR long freq '~10_000_000 .. 200_000_000 long volume '0 .. 32767 long UpDown long stack[noparse][[/noparse]20] PUB Main cognew(DDS_Gen(@freq,@volume),@stack) 'Start Synth Cog repeat 'Demo loop: repeat freq from 10_000_000 to 150_000_000 step 200 'freq sweep if UpDown==1 'volume up/down volume += 5 if volume > 32000 UpDown := 0 else volume -= 1 if volume < 50 UpDown := 1 PUB DDS_Gen(pFreq, pVolume) | phase 'Synth Cog, produces a triangle wave dira[noparse][[/noparse]DAC] := 1 'Set up DAC ctra := %00110 << 26 + DAC 'counter A in DUTY mode frqa := NULL repeat 'DDS loop: phase += long[noparse][[/noparse]pFreq] 'add freq to phase ' frqa := phase>>16 * long[noparse][[/noparse]pVolume] + NULL 'mult saw with volume frqa := (||phase-NULL)>>16 * long[noparse][[/noparse]pVolume] + NULL 'convert to triangle and mult with volume ' frqa := (phase&NULL>>1)>>16 * long[noparse][[/noparse]pVolume] + NULL 'convert to square and mult with volumeThis starts a new cog for generating a frequency with volume control. You can control this parameters
from the Main loop with the 2 variables: freq and volume (for range see comments in VAR section).
There are 3 waveforms in the example which you can change by uncommenting 1 of the 3 "frqa := ..." lines.
For your Theremin you can have 2 Ping sensors.
The first ping controls the frequency:
freq := AVG1 * 100_000
The second controls the volume:
volume := AVG2 * 2000
Andy
The frequency is spec'd as integer Hertz, but you could probably modify it to work in hundredths of Hertz...
(I.e., Instead of giving it 440 for 440 Hz, just give it 44000 and then modify the code as required...)
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
My Prop Info&Apps: ·http://www.rayslogic.com/propeller/propeller.htm
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
My Prop Info&Apps: ·http://www.rayslogic.com/propeller/propeller.htm