Author Topic: BASSMIDI beta  (Read 45969 times)

heftig

  • Posts: 85
Re: BASSMIDI beta
« Reply #50 on: 26 Nov '06 - 17:53 »
I'm having a problem with the synth demo binary. It does not produce any sound output and crashes upon exit. I've tried multiple soundfonts.

---------------------------
synth.exe - Fehler in Anwendung
---------------------------
Die Anweisung in "0x7c921e58" verweist auf Speicher in "0x00000000". Der Vorgang

"read" konnte nicht auf dem Speicher durchgeführt werden.


Klicken Sie auf "OK", um das Programm zu beenden.
---------------------------
OK   
---------------------------

Ian @ un4seen

  • Administrator
  • Posts: 20401
Re: BASSMIDI beta
« Reply #51 on: 26 Nov '06 - 19:25 »
Oops with knobs on! An updated DLL is now in the BASSMIDI download.

BASS_MIDI_StreamCreate was ignoring the "channels" parameter and creating 0 channel streams. That explains the no sound, and probably the crashing too, but it didn't crash here, so please let me know if you still get the crashing there.

heftig

  • Posts: 85
Re: BASSMIDI beta
« Reply #52 on: 26 Nov '06 - 21:03 »
Works now. :D Thanks, Ian.  :)

Orre

  • Guest
Re: BASSMIDI beta
« Reply #53 on: 18 Dec '06 - 16:07 »
I'm sort of a newbie, and I want to play midi files in a little sidescrolling game of mine. The only problem is that i can't seem to get a midi playing without first adding a sounfont, however I don't wanna include a 24 mb large file when I sen my game to friends. ::) (I can play midis in my media players, so it's not that I don't have a soundfont at all.)

So uhm, do you have any idea how i can solve this? I tried playing midi's with mmSystem, but it causes the system to freeze for about a second when it opens the specified file = not good.

Ian @ un4seen

  • Administrator
  • Posts: 20401
Re: BASSMIDI beta
« Reply #54 on: 18 Dec '06 - 18:49 »
If you don't want to use soundfonts, you could use MCI. Something like this...

Code: [Select]
mciSendString("open mymidifile.mid alias mymidi",0,0,0);
mciSendString("play mymidi",0,0,0);
...
mciSendString("close mymidi",0,0,0);

See the mciSendString docs for more info.

Orre

  • Guest
Re: BASSMIDI beta
« Reply #55 on: 18 Dec '06 - 19:57 »
Will do! Thanks.

dukus

  • Posts: 6
Re: BASSMIDI beta
« Reply #56 on: 18 Dec '06 - 20:02 »
I use in c# flowing code :

marksCount = BassMidi.BASS_MIDI_StreamGetMarksCount(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);
marks = new BASS_MIDI_MARK[marksCount];
marks=BassMidi.BASS_MIDI_StreamGetMarks(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);

Counter is returned but , no lyrics marker

radio42

  • Posts: 4574
Re: BASSMIDI beta
« Reply #57 on: 19 Dec '06 - 21:00 »
Can you pls provide your midi file containing the lyrics...and did you test it with the precompiled miditest example in the original midi add-on download?

dukus

  • Posts: 6
Re: BASSMIDI beta
« Reply #58 on: 20 Dec '06 - 18:53 »
The midi file and the program, if i don't use BASS_MIDI_StreamGetMarks work correct .
Thanks.

radio42

  • Posts: 4574
Re: BASSMIDI beta
« Reply #59 on: 20 Dec '06 - 21:56 »
Here is an update to try:

.Net 1.1. build : http://www.un4seen.com/filez/4/Bass23.Net11_update.zip
.Net 2.0 build : http://www.un4seen.com/filez/4/Bass23.Net20_update.zip

Make sure to copy the included files to your install directory!

dukus

  • Posts: 6
Re: BASSMIDI beta
« Reply #60 on: 21 Dec '06 - 14:08 »
Thx, now working, but steal have some problem time to time the program crash. (i thing is some threading problem, not sure ). Any suggestion  how use gui controls and bass engine.

radio42

  • Posts: 4574
