Liberty BASIC Community Forum
« using liberty basic to read sysex midi data »

Welcome Guest. Please Login or Register.
May 29th, 2017, 08:22am


Rules|Home|Help|Search|Recent Posts|Notification


« Previous Topic | Next Topic »
Pages: 1 2  Notify Send Topic Print
 hotthread  Author  Topic: using liberty basic to read sysex midi data  (Read 272 times)
studioman
New Member
Image


member is offline

Avatar




PM


Posts: 12
xx using liberty basic to read sysex midi data
« Thread started on: May 19th, 2017, 8:29pm »

Hello, I have been trying to find out if anyone knows how to read incoming midi timecode that is being sent from another computer (using Liberty Basic). I have the two computers connected via usb midi adapters, and I know they are sending midi time code.

I found the program below presented by Stefan Pendl. I wonder if any further progress was made on it so it would read system exclusive data being sent by another computer. Will Stefan see this post or is there a way I could send this to him directly? I am relatively new to using bulletin boards.



'---code start
titlebar "Get MIDI Info"

' Count midi in devices
calldll #winmm, "midiInGetNumDevs",_
devCount as ulong
print
print "Number of MIDI input devices = "; devCount

' the next line is only for testing, since I have no midi in device
'If not(devCount) then devCount = 1

if devCount then
struct lpMidiInCaps,_
wMid as word,_
wPid as word,_
vDriverVersion as ushort,_
szPname$ as char[32],_
dwSupport as ulong

cbMidiInCaps = len(lpMidiInCaps.struct)

for uDeviceID = 0 to devCount - 1
' get information about every device
calldll #winmm, "midiInGetDevCapsA",_
uDeviceID as ulong,_
lpMidiInCaps as struct,_
cbMidiInCaps as ulong,_
result as ulong

if not(CheckResult(result, "midiInGetDevCapsA")) then
'manufacturer and product ID available in mmreg.h
print
print "Device ID ......... "; uDeviceID
print "Manufacturer ID ... "; lpMidiInCaps.wMid.struct
print "Product ID ........ "; lpMidiInCaps.wPid.struct
print "Driver Version .... ";
SplitShort$(lpMidiInCaps.vDriverVersion.struct)
print "Product Name ...... "; lpMidiInCaps.szPname$.struct
end if
next

struct lphMidiIn, value as ulong

CALLBACK.FUNCTION = hexdec("30000")

dwFlags = CALLBACK.FUNCTION
uDeviceID = uDeviceID - 1

callback dwCallback, MidiInProc(ulong, ulong, ulong, ulong, ulong),
void

' open last midi in device, using a callback to check the connection
calldll #winmm, "midiInOpen",_
lphMidiIn as struct,_
uDeviceID as ulong,_
dwCallback as ulong,_
dwCallbackInstance as ulong,_
dwFlags as ulong,_
result as ulong

if not(CheckResult(result, "midiInOpen")) then
hMidiIn = lphMidiIn.value.struct

' start receiving commands
calldll #winmm, "midiInStart",_
hMidiIn as ulong,_
result as ulong

if not(CheckResult(result, "midiInStart")) then
'wait for 3 seconds
timer 3000, [continue]
wait
[continue]
timer 0

' stop receiving commands
calldll #winmm, "midiInStop",_
hMidiIn as ulong,_
result as ulong

dummy = CheckResult(result, "midiInStop")
end if
' reset midi connection
' clear all buffers to ensure closing succeeds!
calldll #winmm, "midiInReset",_
hMidiIn as ulong,_
result as ulong

dummy = CheckResult(result, "midiInReset")
' close midi in connection
calldll #winmm, "midiInClose",_
hMidiIn as ulong,_
result as ulong

dummy = CheckResult(result, "midiInClose")
end if
end if

' exit function for running as tkn
print
input "Hit ENTER to EXIT ..."; dummy
end

' functions and subs
function MidiInProc(hMidiIn, wMsg, dwInstance, dwParam1, dwParam2)
' callback function to display received commands
print hMidiIn, wMsg, dwInstance, dwParam1, dwParam2
end function

