Playing a note ...the hard way ?!

Jeremy Leach

Senior Member
This is just a little experiment to play a note using a loop instead of using 'Sound' or 'tune' commands. Actually not sure it's working correctly yet ...(and no idea what I want to use it for, except was hoping could maybe do a sweeping siren sound !)

In the code below I first off used my Timer1 module to time the for-next loop setting the Pulseout value to 0. This gave time around the loop = 0.81166ms. So any Pulseout duration should just add to this.

If the Pulseout duration = D, then the Halfperiod of the output signal = D + 0.81166*10^-3 seconds
So FullPeriod = 2D + 0.00162333 Seconds

At 8MHz each unit of the Pulseout value (call it P) = 5uS.

So FullPeriod = P * 0.00001 + 0.00162333 Seconds
If F is frequency of output signal, FullPeriod = 1/F
So:
<b> P = [(1/F) - 0.00162333)/0.00001 </b> if I've got my maths right !

So, for MiddleC say, which is 278Hz, this gives P = 197. So the idea was to calculate all the constants for all sorts of notes, perhaps bung them in EEPROM.

I've used my scope and my loop time is seen as 1.2ms not 0.811ms ....which is a bit worrying, although could be the PICAXE clock ??

<code><pre><font size=2 face='Courier'>
Symbol Counter = w1
Symbol MiddleC = 197
Symbol NoteDuration = 60000

setfreq m8

PlayNote:
For Counter = 1 To NoteDuration
Pulsout 2, MiddleC 'to dummy pin just to get precise delay
Toggle 3
Next
Goto PlayNote
</font></pre></code>

Somehow I think this might not have the resolution to get the frequencies spot on, and it will sound a bit detuned !!


Edited by - jeremy leach on 07/01/2007 20:29:26
 

Jeremy Leach

Senior Member
Putting the maths aside, I just had a laugh, and here's a sweeping siren sound ...ish !

<code><pre><font size=2 face='Courier'>
Symbol NoteValue = b0
Symbol Counter = w1
Symbol MiddleC = 197
Symbol NoteDuration = 20

setfreq m8

Main:
For NoteValue = 0 to 60
For Counter = 1 To NoteDuration
Pulsout 2,NoteValue
Toggle 3
Next
Next
Goto Main
</font></pre></code>

Also, have just thought, that you could combine this 'bit-banged' signal with a PWMout signal (shifted down in frequency by method used in recent topic by Dippy) and possibly get flanging and phasing effects.

Edited by - Jeremy Leach on 08/01/2007 12:29:15
 

moxhamj

New Member
You should be able to get all the frequencies with a simple excel spreadsheet. Leaving aside the fact that no-one can agree on the frequency of middle C http://hypertextbook.com/facts/2003/DanielleDaly.shtml

the easiest way to calculate frequencies is to start at A of 440, and work up or down by multiplying/dividing each previous note by 2^(1/12). This gives 277.18 for C. The frequencies in that website were 262 to 278.43. A twelfth root of 2 scale at least sounds ok to me, even though my musical friends say it isn't quite correct.
 

Jeremy Leach

Senior Member
This turned into a bit of a challenge. Here's some code that plays a well-known rock 'riff' (but don't get too excited !).

This is just proving that you don't need the tune command to play a tune, so might help on other picaxes besides the 08M.

I must say it did take a bit of working out, and I've got a separate spreadsheet I could post on my website if anyone's interested.

The code takes approx 50 bytes of program space which isn't bad...

<code><pre><font size=2 face='Courier'>
#rem
###########################################
# #
# PICAXE BitBangedTunes Module #
# #
# Code version :1a #
# Status :Working #
# Date :January 2007 #
# PICAXE Type :18X (and other) #
# Editor Software :5.07 #
# Author: Jeremy Leach #
# #
###########################################

INTRODUCTION
This code allow Tunes to be played on PICAXEs that don't support
the Tune command.

Separate spreadsheet used to calculate values for the tune.

#endrem

'###########################################
'## EEPROM ##
'###########################################

'Note Data. Starting at 0. Used for the Pulseout value.
EEPROM 1,(242) 'B3, 246Hz
EEPROM 2,(219) 'C4 261Hz (Middle C)
EEPROM 3,(198) 'C# 277Hz
EEPROM 4,(178) 'D 293Hz
EEPROM 5,(159) 'D# 311Hz
EEPROM 6,(141) 'E 329Hz
EEPROM 7,(124) 'F 349Hz
EEPROM 8,(107) 'F# 369Hz
EEPROM 9,(92) 'G 391Hz
EEPROM 10,(78) 'G# 415Hz
EEPROM 11,(64) 'A 440Hz (American Standard Pitch)
EEPROM 12,(52) 'A# 466Hz
EEPROM 13,(40) 'B 493Hz
EEPROM 14,(28) 'C 523Hz
EEPROM 15,(18) 'C# 554Hz
EEPROM 16,(7) 'D 587Hz

