Author Topic: Set a stream priority  (Read 1061 times)

teq

  • Posts: 33
Set a stream priority
« on: 18 Nov '18 - 09:45 »
I use Bass.Net in Unity, and my player has metronome option.
My main song channel
Code: [Select]
netStream = Bass.BASS_StreamCreateURL(Uri.EscapeUriString(CommonSettings.Instance.assetBundlesURL + model.clipName.ToLower() + ".mp3"),
                                                          0,
                                                          BASSFlag.BASS_STREAM_DECODE,
                                                          _trackDownloadProc,
                                                          IntPtr.Zero);
streamTempoFX = BassFx.BASS_FX_TempoCreate(streamingTrack ? netStream : stream, BASSFlag.BASS_FX_FREESOURCE);
Metronome stream
Code: [Select]
metronomeStream = Bass.BASS_StreamCreateFile(_clickHGCFile.AddrOfPinnedObject(),
                                                     0L, clickBytes.Length, BASSFlag.BASS_SAMPLE_FLOAT);

Independent thread for metronome
Code: [Select]
private async void Infinite()
    {
        while (infiniteLoopEnabled)
        {
            await Task.Delay(300);

            Bass.BASS_ChannelPlay(metronomeStream, true);
        }
    }

UI has some CG allocations which triggers some lags, and they are not affecting main channel, but metrome lags with them

I thinks it's because tracks is already loaded and due to his not affecting by garbage collector, but metronome click is every time Play in cycle.

May be i need to use another flags or somehow set priority?
« Last Edit: 18 Nov '18 - 12:05 by teq »

Ian @ un4seen

  • Administrator
  • Posts: 21741
Re: Set a stream priority
« Reply #1 on: 19 Nov '18 - 13:41 »
You could use a mixer and BASS_SYNC_POS syncs to precisely time the metronome playbacks, something like this:

Code: [Select]
BASS_CHANNELINFO info;
BASS_ChannelGetInfo(metronomeStream, &info); // get metronome sample format
metronomemixer = BASS_Mixer_StreamCreate(info.freq, info.chans, BASS_SAMPLE_FLOAT | BASS_MIXER_NONSTOP); // create non-stop mixer with same format
BASS_Mixer_StreamAddChannel(metronomemixer, metronomeStream, BASS_MIXER_NORAMPIN); // plug metronome into mixer
QWORD syncpos = BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // repeat playback position (300ms)
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
BASS_ChannelPlay(metronomemixer, 0); // start the mixer

...

void CALLBACK MetronomeSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
BASS_ChannelSetPosition(metronomeStream, 0, BASS_POS_BYTE); // rewind metronome sound
QWORD syncpos = BASS_ChannelGetPosition(channel, BASS_POS_BYTE | BASS_POS_DECODE); // get mixer's current position
syncpos += BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // next playback position
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
}

Please see the documentation for details on the mentioned functions. Note you will also need to add the BASS_STREAM_DECODE flag to the metronome sound's BASS_StreamCreateFile call.

teq

  • Posts: 33
Re: Set a stream priority
« Reply #2 on: 19 Nov '18 - 19:39 »
You could use a mixer and BASS_SYNC_POS syncs to precisely time the metronome playbacks, something like this:

Code: [Select]
BASS_CHANNELINFO info;
BASS_ChannelGetInfo(metronomeStream, &info); // get metronome sample format
metronomemixer = BASS_Mixer_StreamCreate(info.freq, info.chans, BASS_SAMPLE_FLOAT | BASS_MIXER_NONSTOP); // create non-stop mixer with same format
BASS_Mixer_StreamAddChannel(metronomemixer, metronomeStream, BASS_MIXER_NORAMPIN); // plug metronome into mixer
QWORD syncpos = BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // repeat playback position (300ms)
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
BASS_ChannelPlay(metronomemixer, 0); // start the mixer

...

void CALLBACK MetronomeSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
BASS_ChannelSetPosition(metronomeStream, 0, BASS_POS_BYTE); // rewind metronome sound
QWORD syncpos = BASS_ChannelGetPosition(channel, BASS_POS_BYTE | BASS_POS_DECODE); // get mixer's current position
syncpos += BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // next playback position
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
}

Please see the documentation for details on the mentioned functions. Note you will also need to add the BASS_STREAM_DECODE flag to the metronome sound's BASS_StreamCreateFile call.

Thanks again! It works like a charm!

teq

  • Posts: 33
Re: Set a stream priority
« Reply #3 on: 20 Nov '18 - 10:34 »
You could use a mixer and BASS_SYNC_POS syncs to precisely time the metronome playbacks, something like this:

