Big problems should be tackled in a small steps. First let's create a function transpose_objet
that will take a single object with a single transposition, i.e., a shift, and returns a new object, that is transposed in a pitch by the specified shift.
(** [transpose_objet obj shift] takes a musical object [obj] and
transposes it pitch to a value [shift] *)
let rec transpose_objet obj shift : objet_musical = match obj with
| Note (h,v,d) -> Note (h + shift, v, d)
| Silence t -> Silence t
| Sequence objs ->
Sequence (List.map (fun obj -> transpose_objet obj shift) objs)
| Parallel objs ->
Parallel (List.map (fun obj -> transpose_objet obj shift) objs)
Next, let's try to create a chord of three transpositions. So we take a triplet and an object and play it in a parallel (I think that is what chord stands for). We will name this function chord_of_transposition
.
(** [chord_of_transposition obj tlist] takes a musical [obj] and a triplet,
where every element of triplet is a number to which the pitch
should be transposed, and creates a chord *)
let chord_of_transposition obj (t1,t2,t3) : objet_musical =
Parallel [transpose_objet obj t1;
transpose_objet obj t2;
transpose_objet obj t3]
With this handy functions, we can tackle a list of composition triplets. Let's write a function chords_of_transpositions
So we would like to take a musical object and list of transpositions, and create a chord from each transposition. And we would like it to be still a musical object, so we create from a resulting list an object using constructor Sequence
.
(** [chords_of_transpositions obj transpositions] takes a list of
triplets, where each element of triplet is value by which a
musical object should be shifted and creates a sequence of musical
objects that will play a chords from each transposition. *)
let chords_of_transpositions obj ts : objet_musical =
Sequence (List.map (chord_of_transposition obj) ts)
As an exercise, I would suggest you, to rewrite function chord_of_composition
without the ugly repetition (hint, use List.map
).
As a second exercise, try to remove code repetitions from transpose_objet
function. Did you noticed that patterns for Parallel
and Sequence
clause are the same.
As a third exercise, try to rewrite your code, so that your transposition list consists not from triplets, but from n-plets, like this:
let transposition = [[0;4;7];[0;3;7]; [0;8]; []; [0;3;6]]
where empty list stands for silencing.
Answer to a new question
Question
I try this
let seq1= Sequence((Note(60,100,1000)):: (Note (64,100,500)):: (Note (62,100,500)):: (Silence(1000)):: (Note (67,100,1000)):: [])
and
let transposition= [(0,4,7);(0,3,7);(0,4,8);(0,3,6)];;
and your proposition
let chordify om tp : objet_musical= Sequence (List.map (chordify om)tp);;
and the test
let test= chordify seq1 transposition;;
but top Ocaml return
Error: This expression has type (int * int * int) list but an expression was expected of type int list list Type int * int * int is not compatible with type int list .
How to solve it?
Answer
First of all, I would like to note, that we are starting to push to hard on SO. It is a question/answer site, not a forum. I've made some work for you, but I do not see, that you're trying to do your part. I'm here not to do your homework, but to help you with general questions on OCaml and programming. My advice would be start from a good textbook about OCaml and learn it first. Just trying to randomly copy-paste code, until compiles is not a good idea. Now, back to your question.
First of all, instead of building list in a such crude way like 1 :: 2 :: 3 :: []
you can use a more conviniet notation: [1;2;3]
. So that your sequence can be rewritten in a following way:
let seq1 = Sequence [
Note (60,100,1000);
Note (64,100,500);
Note (62,100,500);
Silence (1000);
Note (67,100,1000)
]
Next, your function
let chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
refers to some unbound symbol chordify
. If you want to call a function inside its own body, you need to make it recursive, i.e., to add rec
to the let
expression:
let rec chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
I think, that you have accedantaly pushed this function twice to OCaml top-level, so that effectively you've made the followint definition.
let chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
let chordify om tp : objet_musical =
Sequence (List.map (chordify om) tp)
But instead, what do you really want to do, is to not to call function cordify
but to call function chord_of_transposition
that will transform an objet_musical
accroding with a particular instance of transposition, something like this:
let chordify om tp : objet_musical =
Sequence (List.map (chord_of_transposition om) tp)
So we come out with a defintion equal to the definition of a function chords_of_transpositions
, that I have provided previously.