21 May '13 - 19:15 *
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: BASS_ChannelPlay returns immediately (SOLVED)  (Read 1156 times)
levellord
Posts: 6


« on: 7 Oct '11 - 14:23 »
Reply with quoteQuote

is there any way to let the BASS_ChannelPlay method block until the stream or .wav file reached the end?
the problem is that i don't want to play the files simultaneously but one after another.
« Last Edit: 8 Oct '11 - 02:49 by levellord » Logged
gyrosp
Posts: 31


« Reply #1 on: 7 Oct '11 - 14:37 »
Reply with quoteQuote

Hi. You can use BASS_ChannelSetSync with BASS_SYNC_END. You provide a callback-function which is called when the stream has finished. Then you can play the next stream.
Logged
levellord
Posts: 6


« Reply #2 on: 7 Oct '11 - 15:05 »
Reply with quoteQuote

yes, i read about this, but im not sure what the callback function should do, maybe set a flag?
my function which plays soundfiles is:

internal static void play_bass_device(string soundfile, BASSFlag flags)
        {
            // create a stream channel from a file
            int stream = Bass.BASS_StreamCreateFile(soundfile, 0L, 0L, flags);
            if (stream != 0)
            {
                // play the channel
                Bass.BASS_ChannelPlay(stream, false);
            }
            else
            {
                // error
                Console.WriteLine("Stream error: {0}", Bass.BASS_ErrorGetCode());
            }

        }

it is called several times without delay. so all soundfiles play together.
Logged
gyrosp
Posts: 31


« Reply #3 on: 7 Oct '11 - 15:13 »
Reply with quoteQuote

You can do something like this:

        private static int Play(AudioDatei datei)
        {
            int stream = Bass.BASS_StreamCreateFile(Methods.GetFullMediaPathFromDB(datei), 0, 0, BASSFlag.BASS_STREAM_AUTOFREE);
            if (stream != 0)
            {
                channelFinishedSyncProc = new SYNCPROC(ChannelFinished);
                Bass.BASS_ChannelSetSync(stream, BASSSync.BASS_SYNC_END, 0, _channelFinishedSyncProc, IntPtr.Zero);

                Bass.BASS_ChannelPlay(stream, false);

                return stream;
            }
            else
            {
                return 0;
            }
        }


        private static void ChannelFinished(int handle, int channel, int data, IntPtr user)
        {
            Play(your media);
        }
Logged
Ian @ un4seen
Administrator
Posts: 15259


« Reply #4 on: 7 Oct '11 - 17:02 »
Reply with quoteQuote

yes, i read about this, but im not sure what the callback function should do, maybe set a flag?

If you want to block until the file is played, you could create an "event" (eg. CreateEvent) and then wait (eg. WaitForSingleObject) for that to be set (eg. SetEvent) by the sync callback function. Note the functions in parentheses are Win32 functions (.Net has AutoResetEvent/ManualResetEvent for it).

Another simple (but perhaps less elegant/efficient) way to do it is to poll BASS_ChannelIsActive in a loop (with some pause) until it returns BASS_ACTIVE_STOPPED (0).
Logged
levellord
Posts: 6


« Reply #5 on: 8 Oct '11 - 02:48 »
Reply with quoteQuote

i think i have a solution that works for me. i first tried with AutoResetEvent/ManualResetEvent, but the WaitOne method blocks indefinitely in certain cases
and i couldn't figure out why. so i did it with BASS_ChannelIsActive.
There are 2 methods one sync method which blocks and one async method which doesn't. the bevavior ist very similar to ``BOOL WINAPI PlaySound''
in winmm.dll with flags SND_SYNC and SND_ASYNC. here some code lines:


private static int stream_sync;
private static int stream_async;

//init sound device
internal static void init_bass_device(int hdev)
        {
            stream_sync = 0;
            stream_async = 0;
            //dont init more than one device
            Bass.BASS_Free();
            if (Bass.BASS_Init(hdev, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero))
            {
            }
            else
                _wrln("Bass error: {0}" + Bass.BASS_ErrorGetCode());
        }

        //ASYNC
        internal static void play_bass_device_async(string soundfile, BASSFlag flags)
        {
            
            //i dont want to play sounds at the same time, so i just cancel the synchronous stream
            if(Bass.BASS_ChannelIsActive(stream_async) != BASSActive.BASS_ACTIVE_STOPPED)
                Bass.BASS_ChannelStop(stream_async);
            stream_async = Bass.BASS_StreamCreateFile(soundfile, 0L, 0L, flags);
            if (stream_async != 0)
            {
                // play the channel
                Bass.BASS_ChannelPlay(stream_async, false);
            }
            else
            {
                // error
                Console.WriteLine("Stream error: {0}", Bass.BASS_ErrorGetCode());
            }

        }

        //SYNC
        internal static void play_bass_device_sync(string soundfile, BASSFlag flags)
        {
            //wait until stream_sync has finished
            while (Bass.BASS_ChannelIsActive(stream_sync) != BASSActive.BASS_ACTIVE_STOPPED)
            {
                Thread.Sleep(20);
            }
            //i dont want to play sounds at the same time, so i just cancel the asynchronous stream
            if (Bass.BASS_ChannelIsActive(stream_async) != BASSActive.BASS_ACTIVE_STOPPED)
                Bass.BASS_ChannelStop(stream_async);
            // create a stream channel from a file
            stream_sync = Bass.BASS_StreamCreateFile(soundfile, 0L, 0L, flags);
            if (stream_sync != 0)
            {
                // play the channel
                Bass.BASS_ChannelPlay(stream_sync, false);
            }
            else
            {
                // error
                Console.WriteLine("Stream error: {0}", Bass.BASS_ErrorGetCode());
            }
            //wait until stream_sync has finished
            while (Bass.BASS_ChannelIsActive(stream_sync) != BASSActive.BASS_ACTIVE_STOPPED)
            {
                Thread.Sleep(20);
            }

        }
        
        //calling method
        private void plays(string str, main.PlaySoundFlags flgs)
        {
            //play sound only on rear/surround speakers
            BASSFlag spk_flag = BASSFlag.BASS_SPEAKER_REAR;
            string cur_dir = Directory.GetCurrentDirectory();
            string soundfile = @cur_dir + @"\Media\" + str + ".wav";
            if(!File.Exists(soundfile))
                return;
            main._DEBUG("playSound(): " + soundfile);
            if(flgs == main.PlaySoundFlags.SND_SYNC)
                main.play_bass_device_sync(soundfile, spk_flag);
            else if(flgs == main.PlaySoundFlags.SND_ASYNC)
                main.play_bass_device_async(soundfile, spk_flag);
            
        }

