W2k SDL_GetTicks() problem solved (patch included)!

Hi Sam, hi list,

I solved the problem with SDL_GetTicks() and Windows NT/2000
described in my mail “Strange problems with SDL_GetTicks() &
Windows2000” (Message-ID: <3B3FA21E.45CF9DF0 at mediaways.net>),
completely with a patch against SDL 1.2.1!

The credits must go to Matthijs Hollemans who provided me the
code for the WIN32 functions calling QueryPerformanceFrequency()
and QueryPerformanceCounter(), which replace the timeGetTime()
function used in the current implementation of SDL 1.2.1 that
only provides a precision of 10-15 ms for the current SDL_GetTicks()
function under Windows NT/2000.

Attached is a unified diff “SDL_systimer.c.diff” against the file
SDL-1.2.1/src/timer/win32/SDL_systimer.c.

TODO: Code to handle timer wrap-arounds like for timeGetTime().
(I prefer this case handled by the application, but YMMV.)

With this patch, I get a super-precise 1 ms accuracy of SDL_GetTicks()
on my Windows 2000 installation and the game “Rocks’n’Diamonds”,
where I got an accuracy of 15 ms before, resulting in a badly delayed
scrolling (which is fixed to 50 FPS using SDL_Delay/SDL_GetTicks).
Now it scrolls like a charm! :slight_smile:

The references from the MSDN follow. I give up all prejudice
against it – it’s great and provides lots of detailed information.
(Shame on me that I ever have to write this about M$ stuff. :wink: )

According to the MSDN information, the code with QueryPerformance*
functions should also work fine for the WindowsCE/PocketPC version
of SDL, which currently uses GetTickCount(). Someone with SDL on
WindowsCE/PocketPC available should definitely check this out!

Here are the MSDN references:-----------------------------
QueryPerformanceCounter (Windows 95/98/ME/NT/2000):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/hh/winui/timers_4z76.asp?frame=true

QueryPerformanceCounter (Windows CE):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceoem/htm/oal_f_62.asp

QueryPerformanceFrequency (Windows 95/98/ME/NT/2000):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/hh/winui/timers_6mk9.asp

QueryPerformanceFrequency (Windows CE):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdkr/htm/_wcesdk_win32_queryperformancefrequency.asp

High-Resolution Timer:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/hh/winui/timers_827m.asp

INFO: Timer Resolution in Windows NT and Windows 2000:
http://support.microsoft.com/support/kb/articles/Q115/2/32.asp

Best regards,
Holger

holger.schemel at mediaways.net
-------------- next part --------------
— SDL_systimer.c.orig Thu Apr 26 18:50:18 2001
+++ SDL_systimer.c Mon Jul 2 22:14:29 2001
@@ -39,28 +39,63 @@

#define TIME_WRAP_VALUE (~(DWORD)0)

-/* The first ticks value of the application /
+/
The first (low-resolution) ticks value of the application */
static DWORD start;

+#ifndef USE_GETTICKCOUNT
+/* Store if a high-resolution performance counter exists on the system /
+static BOOL hires_timer_available;
+/
The first high-resolution ticks value of the application /
+static LARGE_INTEGER hires_start_ticks;
+/
The number of ticks per second of the high-resolution performance counter /
+static LARGE_INTEGER hires_ticks_per_second;
+#endif
+
void SDL_StartTicks(void)
{
/
Set first ticks value */
#ifdef USE_GETTICKCOUNT
start = GetTickCount();
#else

  • start = timeGetTime();
  • if (QueryPerformanceFrequency(&hires_ticks_per_second) == TRUE)
  • {
  •   hires_timer_available = TRUE;
    
  •   QueryPerformanceCounter(&hires_start_ticks);
    
  • }
  • else
  • {
  •   hires_timer_available = FALSE;
    
  •   start = timeGetTime();
    
  • }
    #endif
    }