Code: [Select]
BASS_CHANNELINFO info;
BASS_ChannelGetInfo(metronomeStream, &info); // get metronome sample format
metronomemixer = BASS_Mixer_StreamCreate(info.freq, info.chans, BASS_SAMPLE_FLOAT | BASS_MIXER_NONSTOP); // create non-stop mixer with same format
BASS_Mixer_StreamAddChannel(metronomemixer, metronomeStream, BASS_MIXER_NORAMPIN); // plug metronome into mixer
QWORD syncpos = BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // repeat playback position (300ms)
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
BASS_ChannelPlay(metronomemixer, 0); // start the mixer

...

void CALLBACK MetronomeSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
BASS_ChannelSetPosition(metronomeStream, 0, BASS_POS_BYTE); // rewind metronome sound
QWORD syncpos = BASS_ChannelGetPosition(channel, BASS_POS_BYTE | BASS_POS_DECODE); // get mixer's current position
syncpos += BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // next playback position
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
}

Please see the documentation for details on the mentioned functions. Note you will also need to add the BASS_STREAM_DECODE flag to the metronome sound's BASS_StreamCreateFile call.

Can't figure one moment. How to instantly play metronome sound (not waiting first n seconds) ?
And how to reset that sync? So user has one bit per 5 seconds, he off/on or change metronome tempo and it must be restarted with new value (so i need to interrupt started sync)

And i need to use  Bass.BASS_ChannelSetSync or BassMix.BASS_Mixer_ChannelSetSync ?

UPDATE
All done. I just used this before initial play
Code: [Select]
Bass.BASS_ChannelSetPosition(metronomeStream, 0, BASSMode.BASS_POS_BYTE);
and made a reset method
Code: [Select]
Bass.BASS_ChannelRemoveSync(metronomeMixer, metronomeMixerSync);
Bass.BASS_ChannelStop(metronomeMixer);
Bass.BASS_StreamFree(metronomeMixer);
metronomeMixer = 0;

But one question is still remains: can i somehow sync when track is actually started ?
« Last Edit: 20 Nov '18 - 15:28 by teq »

teq

  • Posts: 33
Re: Set a stream priority
« Reply #4 on: 21 Nov '18 - 15:13 »
By the way is BASS_ChannelSetAttribute apply instantly or with delay ? I can't sync metronome with tempo, cause seems that i set both, metronome applies instantly but tempo fx is not

Ian @ un4seen

  • Administrator
  • Posts: 21741
Re: Set a stream priority
« Reply #5 on: 21 Nov '18 - 16:22 »
What attribute are you changing? BASS_ATTRIB_FREQ/PAN/VOL changes will be instant on normal playback channels, ie. those without the BASS_STREAM_DECODE flag set. In this case, that means changes will be instant on the mixer (metronomeMixer) but probably not on the metronome (metronomeStream) due to buffering. Most other attribute changes will generally be delayed in both cases (again due to buffering).

teq

  • Posts: 33
Re: Set a stream priority
« Reply #6 on: 21 Nov '18 - 17:54 »
What attribute are you changing? BASS_ATTRIB_FREQ/PAN/VOL changes will be instant on normal playback channels, ie. those without the BASS_STREAM_DECODE flag set. In this case, that means changes will be instant on the mixer (metronomeMixer) but probably not on the metronome (metronomeStream) due to buffering. Most other attribute changes will generally be delayed in both cases (again due to buffering).
I mean tempo of the main track. So i change it's speed, and then metronome bpm, but seems that tempo changing produced with some delay and song becomes async regarding metronome

And i can't check when actually click starts playing. So i debug in MetronomeSyncProc method, but click play after some delay
« Last Edit: 21 Nov '18 - 18:54 by teq »

Ian @ un4seen

  • Administrator
  • Posts: 21741
Re: Set a stream priority
« Reply #7 on: 22 Nov '18 - 17:38 »
So you're using the BASS_ATTRIB_TEMPO attribute? What type of stream are you using it on? In the metronome's case, I assume you are just changing the playback/sync interval rather than using BASS_FX tempo processing on it.

teq

  • Posts: 33
Re: Set a stream priority
« Reply #8 on: 13 Feb '19 - 14:54 »
Hi there! If i want to use few metronome clicks with different sound and play each in specific period, should i use several mixers with severs BASS_ChannelSetSync ?
« Last Edit: 14 Feb '19 - 09:35 by teq »

teq

  • Posts: 33
Re: Set a stream priority
« Reply #9 on: 14 Feb '19 - 09:36 »
I could count some var, and on every first beat play 1 sound, and other play second sound. But this mixer sync works strange: i start mixer with play and i expect that MetronomeSyncProc wil be called after metronome delay time, and then i would hadnle logic with different sounds, but this sync callback invokes way faster, almost right away after mixer start. May be it's due to threaded Sync origin and in main code i got callback with some delay?
« Last Edit: 14 Feb '19 - 09:50 by teq »

