Author Topic: Dynamic Realtime Loop VS payware version?  (Read 355 times)

RC

  • Posts: 14
Dynamic Realtime Loop VS payware version?
« on: 14 Jul '21 - 15:20 »
Hi,

1) inside of a high precision timer (1ms) I tried to reposition the play position of a stream by BASS_ChannelGetPosition and BASS_ChannelSetPosition.
But each call into BASS response after ~60ms, or values are updated only at ~16.66666Hz. Too slow to play a loops correctly.
How often per time we get a new return value from the function BASS_ChannelGetPosition() ?

Seems a real-time loops with dynamic changing positions is impossible with BASS?

2) I tried another solution and use to play a realtime loop by:
   BASS_ChannelSetPosition(HStream%, LOOP_PlayLoop.Start, BASS_POS_LOOP)
   BASS_ChannelSetPosition(HStream%, LOOP_PlayLoop.End, BASS_POS_END)
   ...

But declarations for BASS_POS_LOOP, or BASS_POS_END are missing in any BASS.X.dll.BASSMode.xxxx
Further BassEnc using BASS_POS_END as well. Therefore I can't get the code to work for testing purposes.

a) Do I have to brought at least the shareware version to access to all functionality?
b) Does the payed version of bass.dll does have an option to fasten up the internal BASS_ChannelGetPosition to about 1ms response?
c) Is there any other easy way to archive real-time play positioning in BASS without extensive coding and moving sample data through the system?

regards, RC

Ian @ un4seen

  • Administrator
  • Posts: 23889
Re: Dynamic Realtime Loop VS payware version?
« Reply #1 on: 14 Jul '21 - 16:52 »
1) inside of a high precision timer (1ms) I tried to reposition the play position of a stream by BASS_ChannelGetPosition and BASS_ChannelSetPosition.
But each call into BASS response after ~60ms, or values are updated only at ~16.66666Hz. Too slow to play a loops correctly.
How often per time we get a new return value from the function BASS_ChannelGetPosition() ?

There will be a delay in the new position being heard due to buffering, ie. the output device will have some buffered data from the old position to play first.

If you want to do sample-accurate custom looping, you can do so by setting a "mixtime" BASS_SYNC_POS sync on the stream and calling BASS_ChannelSetPosition in your SYNCPROC callback:

Code: [Select]
BASS_ChannelSetSync(stream, BASS_SYNC_POS | BASS_SYNC_MIXTIME, loopendpos, LoopSyncProc, 0); // set a mixtime sync at the loop end

...

void CALLBACK LoopSyncProc(HSYNC handle, DWORD channel, DWORD data, void *user)
{
BASS_ChannelSetPosition(channel, loopstartpos, BASS_POS_BYTE); // seek to the loop start
}

Alternatively, you can use the new BASS_POS_LOOP and BASS_POS_END options in BASS 2.4.16...

Seems a real-time loops with dynamic changing positions is impossible with BASS?

2) I tried another solution and use to play a realtime loop by:
   BASS_ChannelSetPosition(HStream%, LOOP_PlayLoop.Start, BASS_POS_LOOP)
   BASS_ChannelSetPosition(HStream%, LOOP_PlayLoop.End, BASS_POS_END)
   ...

But declarations for BASS_POS_LOOP, or BASS_POS_END are missing in any BASS.X.dll.BASSMode.xxxx

That looks like you're using a third-party wrapper of some kind to access BASS? If so, you can copy the BASS_POS_LOOP and BASS_POS_END definitions to that from the BASS.H file included in the BASS package.

a) Do I have to brought at least the shareware version to access to all functionality?

No, the freely downloadable BASS version is the full version.

RC

  • Posts: 14
Re: Dynamic Realtime Loop VS payware version?
« Reply #2 on: 15 Jul '21 - 13:57 »
Thanks for the info.

Your example does not provide control over play position. Unfortunately it does not help on getting the current play position.
As I wrote, GetPosition receives a value at 16 times per second only.

To work properly and "in-time" without any hear-able notice, I must receive the bytepos at about 1ms and set as well.

Would it possible to integrate these 1ms functions to bass?
Or do you have another solution?


Ian @ un4seen

  • Administrator
  • Posts: 23889
Re: Dynamic Realtime Loop VS payware version?
« Reply #3 on: 15 Jul '21 - 15:10 »
BASS_ChannelGetPosition should be sample-precise. When/where are you calling it? If you're doing it in a timer, it may be that the timer's precision is limited. Try calling BASS_ChannelGetPosition and displaying/logging the result in a loop, and see what that shows. If it shows the position is advancing in 60ms increments (or anything like that), also confirm how you're playing the stream, eg. normal BASS playback, via a BASSmix mixer, or perhaps BASSASIO or BASSWASAPI?

