%%% ************************************************************* %%% Copyright (C) 2002-2005 Torsten Anders (www.torsten-anders.de) %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License %%% as published by the Free Software Foundation; either version 2 %%% of the License, or (at your option) any later version. %%% This program is distributed in the hope that it will be useful, %%% but WITHOUT ANY WARRANTY; without even the implied warranty of %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %%% GNU General Public License for more details. %%% ************************************************************* /** %% This functor defines means to output MIDI files. To this end, it makes use of csvmidi (see http://www.fourmilab.ch/webtools/midicsv/). A text file in midicsv file format is output which is transformed into a MIDI file by csvmidi. %% %% The top-level definitions exported by this functor are procedures like OutputMidiFile, RenderMidiFile, PlayMidiFile, and RenderAndPlayMidiFile. Like Strasheela output into other formats (e.g., Csound or Lilypond), the output into MIDI files is primarily customised by clauses which define how certain score objects are transformed into MIDI events. This functor provides low-level functions for outputting virtually every MIDI event possible (e.g., MakeNoteOn, MakeNoteOff, MakeCC) and some higher level functions which simplify the definition of clauses (e.g., NoteToUserEvent, NoteToMidi, NoteToPitchbend). Further functionality is also provided. These include the class MidiNote, some Boolean functions (e.g., HasType, IsNoteOn, HasChannel), and conversion functions (e.g., BeatsToTicks, CentToPitchbend). Several examples demonstrate these procedures (e.g., in strasheela/examples/ the files ContinuousCOntrollersInScore-MidiOutput.oz and Microtonal-MIDI-examples.oz). %% %% The documentation of the lower-level functions in this functor often quotes the documentation of csvmidi for the csv / MIDI event the function creates. %% %% General typing information: %% %% Time: an integer representing the absolute time in MIDI clocks %% Channel: an integer in 0-15 (?) %% Track: an integer identifying the track to which this record belongs. Tracks of MIDI data are numbered starting at 1. Track 0 is reserved for file header, information, and end of file records. %% Text: an atom as 'my Text' %% %% %% Information on internals %% %% An intermediate format is used for the transformation process: on the Oz side, each record in the CSV representation is represented by an Oz record with label csv and the features track (an int), time (an int), and type (an atom). For exammple csv(track:1 time:0 type:'Start_track') %% Additionally, a record may have feature parameters with a list of type-specific parameters, as in the following example (the note on parameters are [Channel Note Velocity]). csv(track:2 time:0 type:'Note_on_c' parameters:[1 79 81]) % or this exammple (the controller parameters are [Channel ControlNum Value]) csv(track:2 time:0 type:'Control_c' parameters:[1 7 64]) %% The feature values track and time and integers (see above). Type is a virtual string corresponding to a type in the CSV file format specification (see the end of http://www.fourmilab.ch/webtools/midicsv/). The parameters are a list of values permitted in a virtual string and follow the CSV specification. For example, a title record has the format (note the explicit double quotes, according to the CSV spec). csv(track:1 time:0 type:'Title_t' parameters:['\"This is my Title\"']) %% An CSV score is represented internally by a list of these records. %% See the CSV documentation (or the MidiOutput.oz source) for details on the various CSV types. %% %% %% */ %% TODO: %% %% * BUG: the tempo setting, e.g., {Init.setTempo 150.0} possibly affects the length on equal note length in uneven way. Has this to do with the resolution / division? %% -> I fixed a bug in BeatsToTicks: is now this issue completely fixed? %% %% %% functor import % System GUtils at 'GeneralUtils.ozf' LUtils at 'ListUtils.ozf' Out at 'Output.ozf' Init at 'Init.ozf' Score at 'ScoreCore.ozf' export OutputMidiFile % play: PlayMidiFile PlayMidiFile RenderAndPlayMidiFile MakeCSVScore ScoreToEvents_Midi OutputCSVScore OutputCSVScore2 CSVScoreToVS % render: RenderMidiFile RenderMidiFile MakeComment MakeTitle MakeCopyright MakeInstrumentName MakeMarker MakeCuePoint MakeLyric MakeText MakeSequenceNumber MakeMidiPort MakeChannelPrefix MakeTimeSignature MakeKeySignature MakeTempo BeatsPerMinuteToTempoNumber MakeSMPTEOffset MakeSequencerSpecific MakeUnknownMetaEvent MakeNoteOn MakeNoteOff MakePitchBend MakeCC MakeProgramChange MakeChannelAftertouch MakePolyAftertouch MakeSystemExclusive MakeSystemExclusivePacket IsCSVEvent HasType IsNoteOn IsNoteOff HasChannel % MakeMidiNote BeatsToTicks TicksToBeats CentToPitchbend MidiNoteMixin IsMidiNoteMixin MidiNote NoteToMidi NoteToPitchbend NoteToUserEvent SetDivision GetChannel prepare MidiNoteMixinType = {Name.new} define %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% Generic and structural interface %% %% Any line with an initial nonblank character of ``#'' or ``;'' is ignored; either delimiter may be used to introduce comments in a CSV file. Only full-line comments are permitted; you cannot use these delimiters to terminate scanning of a regular data record. Completely blank lines are ignored. /** %% [aux fun] Generic CSV representation creator %% Track (integer) identifies the track to which this record belongs. Tracks of MIDI data are numbered starting at 1. Track 0 is reserved for file header, information, and end of file records. Args is a record of the form csv(track: time: