18 Jun '13 - 08:06 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: BASSMIDI MIDI_EVENT_NOTE BASS_MIDI_TICK  (Read 2209 times)
Art60
Posts: 135


« on: 10 May '09 - 20:32 »
Reply with quoteQuote

Hi Ian and all.

It's been a while since I went here,

My project is slowly growing and I'm facing a new problem, please apologize if an answer's already here, I didn't find it.

I'm trying to find which midi channel is the melody one, comparing to the lyrics events, in order to automatically mute it (it's a Karaoke player).

So first, I build an array with the LYRICS or TEXT events.
For each one, I have a mark.pos I translate to midi ticks using the following VB6 statements :
BASS_ChannelSetPosition chan, mark.pos, BASS_POS_BYTE
nTick = BASS_ChannelGetPosition(chan, BASS_POS_MIDI_TICK)

Then I build a fast decode procedure with no soundfont to get every Note-On event from the midi file
BASS_ChannelSetSync nChan, BASS_SYNC_MIDI_EVENT Or BASS_SYNC_MIXTIME, MIDI_EVENT_NOTE, AddressOf NoteEvent, 0

The problem is:
If I get a large buffer to decode, My NoteEvent procedure asking BASS_ChannelGetPosition gets the same value for a lot of consecutive notes.
So I the decided to have a small buffer (a single pair of bytes)
The result is better, every call has a different Tick value, but the value is still erroneous (from 1 to some hundreds of ticks).
I can't achieve in having ticks matching lyrics and notes, though I do know they do in the midi file, for I inspected it with a midi editor.

May BASSMIDI help me in this way or do I have to build a separate midifile decoder to find which is the corresponding melody midi channel ?

Thank you for any help.

Regards,
Arthur.




Logged
Ian @ un4seen
Administrator
Posts: 15352


« Reply #1 on: 11 May '09 - 15:43 »
Reply with quoteQuote

The issue there is that BASS_ChannelGetPosition is returning the position at the start of the chunk of data that is being rendered (containing the note), so rendering smaller chunks should help to separate the notes. I did spot a little tempo event processing bug though; they were being applied 1 tick late, so perhaps that could explain the notes being slightly off target. Here's an update to try...

   www.un4seen.com/stuff/bassmidi.dll

If you still find that you aren't getting accurate tick positions reported even when rendering a single sample at a time, please provide an example file to reproduce that with, and point out a note that is incorrect if the problem doesn't affect them all.
Logged
Art60
Posts: 135


« Reply #2 on: 11 May '09 - 19:52 »
Reply with quoteQuote

Good evening Ian,

Thank you for answering,

Sorry, the DLL you made for me doesn't help much.

I think I have a bug in my MIDI_EVENT_NOTE procedure.

Before I send anything to you, could you please point out where I can find the exact detail for the parameters an event procedure receives : i.e. midi channel, velocity, note value ,etc.
The only thing I saw about MIDI_EVENT_NOTE is on the BASS_MIDI_StreamEvent chm page.
I think I may have messed high and low words/bytes somewhere.

Sub CalcullNote(ByVal handle As Long, ByVal channel As Long, ByVal data As Long, ByVal user As Long)
MidiChannel = data \ 65536 ' High Word
eventparam = data Mod 65536 ' Low Word
NoteValue = eventparam \ 256 ' High Byte
Velocity = eventparam Mod 256 ' Low Byte
If MidiChannel >= 0 And MidiChannel < 16 Then
  If Velocity > 0 Then
    ' Here I got a Note On message for note # NoteValue on Midi channel # MidiChannel
  End If
End If

Thanks a lot for your support.
Logged
Ian @ un4seen
Administrator
Posts: 15352


« Reply #3 on: 12 May '09 - 17:25 »
Reply with quoteQuote

The SYNCPROC "data" parameter will be as the BASS_MIDI_StreamEvent "param" parameter for the same event, with the addition of the channel number in the HIWORD. With the MIDI_EVENT_NOTE event, the note is in the LOBYTE and the velocity is in the HIBYTE, so those need to be swapped around in your code above.
Logged
Art60
Posts: 135


« Reply #4 on: 12 May '09 - 18:48 »
Reply with quoteQuote

Thank you so much Ian for your explanations,

It does confirm my latest tests, I was wrong on various points.

So the final result is following:

(Corresponding test1.kar file in incoming folder)

The decode procedure asks for 2 bytes at a time ( I tried length=1 but BASS_ChannelGetData returns 0 ):

Ticks for Note On for midi chan#3 in the midi file:
5562
5664
5760
6046
6146
6332
6524
6718
6910
7196
7394
7486
7680
7872
8064
10172
10270
10366
10654
10754

Ticks returned by BASS_ChannelGetPosition(channel, BASS_POS_MIDI_TICK):
5561 Err=1
5663 Err=1
5759 Err=1
6045 Err=1
6145 Err=1
6331 Err=1
6523 Err=1
6713 Err=5
6905 Err=5
7195 Err=1
7393 Err=1
7486 Err=0
7679 Err=1
7869 Err=3
8061 Err=3
10171 Err=1
10269 Err=1
10359 Err=7
10653 Err=1
10751 Err=3