RC

  • Posts: 14
Re: Dynamic Realtime Loop VS payware version?
« Reply #4 on: 16 Jul '21 - 14:47 »
I'm on PC win7/10

I use following system calls to create a 1ms MM Timer

Code: [Select]
Declare Function NtSetTimerResolution Lib "ntdll.dll"
Declare Function NtQueryTimerResolution Lib "ntdll.dll"
Declare Function CreateTimerQueueTimer Lib "kernel32"
Declare Function DeleteTimerQueueTimer Lib "kernel32"

https://docs.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueuetimer

You can also create a simple while() loop runs at 1ms using:
https://docs.microsoft.com/de-de/dotnet/api/system.diagnostics.stopwatch?view=net-5.0
 
Inside of the 1ms loop use the following code to check.

Code: [Select]
qword pos_older = 0;
qword pos_newer = 0;
int   count     = 0;        // display how often we receive the same value from BASS_ChannelGetPosition
int   loop_1msCheck  = 0;   // display var to check if we run 1000 times per second

{
pos_newer = BASS_ChannelGetPosition(HStream%, BASS_POS_BYTE);
if (pos_older <> pos_newer) {
          pos_older = pos_newer;
          count = 0;
else       
          count++;
        }
        loop_1msCheck++;
}

The count displays ~60, loop_1msCheck display add 1000 per second.
The worst case scenario would be, the test loop runs 59 times at 16ms, then in the last 16 ms about 951 times. (That's infinite impossibility)

Plz try this on your win system.

Timer on the Windows function QueryPerformanceCounter, which uses the counter component for time measurement, which is also responsible for the interrupts to be called at regular intervals. On every IBM PC compatible it prints this counter at the same frequency. Every time this 16-bit counter runs through zero (1048576/65536, about 16.0 times per second), an interrupt is triggered which, among other things, is used to update the GetTickCount() counter, which is vital for 32 bit Windows part.

« Last Edit: 16 Jul '21 - 14:53 by RC »

QuentinC

  • Posts: 70
Re: Dynamic Realtime Loop VS payware version?
« Reply #5 on: 16 Jul '21 - 15:05 »
Hello,

Are you really sure that these timer functions can achieve 1ms precision ?

Because when I read this in the documentation:
Quote
The callback is called every time the period elapses, whether or not the previous callback has finished executing. Callback functions are queued to the thread pool. These threads are subject to scheduling delays, so the timing can vary depending on what else is happening in the application or the system.

It doesn't look very stable for so short delay.
Typically when scheduling is implied, it's very hard to stay stable under 10ms.

For that level of precision, I think that you should really use BASS_POS_LOOP/BASS_POS_END in BASS 2.4.16, or a mixtime sync in older versions, rather than timers.
You can try to reduce buffering, but I don't believe it would be enough.

And if the loop points are constantly changing, making it not very practical for setting syncs, probably I would go for a custom stream.

Ian @ un4seen

  • Administrator
  • Posts: 23889
Re: Dynamic Realtime Loop VS payware version?
« Reply #6 on: 16 Jul '21 - 15:29 »
Here's a modified version of the CONTEST.C example that you can try for comparison:

   www.un4seen.com/stuff/contest-nowait.exe

This part of the code is modified to display the position on a new line (so you can see the difference) and without a delay:

Code: [Select]
...
printf(" R | cpu %.2f%%  \n", BASS_GetCPU());
fflush(stdout);
// Sleep(50);
...

RC

  • Posts: 14
Re: Dynamic Realtime Loop VS payware version?
« Reply #7 on: 18 Jul '21 - 16:23 »
Thanks for the example. Yes it's works out of the box.
Win10 made some painful changes over the updates. The 2004 update reduce the Thread.sleep to 15ms.

Did you have a code idea to setup a callback timer in win10 can perform at 1ms without .net?

Ian @ un4seen

  • Administrator
  • Posts: 23889
Re: Dynamic Realtime Loop VS payware version?
« Reply #8 on: 19 Jul '21 - 16:39 »
The old timeSetEvent function can be used to request a 1ms timer. I'm not sure that's a good idea though, regarding efficiency. If the timer is just for custom looping purposes then I would recommend trying the BASS_POS_LOOP and BASS_POS_END options (new in BASS 2.4.16)  first, as that will be both more efficient and precise. A demonstration of using those options can be found in the CUSTLOOP.C example included in the BASS package.