Shop OBEX P1 Docs P2 Docs Learn Events
MIDI-Stamp Primer?? — Parallax Forums

MIDI-Stamp Primer??

edited 2009-05-19 20:27 in BASIC Stamp
· --OK here's the deal: I've got no musical abilities at all, but I've gone ahead and built a 12-note solenoid-operated calliope. I'm commanding the solenoids on/off with a BS2 and pBasic, but it's really a cumbersome task to program it this way. What I'd like to do is find some *simple* tunes, somehow·make them·12-note compatible, then 'automatically' load·it as·something the Stamp can process. Anyone got suggestions about reading matter or canned routines to do something like this?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
························ Hacking the Trailing Edge!
················http://www.nmpproducts.com/intro.htm
················---Decks a-wash in a sea of words---

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-10-21 22:55
    You might be able to modify Parallax's RTTTL (ringtone) Player to do what you want. Then you'd have a vast library of tunes you could download from the web and play.

    Your calliope sounds pretty neat! Can you post some photos?

    -Phil
  • edited 2008-10-22 16:40
    ·Haven't taken any recent photos but here's the 'learning curve' blog: http://www.nmpproducts.com/wbjan08.htm
    ·Tell me more about this gadget; got a part number??

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ························ Hacking the Trailing Edge!
    ················http://www.nmpproducts.com/intro.htm
    ················---Decks a-wash in a sea of words---
  • edited 2008-10-24 02:07
    · OK gang I'm a little farther down the road now and I've discovered RTTTL, which reeeeally seems like the way to go. Next thing I've gotta do is find·where I can download the 4 *pages* of code needed to make it happen (Chapter 8, pp 251-255).·Then I can somehow·give frequencies equivalent pinout commands and I'm good to go, yes?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ························ Hacking the Trailing Edge!
    ················http://www.nmpproducts.com/intro.htm
    ················---Decks a-wash in a sea of words---
  • edited 2008-10-27 16:29
    · --Followup to followup: had a visitation from Kris, who sorted out my difficulties with the converion of ringtones to pinout commands. We made a lookup table that sorted it out. Once I finally figured out that my Stamp had 3 bad pinouts we had it sussed. Although tuning still needs a little tweaking, here's a video of the results: http://www.youtube.com/watch?v=Ifq7Z9ZSBl0

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ························ Hacking the Trailing Edge!
    ················http://www.nmpproducts.com/intro.htm
    ················---Decks a-wash in a sea of words---
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-10-27 17:43
    Too cool! Thanks for posting the photo and video links!

    -Phil
  • edited 2008-10-31 17:52
    · --Thot I'd better post the code that Kris and Rich helped me figure out. In its present state it plays the Wallace and Grommit theme, but there are a couple of other tunes 'remmed' out. Curiously I can *not* get the Looney Tunes file to play at all. Can anyone spot the problem?



    ' What's a Microcontroller - MicroMusicWithRtttl.bs2
    ' Play Nokia RTTTL format ringtones using DATA.
    '{$STAMP BS2}
    '{$PBASIC 2.5}
    '
    [noparse][[/noparse] I/O Definitions ]
    · SpeakerPin···· CON···· 15·················· ' Piezospeaker connected to P11.
    '
    [noparse][[/noparse] Variables ]
    · counter······· VAR···· Word··············· ' General purpose counter.
    · char·········· VAR···· Byte··············· ' Variable stores characters.
    · index········· VAR···· Word··············· ' Index for pointing at data.
    · noteLetter···· VAR···· Byte··············· ' Stores note character.
    · noteFreq······ VAR···· Word··············· ' Stores note frequency.
    · notePin······· VAR···· Byte··············· ' turns pin numbers into outputs
    · noteOctave···· VAR···· Word··············· ' Stores note octave.
    · duration······ VAR···· Word··············· ' Stores note duration.
    · tempo········· VAR···· Word··············· ' Stores tempo.
    · default_d····· VAR···· Byte··············· ' Stores default duration.
    · default_o····· VAR···· Byte··············· ' Stores default octave.
    · default_b····· VAR···· Word··············· ' Stores default beats/min.
    · value········· VAR···· Byte
    '
    [noparse][[/noparse] EEPROM Data ]

    '· RTTTL_File····· DATA··· "Flint:d=32,o=7,b=300:a#,p,a#,p,8b,p,a#,p,b,p,8c#6,p,b,p,c#6,p,8d#6,p,c#6,p,b,p,8a#,p,a#,p,a#,p,8b."

    '·· RTTTL_File····· DATA···· "Looney:d=8,o=6,b=140:C,F,E,D,C,4A5,C,F,E,D,D#,4E,E,E,C,D,C,E,C,D,A5,C,G5,A#5,A5,F5"

    ·'· RTTTL_File····· DATA··· "PirateLife:d=4,o=5,b=100:8a.,8c.6,8d.6,8c6,16a#,8a,16a,8g,",
    ·'························· "16g,f,16p,16a,16a.,32p,16a,16a,16a,16a,16a,16a,16a,16a,16a,",
    ·'························· "16a,16d.6,32p,16a,16f,16f,16g,16a.,p,16a,16a#,16a#,16a#,16g,",
    ·'························· "16g,16g,16a,16a,16a,16f,16f,16f,16g,16g,16g,16g,16a,16b,8c6,16p,"'
    ·'························· "16p,8a.,8c.6,8d.6,8c6,16a#,8a,16a,8g,16g,f,16p"

    · RTTTL_File······ DATA··· "Wallace And Gromit Theme:d=4,o=7,b=112:c6,16a#,16p,16a,",
    ··························· "16p,c6,16a#,16p,16a,16p,16c6,16p,2g,p,8d6,16c6,16p,16d6,",
    ··························· "16p,e6,16d6,16p,16c6,16p,16a#,16p,2a,p,c6,16a#,16p,16a,16p,",
    ··························· "c6,16a#,16p,16a,16p,16c6,16p,2g,p,8d6,16c6,16p,16d6,16p,8e6,",
    ··························· "16p,d6,16e6,16p,16f6"

    '· RTTTL_File····· DATA···· "Scale:d=32,o=7,b=50:c,c#,d,d#,e,f,f#,g,g#,a,a#,b"

    ' RTTTL_File···· DATA··· "Reveille:d=4,o=7,b=140:8g6,8c,16e,16c,8g6,8e,",
    '················· ············· "8c,16e,16c,8g6,8e,8c,16e,16c,8a6,8c,e,8c,8g6,",
    '········ ················ ····· "8c,16e,16c,8g6,8e,8c,16e,16c,8g6,8e,8c,16e,",
    '······ ···················· ··· "16c,8g6,8e,c,p,8e,8e,8e,8e,g,8e,8c,8e,8c,8e,8c,",
    '··· ························ ·· "e,8c,8e,8e,8e,8e,8e,g,8e,8c,8e,8c,8g6,8g6,c."
    · Done·········· DATA··· ",q,"
    · Notes········· DATA···· "p",······ "a",······ "#",······ "b",
    ························· "c",······ "#",······ "d",······ "#",
    ························· "e",······ "f",······ "#",······ "g",
    ························· "#"
    · pins·········· DATA···· 0,········ 1,········ %10,······ %100,
    ························· %1000,···· %10000,··· %100000,·· %1000000,
    ························· %10000000, %1,······· %10,······ %100,
    ························· %1000
    · Octave8······· DATA··· Word 0,··· Word 3520, Word 3729, Word 3951,
    ························ Word 4186, Word 4435, Word 4699, Word 4978,
    ························ Word 5274, Word 5588, Word 5920, Word 6272,
    ························ Word 6645

    '
    [noparse][[/noparse] Initialization ]
    · counter = 0······························· ' Initialize counter.
    · GOSUB FindEquals·························· ' Find first '=' in file.
    · GOSUB ProcessDuration····················· ' Get default duration.
    · GOSUB FindEquals·························· ' Find next '='.
    · GOSUB ProcessOctave······················· ' Get default octave.
    · GOSUB FindEquals·························· ' Find last '='.
    · GOSUB GetTempo···························· ' Get default tempo.
    '
    [noparse][[/noparse] Program Code ]
    · DO UNTIL char = "q"······················· ' Loop until 'q' in DATA.
    ··· GOSUB ProcessDuration··················· ' Get note duration.
    ··· GOSUB ProcessNote······················· ' Get index value of note.
    ··· GOSUB CheckForDot······················· ' If dot, 3/2 duration.
    ··· GOSUB ProcessOctave····················· ' Get octave.
    ··· GOSUB PlayNote·························· ' Get freq, play note, next.
    · LOOP······································ ' End of main loop.
    · END······································· ' End of program.
    '
    [noparse][[/noparse] Subroutine - Find Equals Character ]
    · FindEquals:······························· ' Go through characters in
    ············································ ' RTTTL file looking for
    ··· DO······································ ' '='.· Increment counter
    ····· READ RTTTL_File + counter, char······· ' until '=' is found, then
    ····· counter = counter + 1················· ' return.
    ··· LOOP UNTIL char = "="
    ··· RETURN
    '
    [noparse][[/noparse] Subroutine - Read Tempo from RTTTL Header ]
    ' Each keyboard character has a unique number called an ASCII value.
    ' The characters 0, 1, 2,...9 have ASCII values of 48, 49, 50,...57.
    ' You can always convert from the character representing a digit to
    ' to its value by subtracting 48 from the variable storing the digit.
    ' You can examine this by comparing DEBUG DEC 49 and DEBUG 49.
    · GetTempo:································· ' Parse RTTTL file for Tempo.
    ············································ ' Convert characters to
    ··· default_b = 0··························· ' digits by subtracting 48
    ··· DO······································ ' from each character's ASCII
    ····· READ RTTTL_File + counter, char······· ' value.· Iteratively multiply
    ····· IF char = ":" THEN···················· ' each digit by 10 if there
    ······· default_b = default_b / 10·········· ' is another digit, then add
    ······· counter = counter + 1··············· ' the most recent digit to
    ······· EXIT································ ' one's column.
    ····· ENDIF································· ' For example, the string
    ······· default_b = default_b + char - 48··· ' "120" is (1 X 10 X 10)
    ······· counter = counter + 1··············· ' + (2 X 10) + 0.· The '1'
    ······· default_b = default_b * 10·········· ' is converted first, then
    ··· LOOP UNTIL char = ":"··················· ' multiplied by 10.· The '2'
    ············································ ' is then converted/added.
    ··· RETURN·································· ' 0 is converted/added, done.
    '
    [noparse][[/noparse] Subroutine - Look up Octave ]
    · ProcessOctave:···························· ' Octave may or may not be
    ············································ ' included in a given note
    ··· READ RTTTL_File + counter, char········· ' because any note that is
    ··· SELECT char····························· ' played in the default
    ····· CASE "5" TO "8"······················· ' octave does not specify
    ······· noteOctave = char - "0"············· ' the octave.· If a char
    ······· counter = counter + 1··············· ' from '5' to '8' then use
    ····· CASE ELSE····························· ' it, else use default_o.
    ······· noteOctave = default_o·············· ' Characters are converted
    ··· ENDSELECT······························· ' to digits by subtracting
    ··· IF default_o = 0 THEN··················· ' '0', which is the same as
    ····· default_o = noteOctave················ ' subtracting 48. The first
    ··· ENDIF··································· ' time this subroutine is
    ············································ ' called, default_o is 0.
    ··· RETURN·································· ' If 0, then set default_o.
    '
    [noparse][[/noparse] Subroutine - Find Index of Note ]
    · ProcessNote:······························ ' Set index value for lookup
    ············································ ' of note frequency based on
    ··· READ RTTTL_File + counter, char········· ' note character. If 'p',
    ··· SELECT char····························· ' index is 0.· If 'a' to 'g',
    ····· CASE "p"······························ ' read character values in
    ······· index = 0··························· ' DATA table and find match.
    ······· counter = counter + 1··············· ' Record index value when
    ····· CASE "a" TO "g"······················· ' match is found.· If next
    ······· FOR index = 1 TO 12················· ' char is a sharp (#), add
    ········· READ Notes + index, noteLetter···· ' 1 to the index value to
    ········· IF noteLetter = char THEN EXIT···· ' increase the index (and
    ······· NEXT································ ' frequency) by 1 notch.
    ······· counter = counter + 1··············· ' As with other subroutines,
    ······· READ RTTTL_File + counter, char····· ' increment counter for each
    ······· SELECT char························· ' character that is processed.
    ········· CASE "#"
    ··········· index = index + 1
    ··········· counter = counter + 1
    ······· ENDSELECT
    ··· ENDSELECT
    ··· RETURN

    '
    [noparse][[/noparse] Subroutine - Determine Note Duration ]
    · ProcessDuration:·························· ' Check to see if characters
    ············································ ' form 1, 2, 4, 8, 16 or 32.
    ··· READ RTTTL_File + counter, char········· ' If yes, then convert from
    ············································ ' ASCII character to a value
    ··· SELECT char····························· ' by subtracting 48. In the
    ····· CASE "1", "2", "3", "4", "8"·········· ' case of 16 or 32, multiply
    ······· duration = char - 48················ ' by 10 and add the next
    ······· counter = counter + 1··············· ' digit to the ones column.
    ······· READ RTTTL_File + counter, char
    ······· SELECT char
    ········· CASE "6", "2"
    ··········· duration = duration * 10 + char - 48
    ··········· counter = counter + 1
    ······· ENDSELECT
    ······· CASE ELSE··························· ' If no duration, use
    ······· duration = default_d················ ' use default.
    ··· ENDSELECT
    ··· IF default_d <> 0 THEN·················· ' If default_d not defined
    ····· duration = 60000/default_b/duration*3· ' (if default_d = 0), then
    ··· ELSE···································· ' set default_d = to the
    ····· default_d = duration·················· ' duration from the d=#.
    ··· ENDIF
    ··· RETURN
    '
    [noparse][[/noparse] Subroutine - Check For '.' Indicating 1.5 Duration ]
    · CheckForDot:······························ ' Check for dot indicating
    ············································ ' multiply duration by 3/2.
    ··· READ RTTTL_File + counter, char········· ' If dot found, multiply by
    ··· SELECT char····························· ' 3/2 and increment counter,
    ····· CASE "."······························ ' else, do nothing and
    ······· duration = duration * 3 / 2········· ' return.
    ······· counter = counter + 1
    ··· ENDSELECT
    ··· RETURN
    '
    [noparse][[/noparse] Subroutine - Find Comma and Play Note/Duration ]
    · PlayNote:································· ' Find last comma in the
    ············································ ' current note entry.· Then,
    ··· READ RTTTL_File + counter, char········· ' fetch the note frequency
    ··· SELECT char····························· ' from data, and play it, or
    ····· CASE ","······························ ' pause if frequency = 0.
    ······· counter = counter + 1
    ······· READ Octave8 + (index * 2), Word noteFreq

    ·· '···· LOOKDOWN noteLetter, [noparse][[/noparse]"a", "a#", "b", "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#"], notePin
    ······· LOOKDOWN noteFreq, [noparse][[/noparse]4186, 4435, 4699, 4978,
    ·························· 5274, 5588, 5920, 6272, 6645, 3520, 3729, 3951], notePin
    ······· noteOctave = 8 - noteOctave
    ······· noteFreq = noteFreq / (DCD noteOctave)
    ······· DEBUG noteLetter, " = ", DEC notePin, " : ", "noteFreq = ", DEC noteFreq, CR
    ······· IF noteFreq = 0 THEN
    ········· PAUSE duration
    ······· ELSE
    ········· HIGH notePin······································ ' LED will remain on
    ········· FREQOUT SpeakerPin, duration, noteFreq············ ' all the time the speaker is
    ········· LOW notePin······································· ' playing so don't delete the FREQOUT
    ······· ENDIF
    ··· ENDSELECT
    ··· RETURN

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ························ Hacking the Trailing Edge!
    ················http://www.nmpproducts.com/intro.htm
    ················---Decks a-wash in a sea of words---
  • edited 2009-05-19 20:27
    · Howdy all! Update to update: new video of Calliope #4 here:
    http://www.youtube.com/watch?v=vKG3MYgIeMc&feature=related
    · ...and new software for use with proto driver board with 12: TIP-120s currently on another machine; will post that later today.
    · Hope to have all and sundry at upcoming Makers Faire at San Mateo County Fairgrounds on May 30-31. I'll have a hand-out with all the URLs and some sordid details of construction.·Come on·by and say hi!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ························ Hacking the Trailing Edge!
    ················http://www.nmpproducts.com/intro.htm
    ················---Decks a-wash in a sea of words---
Sign In or Register to comment.