Author Topic: Infinity looping with crossover effect  (Read 143 times)

Olek

  • Posts: 21
Infinity looping with crossover effect
« on: 28 Nov '17 - 14:02 »
I use mixer for playback and I need to repeat some channels for infinity and transition between loops must be seamless. I tried to use BASS_SAMPLE_LOOP flag and it was almost acceptable. But in some files we have fade in\out effects with crossover to repeat file for N(not infinity) times. Using BASS_SAMPLE_LOOP with such files causes visible transition between loops.

To fix that I think to create 2 stream channels, play first to the end having second overlapping end of the first. When first channel reaches the end move it to the end of the second and repeat that for infinity times.

But there might be better solution. Another option was infinity stream but I don't a way to do crossover and how to control stream size.




Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: Infinity looping with crossover effect
« Reply #1 on: 28 Nov '17 - 17:36 »
Yes, to crossfade the end of a file, you will indeed need to use 2 streams. You could switch between the streams for each loop. The SYNCPROC could look something like this:

Code: [Select]
void CALLBACK CrossFadeSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
QWORD length = BASS_ChannelGetLength(stream[current], BASS_POS_BYTE); // get channel's length
QWORD fadelen = length - BASS_ChannelGetPosition(stream[current], BASS_POS_BYTE); // get length remaining
fadelen = BASS_ChannelSeconds2Bytes(mixer, BASS_ChannelBytes2Seconds(stream[current], fadelen)); // translate that for the mixer's format (in case it's different)
BASS_MIXER_NODE nodes[2] = { // 2 envelope nodes for a fade-out
{0, 1}, // start at vol=1
{fadelen, 0} // end at vol=0
};
BASS_Mixer_ChannelSetEnvelope(stream[current], BASS_MIXER_ENV_VOL, nodes, 2); // apply the envelope to current stream

current = 1 - current; // switch to other stream
BASS_ChannelSetPosition(stream[current], 0, BASS_POS_BYTE); // rewind it
BASS_Mixer_StreamAddChannel(mixer, stream[current], BASS_MIXER_NORAMPIN); // add it to the mix
// switch envelope vales for fade-in
nodes[0].val = 0;
nodes[1].val = 1;
BASS_Mixer_ChannelSetEnvelope(stream[current], BASS_MIXER_ENV_VOL, nodes, 2); // apply the envelope

QWORD nextsync = BASS_ChannelGetPosition(mixer, BASS_POS_BYTE|BASS_POS_DECODE)
+ BASS_ChannelSeconds2Bytes(mixer, BASS_ChannelBytes2Seconds(stream[current], length)); // position of next sync = current pos + length of channel
BASS_ChannelSetSync(mixer, BASS_SYNC_POS|BASS_SYNC_MIXTIME|BASS_SYNC_ONETIME, nextsync, CrossFadeSyncProc, NULL); // set a one-time sync there
}

Note this is assuming that the sync is set on the mixer (not on the source), as it needs to be to have the fade-in and fade-out start exactly at the same time in the mixer output. If the crossfade isn't very short, then the difference might not be noticeable and you could get away with just setting a single sync at the crossfade position on each of the source streams (instead of setting a new sync on the mixer for each loop).

Olek

  • Posts: 21
Re: Infinity looping with crossover effect
« Reply #2 on: 7 Dec '17 - 10:13 »
Thanks for the answer!

Quote
BASS_Mixer_ChannelSetEnvelope(stream[current], BASS_MIXER_ENV_VOL, nodes, 2); // apply the envelope to current stream

Both on Android and iOS applying envelop causes tiny click in sound. Sliding volume attribute works ok but I would like to use envelopes.
Is it possible to fix somehow?

Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: Infinity looping with crossover effect
« Reply #3 on: 7 Dec '17 - 15:30 »
What crossfade length are you currently using, and does increasing that help? If that doesn't help, is the "click" caused by the fade-in or fade-out envelope?

Olek

  • Posts: 21
Re: Infinity looping with crossover effect
« Reply #4 on: 11 Dec '17 - 15:53 »
I use 3 seconds crossfade. I haven't tried to increase it.
Click caused by fade-out. Not sure is fade-in work.


Ian @ un4seen

  • Administrator
  • Posts: 20433
Re: Infinity looping with crossover effect
« Reply #5 on: 11 Dec '17 - 17:44 »
A click could be caused by the stream ending before the fade-out does. Is the stream's initial BASS_ChannelGetLength value accurate? If you're playing an MP3 file, you can use the BASS_STREAM_PRESCAN flag to pre-scan the file for an accurate length.

If it's still not working properly, how are you adding the stream to the mixer and setting the first crossfade sync? With the code I posted above, it should be something like this:

Code: [Select]
BASS_Mixer_StreamAddChannel(mixer, stream[current], 0); // add stream to mix
QWORD length = BASS_ChannelGetLength(stream[current], BASS_POS_BYTE); // get its length
QWORD syncpos = BASS_ChannelGetPosition(mixer, BASS_POS_BYTE|BASS_POS_DECODE)
+ BASS_ChannelSeconds2Bytes(mixer, BASS_ChannelBytes2Seconds(stream[current], length) - 3.0); // position of first sync = current pos + length of channel - crossfade length
BASS_ChannelSetSync(mixer, BASS_SYNC_POS|BASS_SYNC_MIXTIME|BASS_SYNC_ONETIME, syncpos, CrossFadeSyncProc, NULL); // set a one-time sync there