'Music Data, starting at 200.
'(Credits of this 'riff' from the 'Final countdown'1986 hit single, to
'the Swedish hard rock band Europe.)

EEPROM 200,(13,24)
EEPROM 202,(11,21)
EEPROM 204,(13,98)
EEPROM 206,(6,164)
EEPROM 208,(14,26)
EEPROM 210,(13,24)
EEPROM 212,(14,52)
EEPROM 214,(13,49)
EEPROM 216,(11,219)
EEPROM 218,(14,26)
EEPROM 220,(13,24)
EEPROM 222,(14,104)
EEPROM 224,(6,65)
EEPROM 226,(8,110)
EEPROM 228,(11,21)
EEPROM 230,(9,19)
EEPROM 232,(11,43)
EEPROM 234,(9,39)
EEPROM 236,(8,36)
EEPROM 238,(11,43)
EEPROM 240,(9,117)

'###########################################
'## CONSTANTS ##
'###########################################

Symbol TuneStartAddress = 200
Symbol TuneEndAddress = 240

'###########################################
'## VARIABLES ##
'###########################################

'Word0 (b0 and b1)
Symbol NoteDuration = w0
'Word1 (b2 and b3)
Symbol PulseCounter = w1

'Word2 (b4 and b5)
Symbol PulseValue = b4
Symbol TuneAddress = b5
'Word3 (b6 and b7)
Symbol Pair = w3
Symbol Pair_NoteIndex = b6
Symbol Pair_Duration = b7

'###########################################
'## INITIALISE ##
'###########################################

setfreq m8

'###########################################
'## MAIN ##
'###########################################

Main:
Gosub PlayTune
Pause 1000
Goto Main

PlayTune:
'Plays the Tume stored in EEPROM

For TuneAddress = TuneStartAddress to TuneEndAddress Step 2
'Get the next note and duration pair
Read TuneAddress,Word Pair

'Lookup the PulseValue
Read Pair_NoteIndex,PulseValue

'Calculate the duration value
NoteDuration = Pair_Duration * 4

'Play the note
For PulseCounter = 1 To NoteDuration
Pulsout 2, PulseValue 'to dummy pin just to get precise delay
Toggle 3
Next
Next
Return
</font></pre></code>
 

piclt

Member
I tried your prog and it works very well.
I had been using something similar to play sound depending on the state of some of the input pins. eg. In my case I had the speaker connected to pulsout pin.

checkpins:
if input0 = 1 then playone
if input1 = 1 then playtwo
etc, etc

goto checkpins


playone:
pulsout 2,430 'gave me note A low sound
pause 2
if input0 &lt;&gt; 1 then checkpins
goto playone

playtwo:
pulsout 2,246 ' gave me note A an octave higher
if input1 &lt;&gt; 1 then checkpins
goto playtwo

etc, etc

when I tried your Pulsout followed by Toggle I had to reduce the pulse length to 184 and no pause for the low note, I needed pulsout 2,0 to give me the higher note. I had the speaker connected to the Toggle pin.
If I connect speaker to pulsout pin I get higher pitch ?? and more scope for adjusting pitch by the pulse length.

Along similar lines I have been trying out ISD / Winbond sound record/play chips to do the same type of thing but I find they are too slow (approx 50 - 100 msecs) to start to play the sound for short events that happen quickly. The event is over before the sound has played. Generated sounds are OK but I was wanting to get more realistic sound by recording actual sounds. The problem is the processing time for the chips to start to play and also the delay in stopping the play. I would want to be able to play sounds for events of approx 20 msecs duration occurring at 20 msecs intervals. once the event has occurred I do not know how long it will be but I want the same sound to play for the duration of the event, If it is short I want a &quot;chirp&quot; and if it is long I want it to continue with the same long note.
I was wondering has anybody experience of using any other sound chips or playing wav files or mp3 files from EPROM etc.
Thanks, piclt
 

Jeremy Leach

Senior Member
Hi

I'm not expert here, but would guess EEPROM and PICAXEs in general are far too slow to get actual wave data back from. I think you'd need external RAM and decicated Dig-To-Analogue converters. I played around with a home-built echo unit using assembler, RAM and a DAC years ago. I bet there are specialised chips out there that do it all for you though.

ANY additional code in the core loop of my module will cause the code not to work properly. I've done a lot of calculation to get the values right, and it was all made possible by the Timer1 routines, allowing me to time (in a test program) the precise execution times.

Note how the value for the duration of the note is based on the number of cycles played. So to get the same duration at different pitches will require different cycle counts ! Even though it's hard to work out initially, once it's in a spreadsheet it's easy to change and seemed the most efficient way of producing a tune without the Tune command.

A while back I posted an idea about using some 08Ms to provide polyphony - I'm still tempted to give this a go !

 
Top