Re: BASSMIDI beta
« Reply #61 on: 21 Dec '06 - 14:29 »
Do you mean with BASSmidi or in general.

If this is your general issue - than please take a look to the "MemoryManagement.html" document provided with the setup. It contains a complete chapter about it.

Whenever you have multiple threads running - never-ever impact something in a different GUI-Thread.
So, any window, dialog etc. always runs it it own GUI-Thread. When you for example create your own thread (e.g plain .Net via "ThreadPool.QueueUserWorkItem") and modify a GUI control from within this new thread - you might run into the problem of crashing your application. The reason is, that each window typically uses it's own UI thread and in .Net you have to make sure, that each method which changes the UI (e.g. sets a window text, progress bar whatsoever) needs to be called from within it's own UI thread.

The trick with BASS is, that you do not clearly see when a new thread is created by BASS. But you can in most cases be sure, that each BASS-callback might execute in it's own thread - which then requires you to invoke any GUI related things. Normally a callback delegate is needed, when you have to deal with multiple threads. An example are the normal BASS callbacks. Since BASS creates it's own threads in the background the BASS callback (e.g. a DSPPROC) is typically running in it's own thread and not in the main GUI thread. So the .Net callback method will do as well. If you now would directly modify a GUI control (e.g. a label or a progressBar) from within that callback method - you can run into some crashes, because all windows controls can only be modified from the main GUI thread (which also created the control). Hence your own DSPPROC method might run within a different thread.

So here a callback delegate will solve that problem. Simply use the main form handle (like "this") and invoke your defined method to make sure the method invoked will run in the GUI thread of that given control.

So the best way is to "Invoke" a method on your window, dialog etc. class. Take a look to the "Control.Invoke" or "Control.BeginInvoke" method help in your VisualStudio environment for more info. The invoke makes sure, that a method or function executes in the related thread. When making a call like "Invoke" or "BeginInvoke" you make an asyncronious call ...meaning you ensure, that the method specified in your Invoke call in called in the UI thread of the caller.

Here comes an example using .Invoke in VB.Net...Let's assume you have two from windows frmMain and frmPlaylist. In frmPlaylist you place the following code:
Code: [Select]
// VB
Public Delegate Sub PlaylistAction(ByVal action as integer, ByVal filename as string, ByVal listIndex as string)

Private _pa as PlaylistActionPublic

Sub SetCallback(ByVal pa as PlaylistAction)
    _pa  = pa