function SplitShort$(number)
' extract major and minor version number
hexstring$ = right$("0000"; dechex$(number), 4)
major = hexdec(left$(hexstring$, 2))
minor = hexdec(right$(hexstring$, 2))
SplitShort$ = major; "."; minor
end function

function CheckResult(CheckResult, FunctionName$)
' check midi in functions for errors
' zero indicates no error
if CheckResult then
cchText = 256
Message$ = space$(cchText)

calldll #winmm, "midiInGetErrorTextA", _
CheckResult as ulong,_
Message$ as ptr,_
cchText as ulong,_
result as ulong

dummy = CheckResult(result, "midiInGetErrorTextA")
print
print "Error #"; CheckResult; " in "; FunctionName$; ":"
print trim$(Message$)
end if
end function
'---code end

---
Stefan Pendl


This program will read a lot of midi data, but I cannot find a way to receive Midi Time Code. Thank you in advance,

studioman567
« Last Edit: May 19th, 2017, 8:31pm by studioman » User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #1 on: May 20th, 2017, 09:13am »

Well the code you cut and paste won't run for me and in any event I do not have a midi in device to experiment.

My guess is you are receiving the messages. Here is what they look like. If this is all gobbledegook you need to spend some time reading the midi message spec.

The MTC is sent as a sys (edit to correct, the frame mtc message is a standard message not a sysex message. It is named dec 248 and sent in eight segments) message, it splits the MTC into eight segments and sends eight messages.

Each message is two bytes long, the first byte identifies the message and is 1110001 in binary

The second byte identifies which of the eight segments it is and provides the data for that segment nnnndddd, nnnn is the message segment 0-7 and dddd is the actual MTC data.

Here are the segment descriptions.

MIDI time code segment
0
0000 ffff
Frame number lsbits
1
0001 000f
Frame number msbit
2
0010 ssss
Second lsbits
3
0011 00ss
Second msbits
4
0100 mmmm
Minute lsbits
5
0101 00mm
Minute msbits
6
0110 hhhh
Hour lsbits
7
0111 0rrh
Rate and hour msbit

So are you getting messages named 11110001 and can you see yourself parsing them out?

If you can at least post a list of sample messages we can show you how to parse them out.

« Last Edit: May 22nd, 2017, 02:24am by Rod » User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #2 on: May 20th, 2017, 09:20am »

I also read that there is another time code message that is sent to sync equipment. Is it this you are interested in or the real time MTC data?

"Full time code
When there is a jump in the time code, a single full-time code is sent to synchronize attached equipment. This takes the form of a special global system exclusive message:
F0 7F 7F 01 01 hh mm ss ff F7"
User IP Logged

studioman
New Member
Image


member is offline

Avatar




PM


Posts: 12
xx Re: using liberty basic to read sysex midi data
« Reply #3 on: May 20th, 2017, 12:34pm »

Thanks for the reply Rod.

I should have described my problem more clearly. I understand how system exclusive messages are sent/received and that they start with F0 (240) and end with F7 (247). Using the program that I copied and pasted, I can read incoming data. My problem is that at no time is that data an F0 or an F7. I will get a 251(song start/continue), a 252(stop), 248(midi time CLOCK), but at no time do I see 240 or 247.

Mr. Chung has done some work in Liberty basic that will record midi but I cannot get that program to show me any midi time code either. I have emailed him a few times and we have tried a few things, but I cannot get any F0 or F7 from that program either.

I know my computer is receiving system exclusive messages because I downloaded a program called Midiox, and that program shows that my computer is receiving sysex.

I can't can't seem to find out if there is a special API I need to call or if the same command that receives the 251,252, and 248 is the same command that should get the 240, the 247, and the hours, minutes, seconds, and frames information in between.

If the line in the program that reads the midi information is:
function MidiInProc(hMidiIn, wMsg, dwInstance, dwParam1, dwParam2),
where the dwParam1 is the incoming midi data, then I don't understand why it won't show a 240 or 247. I am stumped.

Should the dwParam1 be able to read all incoming info. no matter what it is, or am I missing something?
User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #4 on: May 20th, 2017, 1:01pm »

Ok, it seems we are dealing with the sysex 240 full time code message and not the frame by frame 248 MTC.

When you say you are receiving sysex messages as proved by midiox have you seen the 240 full time code message being sent?