Uint32 SDL_GetTicks(void)
{
DWORD now, ticks;
+#ifndef USE_GETTICKCOUNT

  • LARGE_INTEGER hires_now;
    +#endif

#ifdef USE_GETTICKCOUNT
now = GetTickCount();
#else

  • now = timeGetTime();
  • if (hires_timer_available)
  • {
  •   QueryPerformanceCounter(&hires_now);
    
  •   hires_now.QuadPart -= hires_start_ticks.QuadPart;
    
  •   hires_now.QuadPart *= 1000;
    
  •   hires_now.QuadPart /= hires_ticks_per_second.QuadPart;
    
  •   return (DWORD)hires_now.QuadPart;
    
  • }
  • else
  • {
  •   now = timeGetTime();
    
  • }
    #endif
  • if ( now < start ) {
    ticks = (TIME_WRAP_VALUE-start) + now;
    } else {

It was a long ago we had discussion about SDL timer
precision here. I told there was performance counter
in win32, and I had code for that, and I wasn’t the
only one who did so. Still, the higher precision timer
(implementation) wasn’t included in SDL. Several versions
passed.

With this patch, I get a super-precise 1 ms accuracy of SDL_GetTicks()
on my Windows 2000 installation and the game “Rocks’n’Diamonds”,
where I got an accuracy of 15 ms before, resulting in a badly delayed

Yeah. But since they didn’t like to add better precision
back then, what would make you think they would like this,
essentially same thing, now later?

I know and you know, they should add the better timer, but
they just insisted that the existing timer was precise
enough, even though some people clearly experienced and
expressed otherwise.

– Timo Suoranta – @Timo_K_Suoranta

It was a long ago we had discussion about SDL timer
precision here. I told there was performance counter
in win32, and I had code for that, and I wasn’t the
only one who did so. Still, the higher precision timer
(implementation) wasn’t included in SDL. Several versions
passed.

At that time it was not made clear that the current implementation of
SDL_GetTicks() on win32 might not always give 1 ms accuracy. Instead
there was a lot of nonsense about “SDL needs a gettime API with higher
precision than 1 ms” and the like. (The answer is still No as far as I
am concerned; I have yet to see an informed argument for it and each
time someone claims there being a need, it turns out to be a
misunderstanding)

Holger has found a bug and as a bug it should be fixed

It was a long ago we had discussion about SDL timer
precision here. I told there was performance counter
in win32, and I had code for that, and I wasn’t the
only one who did so. Still, the higher precision timer
(implementation) wasn’t included in SDL. Several versions
passed.

With this patch, I get a super-precise 1 ms accuracy of
SDL_GetTicks()
on my Windows 2000 installation and the game “Rocks’n’Diamonds”,
where I got an accuracy of 15 ms before, resulting in a
badly delayed

Yeah. But since they didn’t like to add better precision
back then, what would make you think they would like this,
essentially same thing, now later?

I know and you know, they should add the better timer, but
they just insisted that the existing timer was precise
enough, even though some people clearly experienced and
expressed otherwise.

– Timo Suoranta – tksuoran at cc.helsinki.fi

Is this true? Can anyone of the SDL dev team comment on this? I also had to
add ‘PerformanceCounter’ timing to my program because of the lack of
precision of SDL_GetTicks(). My OpenGL program really suffered from this.
The movement in my program is updated based on time elapsed since the last
frame, trying to to this with SDL_GetTicks() made everything very 'choppy’
in windows 2000. So I had to choose for a non-portable solution
(PerformanceCounter). This is somewhat against the SDL philosophy, no?

Dominique Biesmans> -----Original Message-----

From: Timo K Suoranta [mailto:tksuoran at cc.helsinki.fi]

Hello Timo,

It was a long ago we had discussion about SDL timer
precision here. I told there was performance counter

Hm, I must have missed that discussion. I searched the whole
SDL mailing list before posting my initial mail about that topic
two days ago.

With this patch, I get a super-precise 1 ms accuracy of SDL_GetTicks()
on my Windows 2000 installation and the game “Rocks’n’Diamonds”,
where I got an accuracy of 15 ms before, resulting in a badly delayed

Yeah. But since they didn’t like to add better precision
back then, what would make you think they would like this,
essentially same thing, now later?

I know and you know, they should add the better timer, but
they just insisted that the existing timer was precise
enough, even though some people clearly experienced and
expressed otherwise.

I don’t think so, because:

In <200107021343.PAA16062 at my.nada.kth.se>, Mattias Engdeg?rd wrote:

using timeBeginPeriod and timeEndPeriod. Use the QueryPerformanceCounter
and QueryPerformanceFrequency functions to measure short time intervals
at a high resolution.

We would definitely appreciate a patch for this — there is no reason
SDL_GetTicks() should settle for worse than 1 ms accuracy on platforms
where it is at all possible. If possible, select the best method
during runtime, so that the same binary will work on any Windows variant

My patch for SDL_GetTicks() does exactly what Mattias suggested:
Check at runtime if the high-resolution ounter is available, and if so,
use it! It is available on Win95/98/ME/NT/2000/CE, that means, virtually
on any WIN32 platform, so the patch could in fact replace the current
implementation. But I choose the conservative method of using it only
if the system says that it is really available.

[again Mattias Engdeg?rd:]

you should be able to rely on SDL_GetTicks() to give the best resolution
possible on the platform (which usually means 1 ms), and on SDL_Delay to
have no worse granularity than allowed by the OS scheduler/timers (usually
10 ms)

With current SDL-1.2.1, you can not rely on SDL_GetTicks() giving you
the best resolution possible on the Windows NT/2000 platform (10-15 ms
instead of the usual 1 ms).

With my patch, you can.

So I really do not see why the SDL maintainers should refuse to have
a look at my patch, test it, and incorporate it into the next release
of SDL if it passes the usual reliability tests.

Best regards,
Holger–
holger.schemel at mediaways.net … ++49 +5246 80 1438

Hello Timo,

It was a long ago we had discussion about SDL timer
precision here. I told there was performance counter

Hm, I must have missed that discussion. I searched the whole
SDL mailing list before posting my initial mail about that topic
two days ago.

With this patch, I get a super-precise 1 ms accuracy of SDL_GetTicks()
on my Windows 2000 installation and the game “Rocks’n’Diamonds”,
where I got an accuracy of 15 ms before, resulting in a badly delayed

Yeah. But since they didn’t like to add better precision
back then, what would make you think they would like this,
essentially same thing, now later?

I know and you know, they should add the better timer, but
they just insisted that the existing timer was precise
enough, even though some people clearly experienced and
expressed otherwise.

I don’t think so, because:

In <200107021343.PAA16062 at my.nada.kth.se>, Mattias Engdeg?rd wrote:

using timeBeginPeriod and timeEndPeriod. Use the QueryPerformanceCounter
and QueryPerformanceFrequency functions to measure short time intervals
at a high resolution.

We would definitely appreciate a patch for this — there is no reason
SDL_GetTicks() should settle for worse than 1 ms accuracy on platforms
where it is at all possible. If possible, select the best method
during runtime, so that the same binary will work on any Windows variant

My patch for SDL_GetTicks() does exactly what Mattias suggested:
Check at runtime if the high-resolution ounter is available, and if so,
use it! It is available on Win95/98/ME/NT/2000/CE, that means, virtually
on any WIN32 platform, so the patch could in fact replace the current
implementation. But I choose the conservative method of using it only
if the system says that it is really available.

[again Mattias Engdeg?rd:]

you should be able to rely on SDL_GetTicks() to give the best resolution
possible on the platform (which usually means 1 ms), and on SDL_Delay to
have no worse granularity than allowed by the OS scheduler/timers (usually
10 ms)

With current SDL-1.2.1, you can not rely on SDL_GetTicks() giving you
the best resolution possible on the Windows NT/2000 platform (10-15 ms
instead of the usual 1 ms).

With my patch, you can.

So I really do not see why the SDL maintainers should refuse to have
a look at my patch, test it, and incorporate it into the next release
of SDL if it passes the usual reliability tests.

Best regards,
Holger–
holger.schemel at mediaways.net … ++49 +5246 80 1438

Yeah. But since they didn’t like to add better precision
back then, what would make you think they would like this,
essentially same thing, now later?

I know and you know, they should add the better timer, but
they just insisted that the existing timer was precise
enough, even though some people clearly experienced and
expressed otherwise.

– Timo Suoranta – tksuoran at cc.helsinki.fi

Perhaps it is better to still use “timeGetTime” but with
"timeBeginPeriod" set to 1ms in “SDL_init” and
"timeEndPeriod" set to 1ms in “SDL_close”.–

Xavier Le Pasteur
@Xavier_Le_Pasteur

I solved the problem with SDL_GetTicks() and Windows NT/2000
described in my mail “Strange problems with SDL_GetTicks() &
Windows2000” (Message-ID: <3B3FA21E.45CF9DF0 at mediaways.net>),
completely with a patch against SDL 1.2.1!

The credits must go to Matthijs Hollemans who provided me the
code for the WIN32 functions calling QueryPerformanceFrequency()
and QueryPerformanceCounter(), which replace the timeGetTime()
function used in the current implementation of SDL 1.2.1 that
only provides a precision of 10-15 ms for the current SDL_GetTicks()
function under Windows NT/2000.

Attached is a unified diff “SDL_systimer.c.diff” against the file
SDL-1.2.1/src/timer/win32/SDL_systimer.c.

Looks good Holger, thank you very much! :slight_smile:

See ya,> TODO -Sam Lantinga, Lead Programmer, Loki Software, Inc.

My patch for SDL_GetTicks() does exactly what Mattias suggested:
Check at runtime if the high-resolution ounter is available, and if so,
use it! It is available on Win95/98/ME/NT/2000/CE, that means, virtually
on any WIN32 platform, so the patch could in fact replace the current
implementation. But I choose the conservative method of using it only
if the system says that it is really available.

It’s available for virtually every win32 platform, but not on every processor
(486?), so the fallback is needed.

Florian–
Florian ‘Proff’ Schulze - @Florian_Schulze
Homepage: - http://proff.fly.to
PGP-Key available from - http://www.keyserver.net/en/

Hi,

I recently thought about using the TimeStampCounter for accurate timing
myself and decided against it:
It assumes that the frequency of the processor is constant. But the
modern mobile processors vary their frequency according to system load.
And the P4 has a way to reduce its frequency if it’s getting too hot.

I don’t know if the Win32 functions have a way to compensate this. The
MSDN reference claims “The frequency cannot change while the system is
running”, but I think this is simply incorrect with todays CPUs.

Any clock powered by the TimeStampCounter will severly drift. For some
timing tasks that may be ok, for others (such as mine) it is fatal.

I didn’t have a way to verify this thesis, because I don’t have such a
notebook CPU. But it sounds plausible, doesn’t it :slight_smile:

Bye,
Martin

Hi Xavier,

[more precise SDL_GetTicks() using QueryPerformanceCounter()]

Perhaps it is better to still use “timeGetTime” but with
"timeBeginPeriod" set to 1ms in “SDL_init” and
"timeEndPeriod" set to 1ms in “SDL_close”.

Can you explain why this might be better or which advantages
this might have?

I also thought about using “timeBeginPeriod/timeEndPeriod”, but
I found more information about the "QueryPerformanceCounter"
related functions in the MSDN (which are explicitely recommended
there for high-precision timing), so I started with that approach.

After it worked great using these functions, I skipped doing
further research with the time*Period functions…

Best regards,
Holger–
holger.schemel at mediaways.net … ++49 +5246 80 1438

Holger Schemel wrote:
[…]

Oops, that mail went out twice accidentally – sorry!

Best regards,
Holger–
holger.schemel at mediaways.net … ++49 +5246 80 1438

Hi Xavier,

[more precise SDL_GetTicks() using QueryPerformanceCounter()]

Perhaps it is better to still use “timeGetTime” but with
"timeBeginPeriod" set to 1ms in “SDL_init” and
"timeEndPeriod" set to 1ms in “SDL_close”.

Can you explain why this might be better or which advantages
this might have?

I also thought about using “timeBeginPeriod/timeEndPeriod”, but
I found more information about the "QueryPerformanceCounter"
related functions in the MSDN (which are explicitely recommended
there for high-precision timing), so I started with that approach.

After it worked great using these functions, I skipped doing
further research with the time*Period functions…

Best regards,
Holger

holger.schemel at mediaways.net … ++49 +5246 80 1438

Hi Roger !

First, thank you very much for providing a patch so soon for this
major problem.

The problem with Performance Counters is that there are not always
available (generally it is CPU dependent, we should test for their
availability with both AMD & Intel processors).

“timeBeginPeriod/timeEndPeriod”, however, are just functions configuring
the behaviour of the “timeGetTime” function (if I have well understood
the MSDN docs).

Theses functions are always available but may not deliver the requested
timer granularity. But since the timer granularity of 1ms is the default
value
for windows 95/98, I “guess” this value would “always” be accepted by
"timeBeginPeriod".

Another advantage: we would have the same timer granularity as windows
95/98 and linux (nor better, nor worse).

So, I think that the ultimate timing procedure for win32 would be:

  • check for performance counter availability:
    • if they are available use them.
    • if not:
      • search and set with “timeBeginPeriod” the lowest accepted timing
        granularity that is superior to 1ms (or another constant value).
      • use “timeGetTime”
      • restore old timing granularity with “timeEndPeriod” when SDL is
        not used any more.–

Xavier Le Pasteur
@Xavier_Le_Pasteur

Right; only a few (non-intel) 486 class CPUs have a TSC equivalent, so don’t
count on it unless the minimum spec is Pentium.

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Tuesday 03 July 2001 11:19, Florian ‘Proff’ Schulze wrote:

My patch for SDL_GetTicks() does exactly what Mattias suggested:
Check at runtime if the high-resolution ounter is available, and if so,
use it! It is available on Win95/98/ME/NT/2000/CE, that means, virtually
on any WIN32 platform, so the patch could in fact replace the current
implementation. But I choose the conservative method of using it only
if the system says that it is really available.

It’s available for virtually every win32 platform, but not on every
processor (486?), so the fallback is needed.

Hi,

I recently thought about using the TimeStampCounter for accurate timing
myself and decided against it:
It assumes that the frequency of the processor is constant. But the
modern mobile processors vary their frequency according to system load.
And the P4 has a way to reduce its frequency if it’s getting too hot.

Indeed, on some platforms this may well be implemented outside the CPU,
which would mean that the TSC clock channges as well. (It’s a 64 bit counter
connected to the CPU core clock.) However…

I don’t know if the Win32 functions have a way to compensate this. The
MSDN reference claims “The frequency cannot change while the system is
running”, but I think this is simply incorrect with todays CPUs.

…if Win32 doesn’t keep track of the current CPU clock at all time (if this
is needed, that is), the TSC function is broken and shold be fixed!

Any clock powered by the TimeStampCounter will severly drift. For some
timing tasks that may be ok, for others (such as mine) it is fatal.

Well, yes, unless the OS checks the CPU clock against the RTC at startup, the
TSC will most likely drift a great deal more than the RTC. However, you
should expect these “multimedia timer” things to drift some. In fact, you
shouldn’t even rely on the RTCs of two computers to stay in sync for extended
periods of time.

That said, if you write your networking code properly, this shouldn’t be an
issue. If it is, then the TSC code in Win32 is broken.

I didn’t have a way to verify this thesis, because I don’t have such a
notebook CPU. But it sounds plausible, doesn’t it :slight_smile:

Yes. At least pre P4 mainboards change the CPU clock in the chipset. This
"SpeedStep" thing, however, might do the clock scaling in the chip, which
could mean that it doesn’t affect the TSC.

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Tuesday 03 July 2001 13:05, Martin Bickel wrote:

Best regards,
Holger

holger.schemel at mediaways.net … ++49 +5246 80 1438

Hi Roger !

Sorry it’s Holger !!!
:wink:
(should have read my post one more time before sending it !)–

Xavier Le Pasteur
@Xavier_Le_Pasteur

Hmm… No advantages, except that it works on any CPU. (Proveded Win2k
implements it correctly, that is!)

Disadvantage: It relies on a periodic (IRQ style) timer (at least it used to,
according to some API docs), so lowering the period value increases overhead.

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Tuesday 03 July 2001 13:37, Holger Schemel wrote:

Hi Xavier,

[more precise SDL_GetTicks() using QueryPerformanceCounter()]

Perhaps it is better to still use “timeGetTime” but with
"timeBeginPeriod" set to 1ms in “SDL_init” and
"timeEndPeriod" set to 1ms in “SDL_close”.

Can you explain why this might be better or which advantages
this might have?

Hi Martin,

I recently thought about using the TimeStampCounter for accurate timing
myself and decided against it:
It assumes that the frequency of the processor is constant. But the
modern mobile processors vary their frequency according to system load.
And the P4 has a way to reduce its frequency if it’s getting too hot.

I don’t know if the Win32 functions have a way to compensate this. The
MSDN reference claims “The frequency cannot change while the system is
running”, but I think this is simply incorrect with todays CPUs.

As I understand the MSDN here, it states that the frequency value
you get from “QueryPerformanceFrequency()” does not change while
the system is running. This frequency value is not necessarily
identical to the CPU frequency, so the question is in what way it
might be affected when CPU frequency changes. Then, such a drift
can also be adjusted by the function QueryPerformanceCounter – the
effective counter value is always combined by the frequency value
(which you get once) and the counter value (which you get for each
query).

But maybe someone with such a CPU should just check this.

Any clock powered by the TimeStampCounter will severly drift. For some
timing tasks that may be ok, for others (such as mine) it is fatal.

Another solution would be to just offer two functions:
One to provide a clock precise ticks value with a potential low
resolution, one to provide a high-resolution ticks value for short,
but precise busy-waiting purposes (which might drift when CPU slows
down).

I didn’t have a way to verify this thesis, because I don’t have such a
notebook CPU. But it sounds plausible, doesn’t it :slight_smile:

Maybe you’re right. Maybe this problem could be handled by using
the timeBeginPeriod/timeEndPeriod functions (if they’re not affected
by CPU slowdowns, too).

Best regards,
Holger–
holger.schemel at mediaways.net … ++49 +5246 80 1438

[…]

I didn’t have a way to verify this thesis, because I don’t have such a
notebook CPU. But it sounds plausible, doesn’t it :slight_smile:

Maybe you’re right. Maybe this problem could be handled by using
the timeBeginPeriod/timeEndPeriod functions (if they’re not affected
by CPU slowdowns, too).

They shouldn’t be, as they rely on one of the mainboard chipset timers as an
interrupt source. (It has to be done that way, as these timers can also used
as time base for threads or callbacks. The TSC cannot generate IRQs.)

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Tuesday 03 July 2001 14:08, Holger Schemel wrote:

“timeBeginPeriod/timeEndPeriod”, however, are just functions configuring
the behaviour of the “timeGetTime” function (if I have well understood
the MSDN docs).

Does anyone know where timeBeginPeriod() and timeEndPeriod() affect
timeGetTime() on an application-wide scale, or on a system-wide scale? In
other words, if your app calls timeBeginPeriod(), will it change the timing
resolution of other applications? If it does, then any other application
could change your application’s timing resolution, which is probably not
what you want…

Matthijs

Visit my page @ www.shakeyourass.org
Listen to my music @ www.mp3.com/mothergoose
Buzz with the Bees @ www.virtualunlimited.com