thx for your help!
« Last Edit: 8 Oct '11 - 17:06 by levellord » Logged
gyrosp
Posts: 31


« Reply #6 on: 8 Oct '11 - 18:11 »
Reply with quoteQuote

            //wait until stream_sync has finished
            while (Bass.BASS_ChannelIsActive(stream_sync) != BASSActive.BASS_ACTIVE_STOPPED)
            {
                Thread.Sleep(20);
            }

This may work but this is definitely no good design for an OOP-language.
Logged
levellord
Posts: 6


« Reply #7 on: 8 Oct '11 - 19:13 »
Reply with quoteQuote

This may work but this is definitely no good design for an OOP-language.

yes i know its a bit dirty, but i had some problems with manual/autoresetevent
which i used with a callback function. so i saw no other possibility.  Undecided
Logged
levellord
Posts: 6


« Reply #8 on: 13 Oct '11 - 18:21 »
Reply with quoteQuote

This may work but this is definitely no good design for an OOP-language.

i didn't like my prevoius solution, too. and also to please gyrosp Smiley i invested some time.
here's a more elegant solution now:

        private static ManualResetEvent _manualevent = new ManualResetEvent(true);
        private static AutoResetEvent _autoevent = new AutoResetEvent(true);
        private static SYNCPROC _channelFinishedSyncProc;
        private static int stream_sync;
        private static int stream_async;

        internal static void init_bass_device(int hdev)
        {
            stream_sync = 0;
            stream_async = 0;
            _channelFinishedSyncProc = new SYNCPROC(ChannelFinished);
            //dont init more than one device
            Bass.BASS_Free();
            if (Bass.BASS_Init(hdev, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero))
            {
            }
            else
                _wrln("Bass error: {0}" + Bass.BASS_ErrorGetCode());

        }
        internal static void play_bass_device_async(string soundfile, BASSFlag flags)
        {
           
            //i dont want to play sounds at the same time, so i just cancel the synchronous stream
            if(Bass.BASS_ChannelIsActive(stream_async) != BASSActive.BASS_ACTIVE_STOPPED)
                Bass.BASS_ChannelStop(stream_async);
            stream_async = Bass.BASS_StreamCreateFile(soundfile, 0L, 0L, flags| BASSFlag.BASS_STREAM_AUTOFREE);
            if (stream_async != 0)
            {
                // play the channel
                Bass.BASS_ChannelPlay(stream_async, false);
            }
            else
            {
                // error
                Console.WriteLine("Stream error: {0}", Bass.BASS_ErrorGetCode());
            }

        }

        internal static void play_bass_device_sync(string soundfile, BASSFlag flags)
        {
            _autoevent.WaitOne();
            _manualevent.Reset();
            //i dont want to play sounds at the same time, so i just cancel the asynchronous stream
            if (Bass.BASS_ChannelIsActive(stream_async) != BASSActive.BASS_ACTIVE_STOPPED)
                Bass.BASS_ChannelStop(stream_async);
            // create a stream channel from a file
            stream_sync = Bass.BASS_StreamCreateFile(soundfile, 0L, 0L, flags | BASSFlag.BASS_STREAM_AUTOFREE);
            if (stream_sync != 0)
            {
                Bass.BASS_ChannelSetSync(stream_sync, BASSSync.BASS_SYNC_END, 0, _channelFinishedSyncProc, IntPtr.Zero);
                // play the channel
                Bass.BASS_ChannelPlay(stream_sync, false);
            }
            else
            {
                // error
                Console.WriteLine("Stream error: {0}", Bass.BASS_ErrorGetCode());
            }
            _manualevent.WaitOne();

        }

        private static void ChannelFinished(int handle, int channel, int data, IntPtr user)
        {
            _manualevent.Set();
            _autoevent.Set();
        }



Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines