PDA

View Full Version : BS2 Code Help for "arrays"

TonyA
07-30-2005, 04:12 AM
Hi,

This is modified code based on a midi out example in O'Sullivan's book "Physical Computing".

Notice the "array". I was wondering how I could go about creating 12 of these arrays, whose elements would be the notes of each of the 12 musical keys. So I thought there would be a total of 12 arrays (like the one in the example), each array would have 8 elements (which are the 8 notes of each musical key). My idea was to have a rotary switch that could be used to switch to different input pins, each diff input pin would be responcible for each of the 12 different arrays, hence you can switch to different keys.

But, when I tried adding the 12 arrays I received the "out of variable space" message. So I'm wondering if any more experienced programmers here might be able to offer advice or referrences. It would be greatly appreciated. Thank you in advance for any help.

(I've only worked with analog stuff before last week, I just learning pBasic, so maybe my idea can be simplified via programming.) I can post the code I wrote with the 12 different "arrays" if it would be useful.

' the 12 elements of the array called pitch are 12 notes of a scale.
pitch(0) = 58' middle C
pitch(1) = 35' C#
pitch(2) = 62' D
pitch(3) = 63' D#
pitch(4) = 74' E
pitch(5) = 87' F
pitch(6) = 52' F#
pitch(7) = 67' G
pitch(8) = 68' A
pitch(9) = 69' A#
pitch(10) = 70' B
pitch(11) = 100' C

Main:
' This is the note section. The sensor goes on pin 8, midiout is on pin 7
'
HIGH 8
PAUSE 1
RCTIME 8, 1, RCTIMEVar
note = RCTIMEVar / 60 ' convert to a range from 0 to 11
SEROUT 7, 12, [\$90, pitch(note), \$40]
'etc.

Paul Baker
07-30-2005, 04:38 AM
The Stamp has a total of 26 bytes availible for data space, your proposed arrays would require 96 bytes, clearly this would not work. Instead you should use the LOOKUP command since the values are constants.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
·1+1=10

TonyA
07-30-2005, 04:54 AM
Hi Paul,

Thank you. Could you give me an example of how I would use LOOKUP in this case?

Tony

Paul Baker
07-30-2005, 05:05 AM
Here (http://www.parallax.com/dl/docs/prod/stamps/BasicStampMan.pdf#page=269) is the page of the Stamp Documentation covering the LOOKUP command.

For the code you supplied the corresponding LOOKUP version would be:

LOOKUP index, [58, 35, 62, 63, 74, 87, 52, 67, 68, 69, 70, 100], result

index is the same value you used in defining your index, LOOKUP retrieves the value at location index and returns the value in result. You should have as few LOOKUP commands in your code since each occurance in the code results all the values being stored in your program space which leads to unnessesary code bloat. If you have serveral places in your program you need to access the same LOOKUP list, place the LOOKUP in a subroutine and call the subroutine instead.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
·1+1=10

TonyA
07-30-2005, 05:16 AM
Hi Paul,

Thanks again. I see what you did. But what if I had 12 arrays each containing a different set of elements? Do I write that LOOKUP command 12 times (for the 12 arrays) or just once and put all of the different elements inside?

Tony

Jon Williams
07-30-2005, 05:23 AM
Another approach is to store your values in DATA statements and then retrieve what you want with READ.· Let's say you had a 3x3 array that looked like this:

Notes··· DATA··· 10, 20, 30
········ DATA··· 40, 50, 60
········ DATA··· 70, 80, 90

You could keep two variables (nibs would work for your app) that store the row and col.· If you wanted to get the value from row #2, column #0 you could get it like this:

· READ (Notes * row + col), result

... which would return 70 in result.· By naming your table and using the name in the equation, it can be placed in anywhere, even when other DATA statments are used.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

Post Edited (Jon Williams (Parallax)) : 7/29/2005 10:30:32 PM GMT

TonyA
07-30-2005, 05:28 AM
Hi,

I'm starting to understand. I'll try both LOOKUP and DATA. Thanks again, Paul & John.

Tony

Paul Baker
07-30-2005, 05:42 AM
TonyA said...
Hi Paul,

Thanks again. I see what you did. But what if I had 12 arrays each containing a different set of elements? Do I write that LOOKUP command 12 times (for the 12 arrays) or just once and put all of the different elements inside?

Tony
This would be a design choice of yours, since you could fit all 96 values in a single LOOKUP you could go with one large array, or you can split it into 12 arrays for more readability of your code.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
·1+1=10

TonyA
07-30-2005, 08:01 AM
Hi,

Would it look something like this:

index VAR Byte
result VAR Byte
rctimeVar VAR Word

HIGH pin#
PAUSE 1
RCTIME pin#, 1, rctimeVar

LOOKUP index, [values of the notes in the key of C...], result

LOOKUP index, [values of the notes in the key of C sharp...], result

(etc. up to 12 "LOOKUPs" for each musical key?)

index = rctimeVar/x (or would this be: result = rctimeVar/x) ' converts to a suitable range for the sensor or pot used.

serout pin#, baud, [\$90, index1, \$40]

How do you distinguish between each "index". Would you make each "index" a variable like index1, index2, etc.?

If "index" retrieves values (in my case the values are the notes in a particular key), I will need "index" to be a variable in order to constantly retrieve different values at any given time (it will need to retreive different notes in the key based on the input of a pot or other sensor using RCTime, etc.

Thanks again for any insight.
Tony

Jon Williams
07-30-2005, 08:10 AM
Can you explain your ultimate goal? Functionally, that is. I think your use of code (that you're just coming to grips with) is interfering with you questions. You seem to be wanting to send MIDI notes based on potentiometer inputs. Right? Explain what you're wanting to build and I think you'll find that the code is ultimately easier that what you're currently thinking. And I think DATA will be far cleaner to execute than LOOKUP.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

TonyA
07-30-2005, 10:11 AM
Hi Jon,

Thanks for your help, I appreciate it very much.

The code I posted at the beginning of the thread (above) contained an "array" of notes for a simple midi out program that uses a variable resistor (pot or fsr, or photocell). The original program above is based on what I saw in O'Sullivan's book. With that program you can play all notes, but my idea is to be able to switch to different keys.

My goal is to build a midi controller that will allow you to switch to each of the 12 musical keys (i.e., key of C, key of C#, Key of D, and so on). Suppose I turn a 12 position rotary switch to the key of D, I will only be able to play the 8 notes of the key of D using my photocell or pot, then I swith to key of F#, I'll then only be able to play the 8 notes in the key of F#, and so on.

I want to write a program that will allow you to choose a specific musical key. I need to be able to choose from any of the 12 keys (each key would of course contain the 8 notes of that specific key) and be able to play any of the notes in that chosen key by using an fsr, or pot, or photocell.

Just to show you the inspiration for this idea here is the code based on O'Sullivan's example uses 1 array with 12 elements like this:

' the 12 elements of the array called pitch are 12 notes of a scale.

pitch(0) = 58' middle C
pitch(1) = 35' C#
pitch(2) = 62' D
pitch(3) = 63' D#
pitch(4) = 74' E
pitch(5) = 87' F
pitch(6) = 52' F#
pitch(7) = 67' G
pitch(8) = 68' A
pitch(9) = 69' A#
pitch(10) = 70' B
pitch(11) = 100' C

Main:
' This is the note section. The sensor goes on pin 8, midiout is on pin 7
'
HIGH 8
PAUSE 1
RCTIME 8, 1, RCTIMEVar
note = RCTIMEVar / 60 ' convert to a range from 0 to 11
SEROUT 7, 12, [\$90, pitch(note), \$40]
'etc.

I thought I could just make 12 arrays (one array for each of the 12 musical keys), and each of the 12 arrays would contain 8 elements which are the 8 notes of each key, but I have a lot of learning to do.

I'm still studying the DATA and LOOKUP commands. Hopefully one day I'll understand :)

Thanks again
Tony

Jon Williams
07-30-2005, 10:36 AM
Photocells are really tricky to control; potentiometers on the other hand -- piece of cake.· If you use our "standard" RCTIME circuit with a 10K pot and 0.1 uF cap (with inline 220), you should get RCTIME values up to 630.· If you divide that by 53 you'll get 0 - 11.· By using two pots you can create your note index.·

I whipped this up on my PDB and it works as expected.· Add a second version for reading the octave.· Valid MIDI notes are 0 - 127, so that is something less than the 144 a 12x12 array would give you, and the lowest note on the piano is well above 0, the highest well below 127.· I think your octave section -- if you want to stick to valid piano notes -- needs only to be 8 (0..7).

Here's the pot code:

Get_Note:
· HIGH NotePot
· PAUSE 1
· RCTIME NotePot, 1, noteVal
· noteVal = noteVal / 53
· RETURN

The variable, noteVal, is a Word.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

Jon Williams
07-30-2005, 10:50 AM
Doing a quick search I found this table -- it can be translated into DATA statements with no trouble at all.· What you should do is pad non note values with \$FF to serve as a marker for an invalide note/octave.

http://forums.parallax.com/attachment.php?attachmentid=73671

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

TonyA
07-30-2005, 08:09 PM
Hi Jon,

This is very cool, but where I am confused is how to set up the DATA statements, and then how to refer to the DATA in my main code.

(But I am slowly starting to see how this works. You mentioned using 2 pots; one for the col and one for the row?)

Thanks again, very much appreciated.

Tony

Jon Williams
07-30-2005, 09:15 PM
Okay, I've attached a full program that should get you going.· Have fun ... it's Saturday, I'm going out for the rest of the day!

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

TonyA
07-31-2005, 04:04 AM
Hi Jon,

That's awesome. I'm studying what you did and I'll see if I can come up with my own versions. Thanks very much for the tremendous help, it's greatly appreciated.

Tony

Jon Williams
07-31-2005, 05:08 AM
You're welcome. Now buy lots of BASIC Stamps ... and tell your friends to do the same thing! ;)

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

TonyA
08-01-2005, 11:33 PM
Hi Jon,

One thing I'm working on is having multiple DATA tables (11 all together), that are referenced via different input pins and pots.

Each DATA table would consist of only the notes in a certain Key (rather than all notes and all octaves), with a couple of upper octaves and a couple of lower octaves for each key.

Something like this:

C, D, E, F, G, A, B, C
KeyofCmajor DATA Oct, Oct, Oct, etc.
DATA, etc.
DATA, etc.

C#, etc
KeyofCsharp DATA Oct, Oct, Oct, etc.
DATA, etc.
DATA, etc.

D, etc.
KeyofD DATA Oct, Oct, Oct, etc.
DATA, etc.
DATA, etc.

Coming up with the DATA tables will be fine, but I wonder if I'll run out of eeprom space or variable space. And also I'm working out who to reference eack individual DATA table.

Thanks for any insight.

Tony

TonyA
08-01-2005, 11:34 PM
The above table didn't post correctly, I'll wil scan a file.

Jon Williams
08-02-2005, 12:12 AM
Well, Tony, you seem to want to do things the hard way -- which is okay by me, but ultimately you're creating more work for youself and those of us trying to help you. My point is this: If you have a table of all valid notes, it can be accessed by anything. It's okay to have different pots, just point to the section of the table that you want. If you have one pot per octave, read its note setting (0..11), then read the line of the notes table that corresponds to the pot.

Am I missing something? There's only 128 valid MIDI notes, so the table in the example I provided is all the EE space you should need. You can of course break that big table into smaller ones, but I don't think it will make your program any more effective.

If you want to give each octave a name, you can do it like this:

' C C# D D# E F F# G G# A A# B
'
Oct_N1 DATA 000,001,002,003,004,005,006,007,008,009,010,011
Oct_00 DATA 012,013,014,015,016,017,018,019,020,021,022,023
Oct_01 DATA 024,025,026,027,028,029,030,031,032,033,034,035
Oct_02 DATA 036,037,038,039,040,041,042,043,044,045,046,047
Oct_03 DATA 048,049,050,051,052,053,054,055,056,057,058,059
Oct_04 DATA 060,061,062,063,064,065,066,067,068,069,070,071
Oct_05 DATA 072,073,074,075,076,077,078,079,080,081,082,083
Oct_06 DATA 084,085,086,087,088,089,090,091,092,093,094,095
Oct_07 DATA 096,097,098,099,100,101,102,103,104,105,106,107
Oct_08 DATA 108,109,110,111,112,113,114,115,116,117,118,119
Oct_09 DATA 120,121,122,123,124,125,126,127,\$FF,\$FF,\$FF,\$FF

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

Post Edited (Jon Williams (Parallax)) : 8/1/2005 5:16:34 PM GMT

Jon Williams
08-02-2005, 12:18 AM
Maybe I am missing something ... are you wanting to create a scale in each key? Please help me understand why you need more than one table.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

TonyA
08-02-2005, 12:40 AM
Hi John,

Yes, That's exactly it. I'm trying to create a scale in each key, that's why I thought of having multiple DATA tabes. There would be a rotary switch that would allow to acess the different scales via different input pins.

Suppose I had a force sensitive resistor that was attached to a 12 position rotary switch, I could access each pf 12 input pins, each input pin would access via programming each of 12 scales.

I have some idea of how to set of the individual DATA tables with the scales, etc.

I see what you did in your previous example, naming the octaves. Would it be possible to just change each octave to just different scales, or would I need to create a new table for each scale.

Does that make sense? I'm sorry for any confusion, I really do appreciate all of the help, I am learning a lot from you.

Thank you,
Tony

Yanroy
08-02-2005, 12:52 AM
Most of this music stuff is completely over my head, but from my limited understanding it seems to me that if you just switch the X and Y axes of the table, it'll solve the problem?· I could be way off base here...

TonyA
08-02-2005, 01:06 AM
Hi,

I don't think that would work, Yanow but thanks for your input, I appreciate it. Let's see if I can simplify what I'm trying to explain.

Jon's DATA table is great. But what if I just wanted to select a particular scale of notes to play, not all of the midi notes.

You select the DATA table that contains only the notes in the key of F#. Now when you play with your pot, or FSR you can only produce the notes of the scale F# and its octaves, no other notes are allowed. Then you want to switch to the scale C major, well then you can only play the notes in C major and its octaves, etc.

I think with the great help from Jon I can construct the DATA tables for each scale with octaves. I'll try to come up with something and then post it here.

I would have an FSR that would trigger the notes, then a pot that would switch ocatves in the scale, and then a rotary switch that will switch the FSR to different input pins, different input pins would allow access to the different DATA tables and hence different scales. Although, I'm not sure yet if I would need to access different input pins for this to occur.

Thanks again,
Tony

Yanroy
08-02-2005, 01:14 AM
To do what you're suggesting using one table, wouldn't it mean using the pot to change either the row/column and then the other input to change the other axis coordinate?· By doing that, you're essentially limiting yourself to a subset of the table - pretend it's a seperate table.· I still don't fully understand your problem here, but it seems to me that Jon's solution is perfect.

Jon Williams
08-02-2005, 01:19 AM
What you might do is create a table that contains the scale. Since the difference from one note to another in a given scale is constant, you could in fact just use the offsets in your scale table. A routine to play that scale would set the base note and play from there -- kind of like a guitar player does (I play a little) when sliding the left (frets) hand up or down the neck. The shape of the pattern is constant, just the starting position changes.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

TonyA
08-02-2005, 01:32 AM
Yanroy,

Yes, I would use one pot for changing the note values and another for changing the octave values, which is what I want. But I was thinking of using separate DATA tables, one for each scale (12 major scales). We don't need to add separate tables for the minor scales because we can just play the relative minor scales of each major scale (just start on a different note, like playing a mode).

Thanks again,
Tony

Jon Williams
08-02-2005, 01:43 AM
I suggest you leave the Notes table as is and create scales tables -- not by key but by the scale itself.· The values in the scales tables would be the notes to play, relative to some current base.· Like this:

Silly··· DATA··· 3, 0, 2, 4

The first value in the table is the number of notes -- the rest are the note values relative to a base.· You would set the base note (hence key) before calling a routine that might look like this:

PlayScale:
· LOOKUP scale, [Scale1, Scale2, Scale3], scaleAddr······· ' get address of scale
· FOR idx = 1 TO numNotes··································' cycle through scale
··· READ Notes + baseNote + offset, theNote··············· ' get note from table
··· SEROUt MidiOut, Baud, [\$90, theNote, velocity]·········' send to MIDI device
··· PAUSE NoteTiming······································ ' delay as required
· NEXT
· RETURN

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

TonyA
08-02-2005, 05:29 AM
Jon,

I think I came up with something. It's a much larger program with 12 DATA tables. I used the first program you wrote as a guide.

(I'm not sure, but I think I am not communicating the actual use of this prog clearly enough here, this is my fault. I think maybe if you saw what I wrote, even if it's wrong you'd probably see what I'm trying to do, and then probably show me a huge short cut.)

I'm pretty sure it could be condensed and made into a much smaller/cleaner prog. But I am learning a lot, particularly from your use of constants, subroutines, the use of eeprom data and read command.

I still have to study the new ideas you wrote, using the LOOKUP command above.

As soon as I check to see if it actually works and get my nerve up I'll post so you can have a look.

Thanks again for the great help and eductaion.

Tony