I ask because the full time code is initiated by the midi device, it won't be transmitted continuously, only when the midi device wants to spit it out. So are we seeing it with midiox?

Given the full time code message is longer than the standard message the code Stefan provides wont catch it
all. I would need to read up on that.

But first are you getting the 240 full time code message via midiox?
User IP Logged

studioman
New Member
Image


member is offline

Avatar




PM


Posts: 12
xx Re: using liberty basic to read sysex midi data
« Reply #5 on: May 20th, 2017, 7:42pm »

Thanks again. With your help, I think there might be 'light at the end of the tunnel'.

Yes, the Midiox program is receiving a Full frame message. It consists of F0 7F 01 01 02 00 F7, which represents 0 hours, 1 minute, 2 seconds, and 0 frames.

I realize that the computer sending the full frame message is the one the decides to do so. The program that I use for recording/midi sends out a Full frame time message upon; top of song start, stop, and if I position the cursor at a different time in the song. I would just be happy if I could keep track of that information.

Is there another way I can get shorter time code info? I do not want to use 1/4 frame beat messages that are dependent on tempo, if I don't have to.

Are my choices either Midi Time Code or Midi Clock? And if so, do you know what I would need to be able to read the Full frame messages?

Thanks for taking the time to help me. I hesitated to even ask because I did not think 'Liberty Basic' and the people behind it would take the time to provide this level of support. Please forgive me for the assumption.
User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #6 on: May 21st, 2017, 05:32am »

Ok, reading into midi more deeply. here is the link to all the api info

https://msdn.microsoft.com/en-us/library/dd798495(v=vs.85).aspx

Here is an extract of what it says about sysex messages, they are not routinely sent to the client, they are sent to a buffer but only if it is pre prepared.

Quote:
midiinstart
This function resets the time stamp to zero; time stamp values for subsequently received messages are relative to the time that this function was called.
All messages except system-exclusive messages are sent directly to the client when they are received. System-exclusive messages are placed in the buffers supplied by the midiInAddBuffer function. If there are no buffers in the queue, the system-exclusive data is thrown away without notification to the client and input continues. Buffers are returned to the client when they are full, when a complete system-exclusive message has been received, or when the midiInReset function is used. The dwBytesRecorded member of the MIDIHDR structure will contain the actual length of data received.


The midiInAddBuffer function sends an input buffer to a specified opened MIDI input device. This function is used for system-exclusive messages.
Syntax
C++


MMRESULT midiInAddBuffer(
 HMIDIIN   hMidiIn,
 LPMIDIHDR lpMidiInHdr,
 UINT      cbMidiInHdr
);

Parameters
hMidiIn
Handle to the MIDI input device.
lpMidiInHdr
Pointer to a MIDIHDR structure that identifies the buffer.
cbMidiInHdr
Size, in bytes, of the MIDIHDR structure.
Return value
Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following.



The midiInPrepareHeader function prepares a buffer for MIDI input.
Syntax
C++


MMRESULT midiInPrepareHeader(
 HMIDIIN   hMidiIn,
 LPMIDIHDR lpMidiInHdr,
 UINT      cbMidiInHdr
);

Parameters
hMidiIn
Handle to the MIDI input device. To get the device handle, call midiInOpen.
lpMidiInHdr
Pointer to a MIDIHDR structure that identifies the buffer to be prepared.
Before calling the function, set the lpData, dwBufferLength, and dwFlags members of the MIDIHDR structure. The dwFlags member must be set to zero.
cbMidiInHdr
Size, in bytes, of the MIDIHDR structure.
Return value
Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following.


I am afraid I am not well versed enough to code the api calls. Perhaps some members are, we shall see if we get a response.
User IP Logged

studioman
New Member
Image


member is offline

Avatar




PM


Posts: 12
xx Re: using liberty basic to read sysex midi data
« Reply #7 on: May 21st, 2017, 10:40pm »

I hate to reply one more time, but after further internet research, I think I would be happy receiving the quarter frame messages to decode the hours, minutes, seconds and frames. Does anyone know how I can do that?

The program I posted earlier receives a '248' while the time code is running, but I do not know how (or where) to extrapolate the time code from there.

