Very nice to hear that it appeals to you, aristid
I'm a musician myself (maybe you guessed that already) and seeing as there were no midi (at least not any midiIN) oplugins around for DBP, I thought I'd give it a try.
Unfortunately, I don't know if a DBP application runs fast enough to give you the desired latency for the midi message sending.
Perhaps you could have that sorted out by letting the plugin do more work, however that would loose you some of the control....
Maybe if I added an option to let the dll callback function handle midiTHRU itself, that would save quite some valuable time. I might look into that when I get the time.
Should you be interrested to talk about any future development of the plugin, you could always send me an email; I would be glad to see such interrest in my work
I've taken the time to write an example that does some really simple recording and playback using arrays, the timer() function and my midi plugin.
Apart from the slightly slow latency between pressing the note and hearing it (which could be reduced by rearranging the command order, however, I thought it better to prioritate the saving of the timestamp), it works pretty neat.
rem *************************
rem * MIDI PLUGIN EXAMPLE *
rem * recording & playback *
rem *************************
rem * Written by *
rem * J. Sjöqvist, aka *
rem * Rudolpho *
rem *************************
`Global variables
global hMI as dword `Handle to opened midiIN port
global hMO as dword ` -||- midiOUT port
global pointer as integer `Points to the current midiMessage (its ID, that is)
global time as integer `Used with timer() to determine *really* simple timestamps
dim midiMsg (65535) `The program will be able to store 65535 separate midiMessages
dim midiStamp (65535) `Timestamps between each midi message.
set display mode 1024, 768, 32 : set window on : set window title "MIDI Recording & Playback" : maximize window : disable escapekey `The escapekey will be used later on
`First out, we need to tell the midi plugin that it will be used; otherwise it wouldn't take up
`unneccessary memory by creating arrays etc. that wouldn't be used anyway.
init midi plugin
ink 0x006699, 0x000001 `(Just a nice font colour)
`Now for the midi ports. We start by allowing the user to choose his midiIN device:
text screen width() - text width(".:Choose an midiIN device:."), 0, ".:Choose an midiIN device:."
for dev = 0 to midiIn devices()
text 22, 22 * dev, get midiIn device name(dev) `Display the name of the current device
next dev
dev = 0 `Since this is used for the selection below, it should start at the first item (id 0)
`Selection loop
repeat
if downkey() = 1
if dev >= midiIn devices()
dev = 0 `Revert
else
inc dev `Increase
endif
sleep 90 `Ensure that the cursor doesn't scroll too fast
endif
if upkey() = 1
if dev =< 0
dev = midiIn devices() `Revert
else
dec dev `Decrease
endif
sleep 90
endif
`Clear the cursor coulumn
ink 0x010101, 0x000001 : box 0, 0, 22, screen height() : ink 0x006699, 0x000001
`We now draw our simple cursor next to the selected device
cursor(1, (22 * dev) - 1)
until returnkey() = 1
hMI = open midiIn port(dev) `Open the selected midiIN port and retrieve it's handle (hMI)
cls `Clear the screen for the next list
repeat
until returnkey() = 0 `Ensure that the user doesn't accidentally choose the first MO device
`This time, we let the user choose his midiOUT device:
`(Keep in mind that you could easily change this so that the MIDI MAPPER device isn't
` displayed or selectable, since most of the time you wouldn't want to use that anyways).
text screen width() - text width(".:Choose an midiOUT device:."), 0, ".:Choose an midiOUT device:."
for dev = 0 to midiOut devices()
text 22, 22 * dev, get midiOut device name(dev) `Display the name of the current device
next dev
dev = 0
`Selection loop
repeat
if downkey() = 1
if dev >= midiOut devices()
dev = 0
else
inc dev
endif
sleep 90
endif
if upkey() = 1
if dev =< 0
dev = midiOut devices()
else
dec dev
endif
sleep 90
endif
`Clear the cursor coulumn
ink 0x010101, 0x000001 : box 0, 0, 22, screen height() : ink 0x006699, 0x000001
`Draw our simple cursor next to the selected device
cursor(1, (22 * dev) - 1)
until returnkey() = 1
hMO = open midiOut port(dev) `Open the selected midiOut port and retrieve it's handle (hMO)
set cursor 10, screen height() - text height("X")
input "Select a midi patch for playback (1 to 128): ", patch
for c = 1 to 16
set midi instrument hMO, c, patch `Set the instrument for each channel
next c
cls
`Allright, the ports are open and we can begin our recording and midiTHRU.
set text size 32 : ink 0xff0000, 0x000001
center text screen width() / 2, screen height() / 2, "PRESS SPACEKEY TO BEGIN RECORDING"
repeat
until spacekey() = 1 `Wait for the user to press the spacekey before continuing
repeat
until spacekey() = 0
cls
center text screen width() / 2, screen height() / 2, "RECORDING" + chr$(13) + chr$(10) + "PRESS SPACEKEY TO END SESSION"
time = timer() `Begin timing
repeat
if midiIn buffer items() > 0 `Loop through the items in the midiIN buffer
for msg = 0 to midiIn buffer items()
midiStamp(pointer) = timer() - time `Sava a (poor) timestamp for the midi event
time = timer()
midiMsg(pointer) = midiIn buffer(msg) `Store the actual message (the midiIN message is temporarily stored in the midiIN buffer)
send midi shortMsg hMO, midiMsg(pointer) `MidiTHRU the message to the output port
inc pointer
next msg
clear midiIn buffer `Purge the midiIN buffer to make room for further messages
`(the buffer stores up to 256 messages).
endif
until spacekey() = 1 `End the recording session when the spacekey is pressed....
repeat
until spacekey() = 0 `....and released.
SESSION_END:
cls
center text screen width() / 2, screen height() / 4, "SESSION ENDED."
center text screen width() / 2, (screen height() / 4) + 20, "PRESS RETURNKEY TO PLAYBACK YOUR RECORDING,"
center text screen width() / 2, (screen height() / 4) + 40, "OR ESCAPEKEY TO END."
repeat
if escapekey() = 1 then goto SHUTDOWN
until returnkey() = 1
repeat
until returnkey() = 0
PLAYBACK:
startTime = timer()
for a = 0 to pointer
time = timer()
while (timer() - time) < midiStamp(a) `Wait for the time given in midiStamp(msg)
endwhile
send midi shortMsg hMO, midiMsg(a) `When the time is right, send the corresponding midi message
set text size 12
`Write info about the midi message to the screen
ink 0x010101, 0x000001 : box 0, screen height() - text height("X"), screen width(), screen height() : ink 0x006699, 0x000001
text 0, screen height() - text height("X"), "Current midi message: 0x" + str$(midiMsg(a)) + " at " + getSec((timer() - startTime)) + " sec"
if returnkey() = 1 or escapekey() = 1 then exit `Break playback with return/escape
next a
repeat
until escapekey() = 0 and returnkey() = 0
goto SESSION_END
SHUTDOWN:
close midiOut port hMO `Close the midiOut port
close midiIn port hMI `Close the midiOn port
`(You should always close your opened ports after use, or they might
` not function properly afterwards. Should that happen, everything
` will be working if you just restart your computer, however).
end
`Like the name suggests, this function will draw a simple cursor at the given coordinates
function cursor(x as integer, y as integer)
for a = 0 to 20
line x, y + a, x + 20, y + 10 `Draw a triangle (the cursor) facing rightwartds
next
endfunction
`This function will return the supplied number (milliseconds) as seconds with two decimals
`as a string.
function getSec(t as integer)
local sec as float
sec = (t / 1000.0)
repeat
inc p
until mid$(str$(sec), p) = "." or p = len(str$(sec))
if p < len(str$(sec))
tmpStr$ = left$(str$(sec), p + 2) `Note that we do not round the number, so it might
`display incorrectly to up to a twohundreth of a
`second. Since this is just an example, it doesn't
`matter though.
else
tmpStr$ = str$(sec) + ".00"
endif
endfunction tmpStr$
(
Maybe slightly overcommented, but just so that there won't be any problems understanding it).
Thank you again aristides, for getting me to write a real example finally (the plugin's been out here for over two months :p )
"I kören hörs de brummande busarna Björnligan och Gondolen"