live-sequencer: Live coding of MIDI music

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Warnings:

An editor shows a textual description of music (like Haskore), an interpreter computes and emits a stream of MIDI events, and (that's the main point) the user can change the program on the fly. Additionally the state of the interpreter is shown in the form of the current reduced term for educational and debugging purposes.


[Skip to Readme]

Properties

Versions 0.0, 0.0.1, 0.0.2, 0.0.3, 0.0.3.1, 0.0.4, 0.0.5, 0.0.5.1, 0.0.5.2, 0.0.6, 0.0.6, 0.0.6.1, 0.0.6.2, 0.0.6.3
Change log ChangeLog
Dependencies alsa-core (>=0.5 && <0.6), alsa-seq (>=0.6 && <0.7), base (>=4.2 && <5), bytestring (>=0.9 && <0.11), cgi (>=3001.1 && <3001.4), concurrent-split (>=0.0 && <0.1), containers (>=0.3 && <0.6), data-accessor (>=0.2.1 && <0.3), data-accessor-transformers (>=0.2.1 && <0.3), directory (>=1.0 && <1.4), event-list (>=0.0.11 && <0.2), explicit-exception (>=0.1.5 && <0.2), filepath (>=1.1 && <1.5), html (>=1.0 && <1.1), httpd-shed (>=0.4 && <0.5), midi (>=0.2.1 && <0.3), midi-alsa (>=0.2 && <0.3), network (>=2.6 && <2.7), network-uri (>=2.6 && <2.7), non-empty (>=0.2 && <0.4), non-negative (>=0.0.6 && <0.2), parsec (>=2.1 && <3.2), pretty (>=1.0 && <1.2), process (>=1.0 && <1.5), stm (>=2.2 && <2.5), stm-split (>=0.0 && <0.1), strict (>=0.3.2 && <0.4), transformers (>=0.2.2 && <0.6), unix (>=2.4 && <2.8), utility-ht (>=0.0.8 && <0.1), wx (>=0.12.1 && <0.93), wxcore (>=0.13.2 && <0.93) [details]
License LicenseRef-GPL
Author Henning Thielemann and Johannes Waldmann
Maintainer Henning Thielemann <haskell@henning-thielemann.de>, Johannes Waldmann <waldmann@imn.htwk-leipzig.de>
Category Sound, Music, GUI
Home page http://www.haskell.org/haskellwiki/Live-Sequencer
Bug tracker https://hub.darcs.net/thielema/livesequencer
Source repo head: darcs get https://hub.darcs.net/thielema/livesequencer
this: darcs get https://hub.darcs.net/thielema/livesequencer --tag 0.0.6
Uploaded by HenningThielemann at 2017-07-15T14:33:40Z

Modules

[Index]

Flags

Automatic Flags
NameDescriptionDefault
gui

Build the wxWidgets GUI for the sequencer

Enabled
mplayer

Build the remote controller to the mplayer

Enabled
httpserver

Enable access to modules via a web browser

Enabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for live-sequencer-0.0.6

[back to package description]

Example usage

The live-sequencer does not make music itself, its entire task is to control other software or hardware synthesizers. That is, in order to hear something you need a working MIDI synthesizer such as the sampling based software synthesizer TiMidity. You may run TiMidity and the live-sequencer this way:

timidity -iA &
live-sequencer-gui --connect-to TiMidity Simplesong &

This should give you an ongoing stream of notes. Then change one of the numbers that appear in the lines like qn = 300 and press CTRL-R for "reloading" that module into the interpreter. This should immediately have an effect, namely increasing the tempo of the melody. You may also alter a note name like c 4 to cis 4, then reload, then undo the modification and reload, again, after a while. This is the main idea of changing the song while it is playing. The way the changes are applied warrants that the change takes effect when the time comes. Music is not interrupted and does not need to be restarted for reacting to changes.

The overall task performed by the sequencer is to lazily evaluate a term called main that is a list of events. The value of main is a stream of midi events (On/Off pitch velocity, PgmChange, Controller) or (Wait milliseconds). You may wrap a MIDI event in a Channel constructor in order to assign the event to the particular MIDI channel. If you omit this constructor then the event is put to channel 0.

In each step, the head of the main stream gets reduced to head normal form (with : at the top), and the first arg of the : gets fully expanded and it must be a MIDI event.

Input language

The used language is syntactically almost a subset of Haskell with only strict pattern matching and pattern matching only at the definition level (no case), no local bindings (no lambda, let, where), no types (no type inference, type signatures and type declarations are skipped), and with diet syntax (i.e. drastically reduced syntactic sugar, like no layout rule, no do syntax, no list comprehension, no operator sections).

Semantics is similar to lazy evaluation, but we have no sharing. The design goal is that code can be changed while the program is running. This implies that evaluation of one expression may give different results at different times (e.g., during a live performance, one changes some chords of a musical theme). In turn, this implies that we do not store and share results of evaluations, hence, we don't have local bindings.

You may import and use the special functions 'Controller.checkBox', 'Controller.slider' from the "Controller" module. For every call to these functions a widget is added to the control window and the state of the widget is the result of the function call. Technically every change of these widgets internally adds or updates a rule in the "Controller" module. The effect is very similar to updating a value definition in a module and then reloading that module to the interpreter, but using the widgets is more intuitive.

Offline rendering

In the library interface of this package we provide the basic Live-Sequencer modules in order to allow offline rendering of music that you programmed within the Live-Sequencer. You may generate a standard MIDI file using functions from the "Render" module. To this end load your song module into GHCi and call

YourModule> Render.writeStream "yoursong.mid" yourSong

HTTP access

You may open a browser and view all modules under http://localhost:8080/. If the user of the GUI inserts comments like this one:

----------------

, then it is possible to modify the content below this mark via HTTP. This way multiple people can participate in the composition process. The recommended situation is a room with a data projector and a loudspeaker, where the conductor explains the functions to the auditory and the participants can watch the screen and listen to the music.

You may choose any other port using the command line option --http-port. If you want to use a system port like the standard HTTP port 80, we recommend to configure a firewall to redirect the external port 80 to the internal user port. We discourage from starting the live-sequencer as root user. You may disable the HTTP server altogether by compiling with cabal install -f-httpServer.

Execution modes

There are three modes of execution that you can choose from the Execution menu:

Editing

You can change a module name by altering the module identifier between the module and where keywords and then triggering module reload. The same way you can load new modules by adding import lines and reloading the module. Alternatively, you may create new modules or close old ones using functions from the File menu.

For composition it is useful to play parts of the music. You can do this by simply placing the cursor within an identifier or by marking an expression and then call Play term from the Execution menu. This will make the marked expression the current term and start playing.

Once the music is playing you can change it by altering the module and reload it. However you may find out that you cannot do a certain modification this way. In this case you can mark an expression that denotes a stream transformation function and call the Apply term menu item. This will apply the marked function to the current term. Useful functions are:

Limits

Without some safety belts it would be very easy to consume all memory or all processing power by accident or by people who contribute malicious code via HTTP. Thus we have added some limits. These have reasonable default values but you can adjust them to your needs via command line options at startup. These are the limits you can set:

ALSA

Using the --new-out-port option you may add more ALSA MIDI ports. Every port extends the range of MIDI channels by 16 new logical channels. That is Channel 40 ev sends an event to MIDI channel 8 at the second newly added ALSA port (because 40 = 2*16+8). Every --connect-to option refers to the latest added port. Example:

live-sequencer --connect-to Synth0 --new-out-port out1 --connect-to Synth1 --new-out-port out2 --connect-to Synth2

You do not need to connect to any synthesizer at startup. You may connect or disconnect the live-sequencer to any synthesizer once it is running using aconnect (command line) or kaconnect, alsa-patch-bay, patchage (graphical interfaces).

The live-sequencer itself can be controlled to some extent. You may start the live-sequencer this way

live-sequencer --connect-from YourMidiController

or connect to it once it is running. This enables the following functions:

The supported MMC commands are:

Tips & Tricks

Append with overlap

The (+:+) operator can only handle precise concatenation of event streams. However, in common music you also have to handle upbeats and legato. Technically, this means that there may be events before and after a core part. First, let us consider the case where there are events after the core part. We define a Block data structure containing two or more parallel Tracks. For simplicity we now use only two tracks:

type Track = [Event Message] ;
data Block = Block Track Track ;

The first track specifies the length of the block. It cannot overlap. If you have no other use for it, fill it with rests. The second track can be shorter or longer than the first track. Everything longer will be merged with subsequent Blocks. This is, how we convert a sequence of overlapping blocks to a plain Event stream:

consBlock :: Block -> [Event Message] -> [Event Message] ;
consBlock (Block t0 t1) y  =  t0 +:+ y  =:=  t1 ;

concatBlocks :: [Block] -> [Event Message] ;
concatBlocks = foldr consBlock [] ;

Blocks with events before a core part must be handled by delaying every block by the maximum time that an event can occur before the core.

Tempo changes

Changing the tempo within a song is a bit tricky, especially in the presence of overlapping blocks (see above). You want

The best I could come up with is to extend the Midi.Message data type by a SetTempo constructor. After you have comletely composed the song you scan the event stream for these constructors and change the Wait events accordingly. The LiveSequencer language is untyped, thus you could simply use a SetTempo constructor as if it were a constructor of Midi.Message. Though, for Haskell compatibility I suggest you wrap Midi.Message in a custom datatype that adds the SetTempo constructor.

The MIDI file format and ALSA sequencer even support a SetTempo statement natively. However, we cannot easily make use of it, since it is not obvious how to merge streams containing SetTempo in the general case.