Any thoughts?
User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #8 on: May 22nd, 2017, 01:05am »

There will be eight 248 messages numbered 0 to 7 each will have part of the time code. It's as I describe in an earlier post. I will try to code an example of parsing out the full time code from eight messages. Perhaps someone will beat me to it.
User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #9 on: May 22nd, 2017, 04:03am »

It would be good to see some real 248 messages to prove this is getting somewhere near. It's messy but you might see where I am going with it.

Code:
'MIDI time code segment
'0
'0000?ffff 0-29
'Frame number lsbits
'1
'0001?000f
'Frame number msbit
'2
'0010?ssss 0-59
'Second lsbits
'3
'0011?00ss
'Second msbits
'4
'0100?mmmm 0-59
'Minute lsbits
'5
'0101?00mm
'Minute msbits
'6
'0110?hhhh 0-23
'Hour lsbits
'7
'0111?0rrh
'rr
'rr = 00: 24 frames/s
'rr = 01: 25 frames/s
'rr = 10: 29.97 frames/s (SMPTE drop-frame timecode)
'rr = 11: 30 frames/s
'Rate and hour msbit

'create somewhere to store the messages as they arrive
'there are eight two byte messages, byte 1 will always
'be 248 so no need to store that just store the data byte
dim mtc$(7)


'data byte is in two parts ssss dddd
'first four bits define the segment number 0-7
'the second four bits is the data itself

'lets say frame number is 1
'so first segment no is bin 0000 dec 0 frame data lsbits bin 0001 dec 1 'if frame no = 1
'multiply the first four bits by 32 to store as the most significant nibble
'0*32=0 add the data nibble unaltered = + 1 = chr$(1)
mtc$(0)=chr$(1)

'second segment is bin 0001 dec 1 frame data msbits bin 0000 dec 0 'if frames=1
'1*32=32+0=32 = chr$(32)
mtc$(1)=chr$(32)

'lets say seconds value is 22
'third segment is bin 0010 dec 2 seconds data lsbits bin 0110 dec 6 ' if seconds=22
'2*32=64 +6=70
mtc$(2)=chr$(70)

'fourth segment is bin 0011 dec 3 seconds data msbits bin 0001 dec 1 'if seconds=22
'3*32=96 +1=97
mtc$(3)=chr$(97)

'lets say minutes value is 9
'fifth segment is bin 0100 dec 4 minutes data lsbits bin 1001 dec 9 ' if seconds=9
'4*32=128 +9=137
mtc$(4)=chr$(137)

'sixth segment is bin 0101 dec 5 minutes data msbits bin 0000 dec 0 'if seconds=9
'5*32=160 +0=160
mtc$(5)=chr$(160)


'lets say hours value is 0
'seventh segment is bin 0110 dec 6 hours data lsbits bin 0000 dec 0 ' if hours=0
'6*32=192 +0=192
mtc$(6)=chr$(192)

'eighth segment is bin 0111 dec 7 minutes data msbits bin 0000 dec 0 'if hours=0
'eigth segment also contains rate value, middle two bits of the data bits 00=24fps
'7*32=224 +0=224
mtc$(7)=chr$(224)


'now lets parse that message and retrieve the data
dim m(7)
for n= 0 to 7
    if asc(mtc$(n))>0 then
        segment=int(asc(mtc$(n))/32)
    else
        segment=0
    end if
    m(n)=asc(mtc$(n))-segment*32
    print segment,m(n)
next

frame=m(1)*16+m(0)
seconds=m(3)*16+m(2)
minutes=m(5)*16+m(4)
hours=m(7)*16+m(6)
print frame
print seconds
print minutes
print hours
'the hours value will be corrupted if the fps rate is not 00 24fps
'i need to do more work to parse out the fps
wait

 
User IP Logged

studioman
New Member
Image


member is offline

Avatar




PM


Posts: 12
xx Re: using liberty basic to read sysex midi data
« Reply #10 on: May 22nd, 2017, 1:28pm »

Thanks even more! I appreciate the help.

