I’m wondering if someone might help me with a problem that has me stumped. I’m new to Scala, but have some experience with c, Pascal and Erlang.
I’m writing some music software and have a class called ‘Note’. It is constructed as:
class Note (
var delta: Int = 0, // time until event occurs
var pitch: Int = 0, // middle C = 60
var velocity: Int = 0, // amplitude corresponds to MIDI velocity
var duration: Int = 0,
var panposition: Int = 0
)
I need to construct a two-dimensional data structure that has two different types: one, an Int, so that I can access the musical track as 0, 1 etc. – and the other, a mutable list of notes as shown above.
Conceptually, the is would be: Array[Int][Note]
Clearly an Array.ofDim doesn’t work as the types are different and I’ve feel like I’m groping in the dark with ListBuffers, tuples, etc. Any suggestion as to how to do this would be most welcome.
If you just want something indexed by integers, use Array[Array[Note]] where the Array[Note] is the track, and the other array holds the tracks in order. (You could also use Vector or ArrayBuffer instead of Array, depending on what features you want the collection to have. ArrayBuffer would be the best choice for something that can be appended to; Vector is good if you want it immutable entirely; Array allows you to change the elements but not the length.)
If for some reason the indexing might be sparse, you can as Dave suggested, use a Map[Int, Array[Note]]. (Where again, Array should perhaps be an ArrayBuffer or something else.)
error: missing argument list for method apply in class GenMapFactory
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing apply _ or apply(_) instead of apply.
var myNoteBuffer = Map[Int, ListBuffer[Note]]
Thanks everyone. After much flailing around – and since the actual components of the type Note are all Ints, the easiest solution seems to be to create a three dimensional array of Ints, as in:
var noteBuffer = Array.ofDim[Int](NumTracks, MaxBuf, NoteParameters)
While you certainly can do this, you’ve basically lost all type safety by
doing so. Nothing will be preventing you from accidentally storing a
note.pitch into the wrong element of your 3d array, except much vigilance
(and as usage grows, the chance of this being correct drops dramatically)
I’m with Dave on this. An Array[Array[Note]] would be better, but perhaps even better than that would be a Map[NoteKey, Note] where NoteKey is a case class that has the two Ints you normally use to look up the Note. This solution would be particularly beneficial if your array is sparse. You want the NoteKey to be a case class because that will automatically provide you with a good hashCode method for using with a Map.
The 245th note in one track of music has no interesting relationship with the 245th note in another. Changing from nested indices to a NoteKey lookup is therefore not a good idea: it obscures the important relationship (sequential notes) and is awkward.
Having notes parameterized in an ordered way inside a class is a good idea, though.
I don’t know a lot about music, but I would guess a note is a value, not a mutable object with an identity. So a case class Note (without vars) would make more sense to me, and will probably make writing this program a lot less painful.