End Sub   
    Private Sub ListView1_DoubleClick(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles ListView1.DoubleClick
            Dim actPlay as integer = 0
            If not _pa is nothing Then
                _pa.BeginInvoke(actPlay, Listview1.selectedItems.item(0), Listview1.SelectedIndex)
            End If
    End Sub
The above "_pa.BeginInvoke" call will make sure, that the callback delegate invoked (in this case the PlaylistActionHandler) will be running in the main forms (frmMain) UI thread. So the main form might contain the following code:
Code: [Select]
Public Sub PlaylistActionHandler(ByVal action as integer, ByVal filename as string, ByVal listIndex as string)
    If action = 0 Then ' Play File
         MsgBox(filename)
    End If
End Sub

Public Sub OpenPlaylistForm()
    Dim fpl as new formPlaylist
    fpl.SetCallback(AddressOf PlaylistActionHandler)
    fpl.Show
    '... Other code here. etc.
End Sub

So you assign the callback delegate of frmMain to the second form window (frmPlaylist) by calling a "SetCallback" method which is actually a method of frmPlaylist (you might also handover the callback delegate in the constructor if you want).

If you are using the .Net 2.0 Framework an even more elegant way can be used, since with 2.0 .Net introduced anonymous delegates had been introduced. With anonymous delegates, a slightly cleaner solution can be used. You can do this (e.g. in C#):
Code: [Select]
private void CalledOnNonUIThread(string data)
{
    // .Net 2.0 or above only!
    BeginInvoke( (MethodInvoker)delegate()
    {
        // This runs on the UI thread!
        this.Text = data;
    } );
}

The same logic aplies to BASS callback delegates (e.g. DSPPROC, STREAMPROC etc.). When implementing your own procedures here, make sure to never directly modify a UI control from within those implementations, since BASS calls those procedures and BASS might have created a new thread in the background, so your BASS procedures might run in this new thread as well. Instead use the above 'Invoke' technique and first create another callback delegate within your related main UI thread and then invoke this callback to modify any UI controls.

dukus

  • Posts: 6
Re: BASSMIDI beta
« Reply #62 on: 21 Dec '06 - 17:35 »
A strange thing. If use function BASS_MIDI_StreamGetMarks the program crash and the ChannelSetSync not return the lyric event correctly(all used variable is global defined  ) , but if close the stream and reopen for playing work perfect.

radio42

  • Posts: 4574
Re: BASSMIDI beta
« Reply #63 on: 21 Dec '06 - 17:54 »
I guess you need to show some code...and especially your multi-threading things...
What error-code do you get from BASS?

dukus

  • Posts: 6
Re: BASSMIDI beta
« Reply #64 on: 21 Dec '06 - 19:41 »
Code: [Select]
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Un4seen.Bass;
using Un4seen.Bass.AddOn.Cd;
using Un4seen.Bass.AddOn.Midi;


namespace Sample
{
    class midi_info_helper
    {
        static public string lyric_text = "";
        static public BASS_MIDI_MARK[] lyric_mark = null;
        static public int lyric_mark_count = 0;
        static public bool isLoaded = false;

        static string _file_name = "";

        public midi_info_helper()
        {
            isLoaded = false;
        }

        public midi_info_helper(string file)
        {
            isLoaded = false;
            FileName = file;
        }

        static public string FileName
        {
            set
            {
                _file_name = value;
                GetMarks(_file_name);
            }
            get { return _file_name; }
        }
        static public BASS_MIDI_MARK[] GetLyricMarks(string fn)
        {
            BASS_MIDI_MARK[] marks = new BASS_MIDI_MARK[1];
            int marksCount = 0;
            int _Stream = 0;
            _Stream = BassMidi.BASS_MIDI_StreamCreateFile(fn, 0, 0, BASSStream.BASS_DEFAULT | BASSStream.BASS_STREAM_AUTOFREE | BASSStream.BASS_MIDI_DECAYEND, 44100);
            long leng = Bass.BASS_ChannelGetLength(_Stream);
            float time = Bass.BASS_ChannelBytes2Seconds(_Stream, leng);
            if (_Stream != 0)
            {
                marksCount = BassMidi.BASS_MIDI_StreamGetMarksCount(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);
                if (marksCount >= 0)
                {
                    marks = new BASS_MIDI_MARK[marksCount];
                    marks = BassMidi.BASS_MIDI_StreamGetMarks(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);
                }
            }
            return marks;
        }
        static public void GetMarks(string fn)
        {
            BASS_MIDI_MARK[] marks = null;
            int marksCount = 0;
            int _Stream = 0;

[glow=red,2,300]// !!!!!!!!!!!!!!!!AccessViolationException Unhadled !!!!!!!!!!!!!!!!!!!!!!
            _Stream = BassMidi.BASS_MIDI_StreamCreateFile(fn, 0, 0, BASSStream.BASS_DEFAULT | BASSStream.BASS_STREAM_AUTOFREE | BASSStream.BASS_MIDI_DECAYEND, 44100);
[/glow]            long leng = Bass.BASS_ChannelGetLength(_Stream);
            float time = Bass.BASS_ChannelBytes2Seconds(_Stream, leng);
            //_Stream = Bass.BASS_StreamCreateFileUser(false, BASSStream.BASS_DEFAULT | BASSStream.BASS_STREAM_AUTOFREE, myStreamCreateUser, 0);
            if (_Stream != 0)
            {
                marksCount = BassMidi.BASS_MIDI_StreamGetMarksCount(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);
                if (marksCount >= 0)
                {
                    //lyric_mark = new BASS_MIDI_MARK[marksCount];
                    marks = new BASS_MIDI_MARK[marksCount];
                    marks = BassMidi.BASS_MIDI_StreamGetMarks(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);
 
                    lyric_mark = marks;
                    //    textBox2.Text += String.Format("{0}" ,i)+ Environment.NewLine;
                }
                //Bass.BASS_StreamFree(_Stream);
                lyric_mark_count = marksCount;
                isLoaded = true;
            }
            return;
        }
    }

}

I mark were the error was given, but not all the time. The full code is in the zip file..
« Last Edit: 21 Dec '06 - 19:44 by dukus »

radio42

  • Posts: 4574
Re: BASSMIDI beta
« Reply #65 on: 21 Dec '06 - 20:28 »
Yepp - now I see what you mean.
I could even reproduce it here with your original code you posted.

However, I guess this time it is really not a BASS.NET issue - but may be a BASSmidi timing issue.

Try to remove the code after your BASS_ChannelPlay call:
Before:
Code: [Select]
if (_Stream != 0 && Bass.BASS_ChannelPlay(_Stream, false))
{
    marksCount = BassMidi.BASS_MIDI_StreamGetMarksCount(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);
    textBox2.Text = marksCount.ToString();
    if (marksCount >= 0)
    {
        marks = new BASS_MIDI_MARK[marksCount];
        marks = BassMidi.BASS_MIDI_StreamGetMarks(_Stream, BASSMIDIMarker.BASS_MIDI_MARK_LYRIC);
    }
    this.textBox1.Text += "ChannelPlay: playing" + Environment.NewLine;
}

After:
Code: [Select]
if (_Stream != 0 && Bass.BASS_ChannelPlay(_Stream, false))
{
    this.textBox1.Text += "ChannelPlay: playing" + Environment.NewLine;
}

When I remove the code getting all the lyric markers right after the BASS_ChannelPlay code, I don't get any exception anymore. It looks like getting the lyric markers right when playback started causes the problem.

I'll contact Ian to see, if he can find something out.

dukus

  • Posts: 6
Re: BASSMIDI beta
« Reply #66 on: 21 Dec '06 - 21:14 »
 :D Thanks, now is much better an working , but is not perfect after 10-15 tries crash, if remove the function Bass.BASS_ChannelGetLength(_Stream) then crash only after 30-50 tries. I don't no what  is the problem again some timing problem or i don't make something  right.
Thanks, again. greet work.

radio42

  • Posts: 4574
Re: BASSMIDI beta
« Reply #67 on: 23 Dec '06 - 20:29 »
Here comes a new little update to the v2.3.0.9 version:

.Net 1.1. build : http://www.un4seen.com/filez/4/Bass23.Net11_update.zip
.Net 2.0 build : http://www.un4seen.com/filez/4/Bass23.Net20_update.zip

Make sure to copy the included files to your install directory! 
 
Fix II:
- BassMidi.BASS_MIDI_StreamGetMarks still sometimes causes a crash!
 

iCorp

  • Posts: 65
Re: BASSMIDI beta
« Reply #68 on: 26 Dec '06 - 12:53 »
Hello!
Can I get all midi tracks names with bassmidi?
Can I mute (turn off) any midi tracks with bassmidi?
 :)
Thank you.

Ian @ un4seen

  • Administrator
  • Posts: 20401
Re: BASSMIDI beta
« Reply #69 on: 27 Dec '06 - 15:47 »
Can I get all midi tracks names with bassmidi?

The track name should be the first entry in the track's BASS_TAG_MIDI_TRACK tags (with the name of the first track being the name of the song).

Can I mute (turn off) any midi tracks with bassmidi?

There isn't currently any overall channel volume/mute control besides the volume MIDI event (which can be overridden by the file), but here's an update to try...

   www.un4seen.com/stuff/bassmidi.dll

It includes a new MIDI_EVENT_MIXLEVEL event...

Code: [Select]
#define MIDI_EVENT_MIXLEVEL 29
Using BASS_MIDI_StreamEvent, set that to 0 to mute a channel (100=normal level).

iCorp

  • Posts: 65
Re: BASSMIDI beta
« Reply #70 on: 29 Dec '06 - 09:12 »
...but here's an update to try...

Thanks a lot Ian!
 :)