My problems seems to be (and I'm sure it arises out of my lack of understanding Liberty Basic), is that the only number (besides 251 and 252) that I can get from the program is 248. I understand that is the number to indicate time code, but how do I get the rest of the info so I can get the hours, minutes, seconds and frames?

Which line in the program reads the other pieces of the time code?

Is it the 'call SplitLong dwParam1, dummy, SecondDataByte, FirstDataByte,MidiStatus' line?

When is 'ask' Liberty Basic to print the values of FirstDataByte and SecondDataByte, they display as a value of 0. None of the other variables seem to indicate anything other than the message number, number of milliseconds from start, and the message number.

Where should I be expecting the information for the time code messages to be showing up? If it is supposed to be the 'MidiStatus'? All that gives me is the 248 indicating that time code is running. Where can I find the lsbits and msbits for each of the 4 elements that make up the real time midi time code messages?

I cannot seem to figure out where that information comes in using the program I posted previously.

That part is as clear as mud to me. I understand the midi part.
User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #11 on: May 22nd, 2017, 2:24pm »

The callback function should be printing the midi message data.

Code:
' functions and subs
function MidiInProc(hMidiIn, wMsg, dwInstance, dwParam1, dwParam2)
' callback function to display received commands
print hMidiIn, wMsg, dwInstance, dwParam1, dwParam2
end function
 


so dwParam1, dwParam2 should be your message? Without a real midi input it is hard to help, experiment you can't break anything.
User IP Logged

studioman
New Member
Image


member is offline

Avatar




PM


Posts: 12
xx Re: using liberty basic to read sysex midi data
« Reply #12 on: May 22nd, 2017, 9:06pm »

Yea, it's me again. I thought your last response would have solved it, but alas, my tears continue

I have tried asking Liberty Basic to print all of the variables that are being called by all of the functions. None of them gave me what I thought I should be seeing for time code. That's the first thing I tried. I am sure this can be solved (or at least I hope).

When the following function is called:
function MidiInProc(hMidiIn, wMsg, dwInstance, dwParam1, dwParam2) - and I print hMidiIn, wMsg, dwInstance, dwParam1, dwParam2, these are the results.

168790360 963 0 248 20903

I assume the 168790360 is the handle number (it changes each time the program is run).

The 963 appears to be the message type.

I don't know what the zero is. The 248 is the midi message (time code running), and the last number (in this case 20903) is the milliseconds from the start of the song.

The 168790360, 963, 0 and 248 remain constant while the time code is running. The only number that changes is the last one (dwParam2), which represents the milliseconds.

I am still lost. cry

I know you have put enough time into this so I hate to ask again. Liberty Basic has helped me write a program that controls my furnace, switches between 8 cameras, knows when someone comes thru the front and back doors (and logs it), logs and graphs temperature and utility usage, keeps track of my customers' sessions, texts them to remind them of their sessions, log phone calls and act as an answering / message machine.

I love Liberty Basic and 'never say die' is my motto. It also helps that I'm single. Thanks again for your help.
User IP Logged

Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5292
xx Re: using liberty basic to read sysex midi data
« Reply #13 on: May 23rd, 2017, 12:46pm »

So does milliseconds not tell you what you want to know?
User IP Logged

studioman
New Member
Image


member is offline

Avatar




PM


Posts: 12
xx Re: using liberty basic to read sysex midi data
« Reply #14 on: May 23rd, 2017, 12:59pm »

No, milliseconds only reports how many milliseconds have passed since midi information was once received. So, even if I start playing the song over from the beginning, milliseconds just reports how much time has elapsed since the midi device started acquiring data.

So if I first stated playing the song 10 minutes ago, and then restarted the song at the beginning, milliseconds would not show me how far along in the song I was, but that 10 minutes had elapsed since I first played the song.

Milliseconds could be helpful to me if I could get a full time code message to indicate what time (hours, minutes, seconds and frames) that the song restarted at. Then I could use milliseconds to indicate how the time is progressing in the song.
User IP Logged

Pages: 1 2  Notify Send Topic Print
« Previous Topic | Next Topic »

Rules|Home|Help|Search|Recent Posts|Notification

Donate $6.99 for 50,000 Ad-Free Pageviews!

| |

This forum powered for FREE by Conforums ©
Sign up for your own Free Message Board today!
Terms of Service | Privacy Policy | Conforums Support | Parental Controls