Ian @ un4seen

  • Administrator
  • Posts: 21741
Re: Set a stream priority
« Reply #10 on: 14 Feb '19 - 13:50 »
Hi there! If i want to use few metronome clicks with different sound and play each in specific period, should i use several mixers with severs BASS_ChannelSetSync ?

If you want the metronome sounds to be in sync with each other, it would be best to use the same mixer to play all of them.

I could count some var, and on every first beat play 1 sound, and other play second sound. But this mixer sync works strange: i start mixer with play and i expect that MetronomeSyncProc wil be called after metronome delay time, and then i would hadnle logic with different sounds, but this sync callback invokes way faster, almost right away after mixer start. May be it's due to threaded Sync origin and in main code i got callback with some delay?

Assuming that you're using a "mixtime" sync (BASS_SYNC_MIXTIME) to play the metronome sounds, as in the code I posted earlier in this thread, the syncs will be called when the mixer is about to generate data at a sync position. That will be some time ahead of when the position is heard due to buffering (see BASS_CONFIG_BUFFER).

If you want to cycle through different sounds for the metronome ticks, you could have an array of streams that you cycle through in the SYNCPROC. For example, the code posted earlier could be modified something like this:

Code: [Select]
void CALLBACK MetronomeSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
metronometick++; // metronome tick number
if (metronometick == metronometicks) metronometick = 0; // back to 1st
DWORD sound = metronomeStreams[metronometick]; // the metronome sound to play
BASS_ChannelSetPosition(sound, 0, BASS_POS_BYTE); // rewind it
BASS_Mixer_StreamAddChannel(metronomemixer, sound, BASS_MIXER_NORAMPIN); // plug it into mixer (in case it isn't already)
QWORD syncpos = BASS_ChannelGetPosition(channel, BASS_POS_BYTE | BASS_POS_DECODE); // get mixer's current position
syncpos += BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // next playback position
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
}

teq

  • Posts: 33
Re: Set a stream priority
« Reply #11 on: 14 Feb '19 - 16:00 »
Hi there! If i want to use few metronome clicks with different sound and play each in specific period, should i use several mixers with severs BASS_ChannelSetSync ?

If you want the metronome sounds to be in sync with each other, it would be best to use the same mixer to play all of them.

I could count some var, and on every first beat play 1 sound, and other play second sound. But this mixer sync works strange: i start mixer with play and i expect that MetronomeSyncProc wil be called after metronome delay time, and then i would hadnle logic with different sounds, but this sync callback invokes way faster, almost right away after mixer start. May be it's due to threaded Sync origin and in main code i got callback with some delay?

Assuming that you're using a "mixtime" sync (BASS_SYNC_MIXTIME) to play the metronome sounds, as in the code I posted earlier in this thread, the syncs will be called when the mixer is about to generate data at a sync position. That will be some time ahead of when the position is heard due to buffering (see BASS_CONFIG_BUFFER).

If you want to cycle through different sounds for the metronome ticks, you could have an array of streams that you cycle through in the SYNCPROC. For example, the code posted earlier could be modified something like this:

Code: [Select]
void CALLBACK MetronomeSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
metronometick++; // metronome tick number
if (metronometick == metronometicks) metronometick = 0; // back to 1st
DWORD sound = metronomeStreams[metronometick]; // the metronome sound to play
BASS_ChannelSetPosition(sound, 0, BASS_POS_BYTE); // rewind it
BASS_Mixer_StreamAddChannel(metronomemixer, sound, BASS_MIXER_NORAMPIN); // plug it into mixer (in case it isn't already)
QWORD syncpos = BASS_ChannelGetPosition(channel, BASS_POS_BYTE | BASS_POS_DECODE); // get mixer's current position
syncpos += BASS_ChannelSeconds2Bytes(metronomemixer, 0.3); // next playback position
BASS_ChannelSetSync(metronomemixer, BASS_SYNC_POS | BASS_SYNC_MIXTIME | BASS_SYNC_ONETIME, syncpos, MetronomeSyncProc, NULL); // set a sync there
}

Thanks a lot! Should i use BASS_Mixer_ChannelRemove for previous click sound stream before adding another?

Ian @ un4seen

  • Administrator
  • Posts: 21741
Re: Set a stream priority
« Reply #12 on: 14 Feb '19 - 17:56 »
You could use BASS_Mixer_ChannelRemove to remove the previous metronome sound from the mixer but it isn't really necessary to do so. I guess it is unlikely that the metronome sounds will overlap, but just in case they do, it's probably best to just leave them in the mixer (so they don't get cut off). They won't be using any CPU once the mixer reaches the end of them.