So, I got much less errors with my bugs removed and I think this will suffice for my search for melody channel.
But there's still some non glitch errors like the one at 10359 instead of 10366...

Don't hurry for it, I'll wait for v2.5 (with tick in mark structure  Grin )

Thank you so much for your efforts in debugging our apps.

Most regards.
Arthur.
Logged
Ian @ un4seen
Administrator
Posts: 15352


« Reply #5 on: 13 May '09 - 15:57 »
Reply with quoteQuote

That could be a case of the notes falling mid-sample, and their position being rounded down. Please try the update posted here...

   www.un4seen.com/forum/?topic=9767.msg68470#msg68470
Logged
Art60
Posts: 135


« Reply #6 on: 13 May '09 - 17:44 »
Reply with quoteQuote

Good evening Ian,

For the sample file I sent you yesterday, this midifile.dll gave me more 0 error count where I had 1 tick difference previously.

So I tested it with another midifile.
mf2t.exe from MidiOx tells me lyrics are exactly on the same tick than the midi channel #3 notes.
But with BassMidi, I haven't 0 errors any more with this new file, most of time it is 1. I could live with it.
But there are still some cases where the position tells 41027 instead of 41040, for instance.
13 ticks error is a bit more than a rounded tick Wink
I launch my software several times, the same tick erros occur at the same time, I don't think it is a latency bug due to time my software takes to process the buffer, but who really knows ?
I just ran my software once in my VB6 IDE then in exe mode and obtained exactly the same differencies, so I don't think this is due to execution time.

So I'll rely on an external software to list notes tick, waiting for a BassMidi solution.

I tried to upload a file to incoming but it seems to be locked  Huh

Thank you very much again for your support.
Logged
Ian @ un4seen
Administrator
Posts: 15352


« Reply #7 on: 14 May '09 - 14:00 »
Reply with quoteQuote

I tried to upload a file to incoming but it seems to be locked  Huh

Strange, perhaps there was a file with the same name already there. Please try renaming the file and then uploading it again.
Logged
Art60
Posts: 135


« Reply #8 on: 15 May '09 - 17:27 »
Reply with quoteQuote

Sorry Ian, I was not using a regular FTP client for this attempt, thought WXP was good enough, silly thought, isn't it?  Grin

So you'll find Luis.kar in incoming folder.

