-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBasicHaskToMidi.lhs
104 lines (88 loc) · 4.8 KB
/
BasicHaskToMidi.lhs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
\section{Midi}
\label{midi}
Midi (``musical instrument digital interface'') is a standard protocol
adopted by most, if not all, manufacturers of electronic instruments.
At its core is a protocol for communicating {\em musical events} (note
on, note off, key press, etc.) as well as so-called {\em meta events}
(select synthesizer patch, change volume, etc.). Beyond the logical
protocol, the Midi standard also specifies electrical signal
characteristics and cabling details. In addition, it specifies what
is known as a {\em standard Midi file} which any Midi-compatible
software package should be able to recognize.
Over the years musicians and manufacturers decided that they also
wanted a standard way to refer to {\em common} or {\em general}
instruments such as ``acoustic grand piano,'' ``electric piano,''
``violin,'' and ``acoustic bass,'' as well as more exotic ones such as
``chorus aahs,'' ``voice oohs,'' ``bird tweet,'' and ``helicopter.''
A simple standard known as {\em General Midi} was developed to fill
this role. It is nothing more than an agreed-upon list of instrument
names along with a {\em program patch number} for each, a parameter in
the Midi standard that is used to select a Midi instrument's sound.
Most ``sound-blaster''-like sound cards on conventional PC's know
about Midi, as well as General Midi. However, the sound generated by
such modules, and the sound produced from the typically-scrawny
speakers on most PC's, is often poor. It is best to use an
outboard keyboard or tone generator, which are attached to a computer
via a Midi interface and cables. It is possible to connect several
Midi instruments to the same computer, with each assigned a different
{\em channel}. Modern keyboards and tone generators are quite amazing
little beasts. Not only is the sound quite good (when played on a
good stereo system), but they are also usually {\em multi-timbral},
which means they are able to generate many different sounds
simultaneously, as well as {\em polyphonic}, meaning that simultaneous
instantiations of the same sound are possible.
Note: If you decide to use the General midi features of your
sound-card, you need to know about another set of conventions known as
``Basic Midi'' which is not discussed here. The most important aspect
of Basic Midi is that Channel 10 is dedicated to {\em percussion}. A
future release of Haskore should make these distinctions more concrete.
Haskore provides a way to specify a Midi channel number and General
Midi instrument selection for each {\tt IName} in a Haskore
composition. It also provides a means to generate a Standard Midi
File, which can then be played using any conventional Midi software.
In this section the top-level code needed by the user to invoke this
functionality will be described; the extended document contains all of
the gory details.
\begin{verbatim}
> module HaskToMidi (module HaskToMidi, module GeneralMidi, module MidiFile)
> where
>
> import Basics
> import Performance
> import MidiFile
> import GeneralMidi
> import List(partition)
> import Char(toLower,toUpper)
\end{verbatim}
Instead of converting a Haskore {\tt Performance} directly into a Midi
file, Haskore first converts it into a datatype that {\em represents}
a Midi file, which is then written to a file in a separate pass. This
separation of concerns makes the structure of the Midi file clearer,
makes debugging easier, and provides a natural path for extending
Haskore's functionality with direct Midi capability (in fact there is
a version of Haskore that does this under Windows '95, but it is not
described here).
A {\tt UserPatchMap} is a user-supplied table for mapping instrument
names ({\tt IName}'s) to Midi channels and General Midi patch names.
The patch names are by default General Midi names, although the user
can also provide a {\tt PatchMap} for mapping Patch Names to
unconventional Midi Program Change numbers.
\begin{verbatim}
> type UserPatchMap = [(IName,GenMidiName,MidiChannel)]
\end{verbatim}
See Appendix \ref{test-functions} for an example of a useful user
patch map.
Given a {\tt UserPatchMap}, a performance is converted to a datatype
representing a Standard Midi File using the {\tt performToMidi}
function.
\begin{verbatim}
> performToMidi :: Performance -> UserPatchMap -> MidiFile
> performToMidi pf pMap =
> MidiFile mfType (Ticks division)
> (map (performToMEvs pMap) (splitByInst pf))
\end{verbatim}
A table of General Midi assignments called {\tt genMidiMap} is
imported from {\tt GeneralMidi} in Appendix~\ref{general-midi}. The
Midi file datatype itself and functions for writing it to files are
imported from the module {\tt MidiFile}, briefly described below. The
remaining details are omitted in the basic version of this document.