Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Foobar event/push mode (Read 38053 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Re: Foobar event/push mode

Reply #25
...the second quote is not talking about semaphores. It is the description of a busy loop. You can only make a connection with a timer given that you put the precondition that the data served is controlled by a crystal clock.

Probably by "semaphores" you actually mean "timers"?

Anyway, a busy loop is a way to implement a timer using a crystal clock.

I don't know if you both realize that with your points, the "event based" and the "push based" API become both different timer implementations, so blurring any difference by means of "abstract concepts".

The core idea here is that a push based system uses a timer to push things at regular intervals, while an event system does not.  The only way you can build a timer using the event system as your primitive is if the events are themselves created by the output of a timer.  This is however a circular argument, a timer can be used to construct a timer because it is a timer. 

 

Re: Foobar event/push mode

Reply #26
Audibly there should not be any difference, at all. Both modes should yield the same result.
Push mode however seems more prone to underruns especially in buggy implementations.

The main difference is that with push it is your job to grab the buffer at the right moment and fill it up again, while with events you will be informed of that.
Whether you do push with a busy loop (bad idea) or sleeps or timers doesn't really matter. And it also doesn't matter how event mode is implemented, but it's basically a monitor, i.e. the caller will be blocked until the event is signaled by the underlying layer (e.g. from another timer or a hardware interrupt).
"I hear it when I see it."

Re: Foobar event/push mode

Reply #27
Probably by "semaphores" you actually mean "timers"?
No. I am arguing all the time that my conception of timer does not include the concept of semaphore. Since we agree that we disagree with this, and we haven't found a way to tell each other why one of the sides is right, we're at an end point and we cannot continue.

Quote
Anyway, a busy loop is a way to implement a timer using a crystal clock.
A busy loop on an MS-DOS program waiting for the user to press a key uses a crystal clock? Or did you mean that waiting for a crystal clock on a soundcard to reach a value is waiting for a clock to reach a value? Duh!

Quote
The core idea here is that a push based system uses a timer to push things at regular intervals, while an event system does not.  The only way you can build a timer using the event system as your primitive is if the events are themselves created by the output of a timer.  This is however a circular argument, a timer can be used to construct a timer because it is a timer. 

Now i am sort of puzzled. You've described it in the exact opposite sense that I understand it:
The disadvantage of using push based method is that you either consume CPU on a busy loop asking if a value has been reached, or you put the thread to sleep for an amount of time to prevent consuming CPU and consequently there might be an undefined (and possibly variable) delay between the clock reaching the expected value, and your code reacting to that action.
And the advantage of the event based method is that the event is produced (supposedly by the soundcard driver itself) at the exact moment that the buffer is ready to be feed, so you don't consume CPU and are waken up as soon as possible.

The problem seems to go, again, around the WaitForSingleObject/WaitForMultipleObjects.
It acts like a timer if the buffer is not freed in time, and it acts like an event if the "event" (semaphore) of "buffer free" happens. But since we didn't agree that timer and semaphore are two different concepts, this argument of myself still leaves us at the same dead end.


Edit: I think what you both try to tell me is that push based is timer based because the soundcard clock works at a fixed interval, and obviously, buffers need to be feed at a regular interval in order for the stream to be delivered to the speakers.

That's not what I was talking about as it is obvious that the only way to feed a soundcard with a stream is delivering the stream "in time". In other words, you cannot implement a continuous audio stream using the user keystrokes as reference to when to deliver it.
What I was talking about is what is *explicitely* making the software determine that it is ready to deliver the next buffer and you keep saying "the timer, the timer", while i was focusing on what is the code checking to do so: A time delay, a busy loop or a synchronization mechanism like a producer/consumer.

Busy loop and producer/consumer are not concepts related to a timer. It just happens that, when used on an audio stream, these two will react on a clock reaching a value. But the concepts do not depend and are in no way related to a timer.

Re: Foobar event/push mode

Reply #28
Probably by "semaphores" you actually mean "timers"?
No. I am arguing all the time that my conception of timer does not include the concept of semaphore.

I don't even know what this is supposed to mean. 

Quote
Anyway, a busy loop is a way to implement a timer using a crystal clock.
A busy loop on an MS-DOS program waiting for the user to press a key uses a crystal clock?

Yes absolutely.  Is this a serious question?  How else do you think a busy loop keeps time but by counting clock cycles?  Magic?

Or did you mean that waiting for a crystal clock on a soundcard to reach a value is waiting for a clock to reach a value? Duh!

No. 

Now i am sort of puzzled. You've described it in the exact opposite sense that I understand it:
The disadvantage of using push based method is that you either consume CPU on a busy loop asking if a value has been reached, or you put the thread to sleep for an amount of time to prevent consuming CPU and consequently there might be an undefined (and possibly variable) delay between the clock reaching the expected value, and your code reacting to that action.
And the advantage of the event based method is that the event is produced (supposedly by the soundcard driver itself) at the exact moment that the buffer is ready to be feed, so you don't consume CPU and are waken up as soon as possible.

Correct, although the delay when you use push has to be variable unless the CPU and sound card are running off of a common oscillator with a fixed ratio between them. 

The problem seems to go, again, around the WaitForSingleObject/WaitForMultipleObjects.

I don't see how. 

Edit: I think what you both try to tell me is that push based is timer based because the soundcard clock works at a fixed interval,

No one has said anything like that and I have no idea why you would think so.

Let me try again: 

The core idea here is that a push based system uses a timer to push things at regular intervals, while an event system does not.  There is no way you can push things are regular intervals while ensuring that you do not get buffer underflows without measuring the passage of time.  The act of measuring the passage of time on a computer requires the concept of a timer.  This is all anyone is telling you. 

Busy loop and producer/consumer are not concepts related to a timer.

Anyway, a busy loop is a way to implement a timer using a crystal clock.

A busy loop is a software construct that measures time by counting hardware oscillator cycles.  I am baffled that you do not understand this. 

Re: Foobar event/push mode

Reply #29
The core idea here is that a push based system uses a timer to push things at regular intervals, while an event system does not.  There is no way you can push things are regular intervals while ensuring that you do not get buffer underflows without measuring the passage of time.  The act of measuring the passage of time on a computer requires the concept of a timer.  This is all anyone is telling you. 
Well, it's not that simple.
A push based system could do a busy wait (there are several options here, from a loop that will burn CPU over giving up the current thread's timeslice to sleeping - none of which use a timer). You can push at regular intervals and if you do it right you can avoid buffer underflows, except in situations where the event based system would also fail on a typical desktop OS, because they are not realtime and make no guarantees...

And the event based system we're talking about here is actually controlled by the audio device's period of fetching data from the buffer, which is synced to a sampling rate and therefore time.

"I hear it when I see it."

Re: Foobar event/push mode

Reply #30
A push based system could do a busy wait (there are several options here, from a loop that will burn CPU over giving up the current thread's timeslice to sleeping - none of which use a timer).

No.  Busy loops are a common way to implement timers in audio applications.  We use more than a few in rockbox drivers for instance, often when the interval is too small to be practical to use with an interrupt on a given hardware platform. 

You can push at regular intervals and if you do it right you can avoid buffer underflows, except in situations where the event based system would also fail on a typical desktop OS, because they are not realtime and make no guarantees...

Yes, but doing so requires you to measure the passage of time such that your intervals remain regular.  Devices for measuring the passage of time are timers. 

Re: Foobar event/push mode

Reply #31
No.
Yes, unless you actually measure the time there is no relation to time in a modern OS or on a modern computer because there are countless variables involved (scheduling, different CPUs, dynamic CPU clock rate, ...)

Busy loops are a common way to implement timers in audio applications.  We use more than a few in rockbox drivers for instance, often when the interval is too small to be practical to use with an interrupt on a given hardware platform.
You're talking embedded/microcontroller here, where you can rely on things like the hardware that you can't on a modern PC that uses WASAPI.

Yes, but doing so requires you to measure the passage of time such that your intervals remain regular.  Devices for measuring the passage of time are timers.
Not necessarily. You don't have to wait until the buffer is half empty, or fill it at such an interval. You could for example just try to fill it in a tight loop. No timers. In fact, this is less "timed" than event style which would fire every N device periods.
You could also do a Sleep(0) or SwitchToThread() on Windows, or do some other task in between on the same thread.
"I hear it when I see it."

Re: Foobar event/push mode

Reply #32
No.
Yes, unless you actually measure the time there is no relation to time in a modern OS or on a modern computer because there are countless variables involved (scheduling, different CPUs, dynamic CPU clock rate, ...)

Nonsense.  You still have to design your loop to poll based on the worst case clock speed.  If you actually tried to design a push system where you literally had no idea what the clock speeds were you'd likely fail and get dropouts.

Busy loops are a common way to implement timers in audio applications.  We use more than a few in rockbox drivers for instance, often when the interval is too small to be practical to use with an interrupt on a given hardware platform.

You're talking embedded/microcontroller here, where you can rely on things like the hardware that you can't on a modern PC that uses WASAPI.

Actually, in rockbox we also (usually) have variable clocks just like on Windows.  We just design the busy loops appropriately.  I don't see how this relates to your argument though.  You're still counting time, its just slightly more complex. 

Yes, but doing so requires you to measure the passage of time such that your intervals remain regular.  Devices for measuring the passage of time are timers.
Not necessarily. You don't have to wait until the buffer is half empty, or fill it at such an interval. You could for example just try to fill it in a tight loop.

Yes necessarily.  Tight loop is a timer in that it measures the passage of time and produces an action at predictable intervals (specifically, the action must happen at least as often as the minimum buffer period). 

I don't see why people keep getting mixed up in the details here.  "Push" is an algorithm, not an implementation.  It defines a series of actions, not any specific way of doing them.  No matter how you implement it, its still the same algorithm, and it still depends critically on being able to measure time.  Think up any crazy implementation you want.  Does it work for push?  Then it incorporates a timer. 

Re: Foobar event/push mode

Reply #33
Nonsense.  You still have to design your loop to poll based on the worst case clock speed.  If you actually tried to design a push system where you literally had no idea what the clock speeds were you'd likely fail and get dropouts.
No, what I wrote is not "nonsense" and such a reply is just as weak as your previous "no".
Clock speed is actually pretty irrelevant to what I tried to explain to you. It doesn't matter if a simple polling loop does 1k or 1 trillion cycles until the buffer has emptied far enough.
If the system is too slow to even finish a single cycle then it would also fail with WASAPI event style, so yeah... but I've told you that before.

Actually, in rockbox we also (usually) have variable clocks just like on Windows.  We just design the busy loops appropriately.  I don't see how this relates to your argument though.  You're still counting time, its just slightly more complex. 
No, as I said it's not counting time.
Code: [Select]
while (!quit)  { TryToFillAudioBuffer(); }
Where does this loop count anything let alone time?

Yes necessarily.  Tight loop is a timer in that it measures the passage of time and produces an action at predictable intervals (specifically, the action must happen at least as often as the minimum buffer period). 
No it's not necessary. Sigh. Go back and read again what I wrote. Your response here also misses the point.

I don't see why people keep getting mixed up in the details here.  "Push" is an algorithm, not an implementation.  It defines a series of actions, not any specific way of doing them.  No matter how you implement it, its still the same algorithm, and it still depends critically on being able to measure time.  Think up any crazy implementation you want.  Does it work for push?  Then it incorporates a timer. 
No, you don't need to measure any time. The only requirement for a tight loop would be the users' system: for example it needs to be fast enough to read some chunk of a file and decode it and fill the audio buffer with it before there is an underrun. That's also why buffer sizes are usually not hardcoded but user configurable to fit the user's system/requirements.
"I hear it when I see it."

Re: Foobar event/push mode

Reply #34
No, what I wrote is not "nonsense" and such a reply is just as weak as your previous "no".
Clock speed is actually pretty irrelevant to what I tried to explain to you. It doesn't matter if a simple polling loop does 1k or 1 trillion cycles until the buffer has emptied far enough.

This is wrong.  If your loop cannot be guaranteed to poll on an interval less than the buffer refill time, it will not work.  Therefore time absolutely does matter. 

If the system is too slow to even finish a single cycle then it would also fail with WASAPI event style, so yeah... but I've told you that before.

So what you are saying is that your implementation must consider time... and is therefore a keeping time...like a timer.

Actually, in rockbox we also (usually) have variable clocks just like on Windows.  We just design the busy loops appropriately.  I don't see how this relates to your argument though.  You're still counting time, its just slightly more complex. 
No, as I said it's not counting time.
Code: [Select]
while (!quit)  { TryToFillAudioBuffer(); }
Where does this loop count anything let alone time?

That loop is an oscillator that counts time.  Literally.  You are configuring a circuit in your PC to oscillate and so produce events on an interval with an upper bound (the duration of the audio buffer).  This is exactly what the hardware timers in your PC do BTW.

Yes necessarily.  Tight loop is a timer in that it measures the passage of time and produces an action at predictable intervals (specifically, the action must happen at least as often as the minimum buffer period). 
No it's not necessary.

Yes it is.  If you loop cannot meet those timing requirements, it will not work.

I don't see why people keep getting mixed up in the details here.  "Push" is an algorithm, not an implementation.  It defines a series of actions, not any specific way of doing them.  No matter how you implement it, its still the same algorithm, and it still depends critically on being able to measure time.  Think up any crazy implementation you want.  Does it work for push?  Then it incorporates a timer. 
No, you don't need to measure any time. The only requirement for a tight loop would be the users' system: for example it needs to be fast enough to read some chunk of a file and decode it and fill the audio buffer with it before there is an underrun.

You cannot simultaneously say that you do not need to measure time while also saying that you must meet some upper bound on timing.  It is one or the other.  Either time is bounded or it is not.  If it is bounded, then you have implemented a timer.  If it is truly unbounded, then you have not. 

Re: Foobar event/push mode

Reply #35
@saratoga: This conversation is really strange. It looks incredibly similar to the audiophile conversations that we try to keep out of this forum with the likes of TOS #8.

You are a knowledgeable person, with first hand experience in what we are talking here, but so we are. (Probably the experience of each one differ).
Quote
while(!exit) {
 int i= haskeypress();
  if (i) {
    char c = getc();
    doAction(c);
  }
  printScreen();
}

Say we want to do that in a PIC ( Programmable microprocessor).  Maybe with a clock of 10Mhz.
The loop will run at whatever speed the processor is able to put out.
It is to be expected that "haskeypress()" is faster than "getc()" and "doAction()" together, and that printscreen() is not taking too many cycles.
Depending on what doAction() does, the processor might not be able to respond to user key presses fast enough, skipping some of them (because a new one comes before the older is processed. I had that problem 15 years ago with a similar code).

All I can understand from your comments is that, since I had to take into consideration the max amount of time that i can take to do "doAction()", somehow I have a timer.

If i am still wrong, please show us very explicitely which timer are we using in this loop.

Re: Foobar event/push mode

Reply #36
All I can understand from your comments is that, since I had to take into consideration the max amount of time that i can take to do "doAction()", somehow I have a timer.

If i am still wrong, please show us very explicitely which timer are we using in this loop.

I am saying that you have configured an oscillator to generate an action within a prescribed time interval...this is, functionally, the description of what a timer is. 

From my point of view, it makes no difference if the oscillator is hooked up to some ALU and registers that count cycles and reset at intervals, or is connected to some different ALU and registers inside of a microprocessor that do the same thing.  Its still an oscillator counting time.  Therefore, algorithmically, you are describing a timer. 

Nothing else matters, not how you build it, not how fast it runs, not how much you like the implementation.  I don't care if its a wall clock, a crystal oscillator, a mode-locked fiber laser generating a frequency come, or a software program running on a microprocessor with an ALU and a register file.  If you are counting the passage of time within some prescribed tolerance, you have a timer.  If you have something that does not oscillate or for which the timing is truly random and unbounded, then you do not have a timer. 

If you want to make a push implementation that truly did not have a timer, you could do:

Code: [Select]
while (true)
{
for (int128_t i=0; i< randi(); i++)
{

}
push_audio_data();
}

But it would not work without constant drop outs because you must keep track of time to know how to size the buffer, and if you don't do that, you will underflow.  

Re: Foobar event/push mode

Reply #37
This is wrong.  If your loop cannot be guaranteed to poll on an interval less than the buffer refill time, it will not work.  Therefore time absolutely does matter. 
Sigh. I've actually explicitely pointed this out 3 times now, that if the system is too slow to do even just 1 cycle then it will run into buffer underruns regardless of event/push/whatever.
But your point is not only strawmanning, it's actually wrong. There do not need to be guarantees for it to work. You only need guarantees (like from a realtime OS) if you want to guarantee that there cannot be an underrun, ever, under any configuration.

So what you are saying is that your implementation must consider time... and is therefore a keeping time...like a timer.
No, what I am saying is exactly what I told you 4 times before. I will not further engage in what appears to be borderline trolling.

That loop is an oscillator that counts time.  Literally.  You are configuring a circuit in your PC to oscillate and so produce events on an interval with an upper bound (the duration of the audio buffer).  This is exactly what the hardware timers in your PC do BTW.
No, you're wrong again and also evaded my question. Here are more questions: what is the "configured upper bound" for the loop I've posted? Where is this configuration? Where is the counting? What is counted?

Hardware timers are something else. I really don't get why you'd still confuse the two after all these explanations.

Yes it is.  If you loop cannot meet those timing requirements, it will not work.
Copy/paste it is: No it's not necessary. Sigh. Go back and read again what I wrote. Your response here also misses the point.

You cannot simultaneously say that you do not need to measure time while also saying that you must meet some upper bound on timing.  It is one or the other.
We call this a false dichotomy.

Either time is bounded or it is not.  If it is bounded, then you have implemented a timer.  If it is truly unbounded, then you have not.
No, that's called a non sequitur.
Besides, you refute your own statement here. If it is truly unbounded, then I do not have implemented a timer, but if it is I have? LOL, nothing changes about the implementation in either case.
The implementation stays the same. It's not a timer in either case. I rest my case.
"I hear it when I see it."

Re: Foobar event/push mode

Reply #38
If you want to make a push implementation that truly did not have a timer, you could do:
[...]

Ok that was clear enough.
You describe a timer as a process that can be executed with a somewhat predictable latency. The randomness on your example loop makes it unpredictable, and then there is no guarantee that the action is done within some time constraints.

Now, Is this implementation a timerless one?  (wait time is not constant, because it depends on how many samples are still remaining in the previous buffer)

Quote
while(!exit) {
  int samplesRemaining = wasapi.getRemainingSamples();
  if ( samplesRemaining <= 0 ) {
   prepareNextBlockOn(wasapi.freeBlock);
  }
  else if (samplesRemaining > 32) {
    int millis = calcMillisFromRemaining(samplesRemaining/2);
   sleep(millis);
  }
}