Music-logic with LUA scripts
LUA scripts in Expresseur
Expresseur uses LUA to script the music logic. LUA is simple but powerfull script language. It has a very efficient pre-compiled engine.
The LUA gives the possibility to add-change easily the music logic.
Example :
- Adapt the behavior to specific MIDI instruments
- Use other sound generator ( e.g. play sound wav files )
- Extend to other modules ( e.g. MIDI to vibrations, MIDI to screen-animation, .. )
The Graphic User Interface ( GUI ) uses by default these LUA scripts :
- expresseur.lua : contains the midi-in callbacks functions, and the end-user logic. This filename can be set in the GUI
- These LUA modules are automatically loaded by the GUI, as global module
- luachord.lua : contains the functions to interpret a text file with chords, which uses
- texttochord.lua : contains the function which translate a string in a structure ( chord/scale )
- luascore.lua : contains the functions to interpret a score structure, pushed by the GUI
- luabass.lua : to drive midi-outputs
To develop new behavior with LUA, it is possible to edit the LUA scripts in any text editor. But it is recommended to use IDE to test before to implement ( e.g. zerobrane )
The global API-LUA Expresseur package can be used without the GUI. The expresscmd.exe is delivered as an example, to build a command-line tool.
LUA script with expressmd
"expresscmd" is a tinny command line tool, already available in the package. You have just to script your music logic, using LUA language.
This tinny "expresscmd" does this :
- load your LUA script ( by default "expresscmd.lua" )
- include the following library :
- basslua : to capture midi-event, and trigger your LUA script on midi-events
- luabass : to generate midi-out ( on SF2, VSTi, Midi-devices, wav files )
- luachord : to interprete a text score ( like in the Graphic User Interface )
- luascore : to interpret a pre-compiled musicxml score
- Wait for optional commands on the standard input ( an LUA-function in your script with optional parameters )
Recommendation :
- Copy the whole expresseur package in "my_project" directory ( eg in your documents repository )
- In "my_project", copy "lua/expresscmd.lua" in "lua/myscript.lua"
- Script your music-logic in "lua/myscript.lua"
- In a terminal, change working-directory to "my_project" directory
- run "expresscmd myscript.lua"
- For intensive usage, you can save time using LUA-IDE ( eg zerobrane )
Create your own Graphic User Interface
If you want to build your own Graphic User Interface ( eg C++, python, ... ), you can build it over the API already available in the package.
The GUI will have to start "basslua.dll" .That is the only package seen by the GUI
the basslua.dll will loads by default the other components :
- lua engine
- basslua : to capture midi-event, and trigger your LUA script on midi-events
- luabass : to generate midi-out ( on SF2, VSTi, Midi-devices, wav files )
- luachord : to interprete a text score ( like in the Graphic User Interface )
- luascore : to interpret a pre-compiled musicxml score
Licence
The Expresseur-API uses BASS/un4seen ( for SF2, ASIO, multithread audio)). This Bass/un4seen is not a freeware ...
Global schema of the MIDI workflow, GUI, and API of the Expresseur
Documentation of the API
The LUA script loaded by basslua ( using the API, expresscmd, or the GUI ) must have :
- a function onStart(), with optional parameters. It is called after the initialisation of the script
- a function onStop() : before to stop this script
- a table midiinOpen={} to specify midi-in devices to open ( list of midi-in device number )
- optional functions, with optional parameters, to be called from expresscmd command line
- optional functions to catch events form MIDI-inputs :
- onMidi(device,t,type,channel,data1,data2) : return an optional MIDI message for the next functions
- onNoteOff(device,t,channel,pitch,velocity)
- onNoteOn(device,t,channel,pitch,velocity)
- onControl(device,t,channel,control_nr,control_value)
- onProgram(device,t,channel,program_nr)
- onChannelPressure(device,t,channel,value)
- onPitchBend(device,t,channel,value)
- onSystemCommon(device,t,b1,b2,b3)
- onSyssx(device,t,hexadecimal_string)
- onActive(device,t)
- onClock(device,t)
- onTimer(t) : cascaded periodical trigger :(GUI => basslua => luabass)
Midi-out note-on conflict management
To manage conflict of same pitch on same channel, the API uses the "extended midi-channel". One midi-channel can be "linked" to additional channel on the same device, to play multi note-on on same pitch/channel.
LuaBass API
An LUA script can use the functions of luabass C-module ( loaded by default in global _G ) :
- midi device section
- inGetMidiList
- return: table of midi-in device
- inGetMidiName
- parameter #1 : [1..] nr
- return : name of the midi-in device
- outGetMidiList
- return: table of midi-out device
- outGetMidiName
- parameter #1 : [1..] nr
- return : name of the midi-out device
- track section
-
outTrackOpenMidi :
open the track on a midi out -
parameter #1 : integer track nr
-
-
parameter #3 : string setting instrument initial ( eg mypiano(P0/C10/2)
-
-
parameter #5 : optional number of additional physical MIDI channels attached to this MIDI channel ( default 0 )
-
-
parameter #7 : optional localoff. Default true
-
- parameter #1 : integer track nr
- parameter #2 : integer midi channel
- parameter #3 : string initial
-
- parameter #5 : optional , integer, number of additional physical MIDI channels attached to this MIDI channel ( default 0 )
-
- parameter #7 : optional integer, audio ( ASIO for PC ) device nr. Default g_default_audio_device, or as defined in parameter #4
- outTracksClose : close all the tracks
-
outTrackMute :
It's different than an audio volume on the channel using note ctrl7 !!
- parameter #1 : mute = 0, unmute = 1, toggle = 2
-
parameter #2 : optional nrTrack ( default 1 )
- outSetTrackVolume : set reack volume. Different than an audio volume on the channel using note ctrl-7 !!
- parameter #1 : volume 0..64(neutral)..127
- parameter #2 : optional nrTrack ( default 1 )
- outGetVolumeTrack
- parameter #1 : optional nr track ( default 1 )
- return current volume
-
outSetTrackInstrument :
set instrument for a track . -
parameter #1 : string which describe the instrument required. eg "pianoleft(P0,C10/1)"
-
- outSetVolume : set global volume, over all tracks
- parameter #1 : 1..127
- ouGetVolume : get the global volume
- return the global volume 1..127
- chord section : to manage a table of pitches as an object
- outSetChordCompensation
- parameter #1 : [0..32] compensation of the mitigate different number of notes in chords
- outSetRandomDelay
- parameter #1 : [0..256] random delay in ms
- outSetRandomVelocity
- parameter #1 : [0..50 ] random velocity
- outChordSet :
set the chord to play with outChordOn
- parameter #1 : unique_id . With -1 : return a unique-id
- parameter #2 : transpose
- parameter #3 : [0..] delay in ms between notes
- parameter #4 : ([0..50..100]) % dvelocity between notes ( 50 all equal, 25 divide by two for next note )
- parameter #5 & #6 : start# and end# of pitches ( 1 & -1 : all pitches , -1 & 1 : all in reverse order )
- parameter #7.. : list of pitch
- return the unique_id
- outChordOn : play a chord prepared by chordset
- parameter #1 : unique_id ( set in outChordSet )
- parameter #2 : velocity
- parameter #3 : optional integer delay dt in ms before to send the msg
- parameter #4 : optional nrTrack ( default 0 )
- outChordOff :
stop a chord played with chordon
- parameter #1 : unique_id ( set in outChordSet )
- parameter #2 : optional velocity, default 0
- parameter #3 : optional integer delay dt in ms before to send the msg
- Midi-event section
- outNoteOn
- parameter #1 : pitch 1..127
- parameter #2 : optional velocity ( default 64 )
-
parameter #3 : optional unique id. ( to manage concurrential note-on note-off )
. Default 0 .With -1 : a unique_id is returned
- parameter #4 : optional integer delay dt in ms before to send the msg
- parameter #5 : optional nrTrack ( default 1 )
- return the unique id
- outNoteOff
- parameter #1 : pitch 1..127 ( if parameter "unique id " is defined, this parameter can be = 0 )
- parameter #2 : optional velocity, default 0
- parameter #3 : optional unique id ( to manage concurrential note-on note-off )
- parameter #4 : optional integer delay dt in ms before to send the msg
- parameter #5 : optional nrTrack ( default 1 )
- outPressure
- parameter #1 : pitch
- parameter #2 : pressure
- parameter #3 : optional integer delay dt in ms before to send the msg
- parameter #4 : optional nrTrack ( default 1 )
- outControl
-
parameter #1 : nr control
- parameter #2 : data
-
parameter #3 : optional integer delay dt in ms before to send the msg
- parameter #4 : optional nrTrack ( default 1 )
- outProgram
-
parameter #1 : nr program
- parameter #2 : optional integer delay dt in ms before to send the msg
-
parameter #3 : optional nrTrack ( default 1 )
- parameter #4 : optional bank msb
-
parameter #5 : optional bank lsb
- outPitchbend
- parameter #1 : value -8192 ..0..8192
- parameter #2 : optional integer delay dt in ms before to send the msg
- parameter #3 : optional nrTrack ( default 1 )
- outChannelPressure
- parameter #1 : value
- parameter #2 : optional integer delay dt in ms before to send the msg
- parameter #3 : optional nrTrack ( default 1 )
- outTune
- parameter #1 : optional, float, A4 Frequency Hz ( default 440 Hz )
- parameter #2 : optional nrTrack ( default 1 )
- outBendRange
- parameter #1 : semitone , integer , ( default 1 )
- parameter #2 : optional nrTrack ( default 1 )
- outClock
- parameter #1 : optional delay dt in ms before to send the msg
- parameter #2 : optional integer track ( default 1 )
- outSystem
- parameter #1 : byte 1
- parameter #2 : byte 2
- parameter #3 : byte 3
- parameter #4 : optional delay dt in ms before to send the msg
- parameter #5 : optional integer track ( default 1 )
- outSysex
- parameter #1 : text hexa message sysex ( eg ""F0 7E 7F 09 01 F7" )
- parameter #2 : optional integer track ( default 0 )
- Audio section
- audioClose : close all the audio streams
- getAudioList
- return the list of audio devices
- getAudioName
- parameter #1 : nr device
- return the name of the audio device
- audioAsioSet : open the setting of the ASIO device ( PC only )
- parameter #1 : nr device
- return : buffer length
- audioAsioBuflenSet
-
-
parameter #1 : Buffer length in samples ( 0 :use the prefereed one )
-
audioDefaultDevice :
set audio default device ( to be called before any use of audio ( vi, wav ... ) -
parameter #1 : audio_device 1..
- outSoundPlay
- parameter #1 : audio file name, with its extension ( end of name can be "@audio_device", to plug this sond in the non-default audio-output )
- parameter #2 : optional volume 0..64..127
- parameter #3 : optional pan 0..64..127
- parameter #4 : optional integer, audio ( ASIO for PC ) device nr, default g_default_audio_device
- return : ref for further manipulation
- outSoundControl
- parameter #1 : reference to audio ( returned by sound_play )
- parameter #2 : optional volume 0..64..127
- parameter #3 : optional pan 0..64..127
- parameter #4 : control the sound : 0=pause, 1=restart, 2=stop
- Virtual Instrument section ( VI )
- outListProgramVi :
- create text files, with instruments available in the VI. The text file has the same name than the VI, but with txt etxension
- parameter #1 : VI file name, with its .sf2 or .dll extension
- viVolume : set the volume of a midi Virtual Instrument
- parameter #1 : VI track ( returned by vi_open )
- parameter #2 : volume 0..64..127
- post-Midi-out section
-
onMidiOut
- set a LUA script for each midiout msg
- this script contains optional functions :
-
onNoteOn(track,pitch,velocity) : process midiout noteon
- onNoteOff(track,pitch,velocity) : process midiout noteoff
-
onProgram(track,program) : process midiout program
- onControl(track,control,value) : process midiout control
-
onPitchbend(track,value) : process midiout pitchbend
- onChannelPressure(track,value) : process midiout channel pressure
-
onKeyPressure(track,pitch, value) : process midiout key pressure
- onClock(track) : process midiout clock
-
The LUA function returns midi-messages to play
- These midi-messages are played immediatly.
-
Each midi-messages is define by these parameters :
- track-nr : integer ( must already exists and opened )
-
type message : NoteOn NoteOff Ctrl Program KeyPressure ChannelPressure PitchBend
- value#1 : integer 0..127 ( e.g pitch for noteon, program, ... )
-
value#2 : integer 0..127 ( e.g. velocity for noteon, no meaning fro program , .. )
- parameter #1 : LUA file name, with its extension
- Example of lua script file
-
-- postprocess the midiout of luabass.
-- this script is loaded dynamically. Example : luabass.onMidiOut("postluabass.lua")
-- global variable of this script can be set . Example : luabass.setVarMidiOut("transpose",10)
transpose = 0-- list of pitches to map to another value (for drums, .. )
local midiMap = { [1]=5,[20]=10,[32]=11}function map(i)
return (midiMap[i] or i)
endfunction onNoteon(nrTrack,pitch,velocity)
return nrTrack,"Noteon",map(pitch)+transpose,velocity
end
function onNoteoff(nrTrack,pitch,velocity)
return nrTrack,"Noteoff",map(pitch)+transpose,velocity
end
function getTranspose()
return transpose
end - setVarMidiOut :
set a global variable in LUA script which processes the midiout
- parameter #1 : variable name
- parameter #2 : value
- Misc
- outTranspose : noteoff, and transpose all midi-out
- parameter #1 : value in half-tone
- logmsg : log a message ( visible in the menu "setting/log" and file "expresscmd_log_out.txt" )
- parameter #1 : text