As told earlier, I rely on mf2t from MidiOx to have an "impartial" vision of ticks and I found these (midichannel are numbered from 1 to 16):
36240 On ch=4 n=67 v=105
36480 On ch=4 n=67 v=94
36720 On ch=4 n=67 v=96
39360 On ch=4 n=67 v=101
39720 On ch=4 n=69 v=97
40080 On ch=4 n=70 v=100
40320 On ch=4 n=74 v=96
41040 On ch=4 n=72 v=96
44160 On ch=4 n=72 v=102
44520 On ch=4 n=72 v=94
44880 On ch=4 n=72 v=90
45120 On ch=4 n=74 v=100
45480 On ch=4 n=74 v=88
45840 On ch=4 n=74 v=90
46080 On ch=4 n=75 v=100
46440 On ch=4 n=75 v=98
46800 On ch=4 n=75 v=62
47040 On ch=4 n=78 v=99
47400 On ch=4 n=79 v=102
47760 On ch=4 n=81 v=97
I wrote similar decoding using BassMidi library (I stripped off if then end if statements to make it clearer:
.../...
  BASS_ChannelSetSync nChan, BASS_SYNC_MIDI_EVENT Or BASS_SYNC_MIXTIME, MIDI_EVENT_NOTE, AddressOf CalculNote, 0
  Do
    nCount = BASS_ChannelGetData(nChan, aBuffer(0), 2) ' aBuffer is an array of integers
    DoEvents
  Loop While (nCount = nLength) And BASS_ChannelIsActive(nChan)
.../...

Sub CalculNote(ByVal handle As Long, ByVal channel As Long, ByVal data As Long, ByVal user As Long)
  midichan = data \ 65536
  eventparam = data Mod 65536
  nValue = eventparam Mod 256
  nVelocity = eventparam \ 256
  nTick = BASS_ChannelGetPosition(channel, BASS_POS_MIDI_TICK)
  debug.print nTick;" On ch=";midichan;"n=";nValue;" v=";nVelocity
End Sub
And I get this timing (midichan lies between 0 and 15):
36241 On ch=3 n=67 v=105
36481 On ch=3 n=67 v=94
36721 On ch=3 n=67 v=96
39361 On ch=3 n=67 v=101
39714 On ch=3 n=69 v=97
40081 On ch=3 n=70 v=100
40321 On ch=3 n=74 v=96
41027 On ch=3 n=72 v=96
44161 On ch=3 n=72 v=102
44521 On ch=3 n=72 v=94
44867 On ch=3 n=72 v=90
45121 On ch=3 n=74 v=100
45481 On ch=3 n=74 v=88
45841 On ch=3 n=74 v=90
46081 On ch=3 n=75 v=100
46441 On ch=3 n=75 v=98
46787 On ch=3 n=75 v=62
47039 On ch=3 n=78 v=99
47389 On ch=3 n=79 v=102
47761 On ch=3 n=81 v=97
As you can see, there is more than 1 tick difference at ticks # 39714/39720, 41027/41040, 44867/44880, 46787/46800, 47389/47400, ...

Thanks again for your support.  Cheesy Cheesy Cheesy

Regards,
Arthur.
« Last Edit: 15 May '09 - 18:16 by Art60 » Logged
Ian @ un4seen
Administrator
Posts: 15352


« Reply #9 on: 18 May '09 - 15:17 »
Reply with quoteQuote

I tried to reproduce the problem (doing basically the same as your code above), but the notes appeared to be at their correct positions Smiley

Perhaps you are using a low sample rate for the MIDI stream? BASSMIDI will process a minimum of 16 samples's worth per update, so a combination of a low sample rate and a high tempo/PPQN could mean that the minimum step is more than 1 tick (ie. a tick is less than 16 samples). Here's an update to try, in which that minimum processing unit has been reduced to just 1 sample...

   www.un4seen.com/stuff/bassmidi.dll
Logged
Art60
Posts: 135


« Reply #10 on: 18 May '09 - 17:27 »
Reply with quoteQuote

Good evening Ian, you are totally true, as usual.

First, I put your new DLL in my developpement folder, and it does work!
There are no more such big tick count differencies !
The "error" is now constant and equals to 1.
In a second time, I had a look at my code: Effectively, as told in another thread, to speed up this decoding to null, with no soundfont, to get every event, I had lowered the sample frequency to 1kHz :
BASS_MIDI_StreamCreateFile(BASSFALSE, StrPtr(sFileName), 0, 0, BASS_STREAM_DECODE Or BASS_SAMPLE_MONO Or BASS_MIDI_NOFX, 1000)
This was the faulty parameter !
When I put it at 44100, tick "errors" get all down to 0 and it's now accurate !
But the whole thing is v-e-r-y slow Sad

So I really do thank you for helping me pointing out the cause of this problem, I never thought of this 1ms stupid sampling rate!

So, to resume, there is no more problem but it does take a lot of time.
I'm currently trying to decode the midifile myself (in standard midifile format) to see if I can get these informations faster.

I'll get back with further information if I succeed.

Grateful thanks, Mr Ian !

Regards,
Arthur.
Logged
Ian @ un4seen
Administrator
Posts: 15352


« Reply #11 on: 19 May '09 - 16:29 »
Reply with quoteQuote

Just to be sure that there is no soundfont loaded (no default or matching soundfont), you could do this:

midi=BASS_MIDI_StreamCreateFile(...); // load MIDI file
BASS_MIDI_StreamSetFonts(midi, NULL, 0); // remove any soundfonts from it

Without a soundfont, BASSMIDI will just be rendering silence, but even then it'll probably still be quite slow when rendering 1 sample at a time, as most of the time will be taken by the overheads rather than the rendering. So another thing you could try is adapting the rendering unit to the length of a tick. You can calculate the number of samples in a tick like this:

   samples = rate*tempo/ppqn/1000000

Where "tempo" is the MIDI tempo event value, eg. as given by BASS_MIDI_StreamGetEvent. Be sure to multiply the "samples" value by the number of bytes per sample in the BASS_ChannelGetData call Smiley

MIDI streams are rendered in floating-point, and then converted to 16-bit if necessary. So you could also save a tiny bit of time by making the stream floating-point too (use the BASS_SAMPLE_FLOAT flag), so that BASSMIDI doesn't have to bother with the conversion.
Logged
Art60
Posts: 135


« Reply #12 on: 19 May '09 - 17:33 »
Reply with quoteQuote

Good evening Ian,

Thanks for keeping on helping me.

1) Yes, soundfonts were removed, I saw it in the other thread.

2) I'm wondering if calculating number of samples in a tick would be accurate when handling a midi file embedding tempo changes, but this could be a good idea.

3) As far as I don't render for real, I'm asking myself if I have to call BASS_ChannelGetData with floating point width in order to match the BASS_MIDI_StreamCreateFile BASS_SAMPLE_FLOAT flag. Anyway, I'll give it a try.

Most regards,
Arthur.
Logged
Ian @ un4seen
Administrator
Posts: 15352


« Reply #13 on: 20 May '09 - 14:58 »
Reply with quoteQuote

2) I'm wondering if calculating number of samples in a tick would be accurate when handling a midi file embedding tempo changes, but this could be a good idea.

You could re-calculate the number samples to render whenever the tempo changes, which you could detect via a BASS_SYNC_MIDI_EVENT (MIDI_EVENT_TEMPO) sync.

3) As far as I don't render for real, I'm asking myself if I have to call BASS_ChannelGetData with floating point width in order to match the BASS_MIDI_StreamCreateFile BASS_SAMPLE_FLOAT flag. Anyway, I'll give it a try.

You will indeed need to double the amount of data requested when switching from 16-bit to floating-point. If the stream is mono floating-point, that would be 4 bytes per sample (multiply the "samples" value by 4).
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines