Jump to content

[VMware] Ensoniq AudioPCI driver for Leopard v1.0.1


65 posts in this topic

Recommended Posts

I've reconstructed sources for Maxxuss' legendary ES137x audio driver. It can be used for sound support when running OS X Leopard as a VMware guest.

 

I had 2 goals in reconstructing the driver

  • Fix the choppy sound I was getting with Maxxuss' driver and an old build of AppleAC97Audio.
  • Make sources available for this driver so it can be rebuilt for future OS X updates.

 

Three packages are attached below

  • AppleAC97Audio.kext.tar.gz contains a full current rebuild of AppleAC97Audio. The new ES137x driver is called EnsoniqAudioPCI.kext and can be found under Plugins. If you want to try this driver with your existing build of AppleAC97Audio, you can pluck it from there and install it as a plugin.
  • AppleAC97Audio-5.tar.gz contains updated sources for building AppleAC97Audio including an xCode 3.1 project file.
  • EnsoniqAudioPCI_Src.tar.gz contains the sources for the ES137x driver.

 

As for the choppy sound issue - The newly rebuilt driver (including AppleAC97Audio) is giving me much smoother sound than the driver I had installed. I can't quite figure out why, since in theory the driver is functionally the same. Apple's audio architecture is designed on having the low-level driver implement a DMA ring buffer and deliver interrupt notifications whenever the ring buffer wraps around. The high-level audio layers use a complex timing scheme to estimate the drain rate of the buffer and keep it filled in order to provide continuous audio. In a virtual machine, this timing scheme can get derailed due to inaccuracies in the guest's emulated timing and interrupt delivery mechanisms.

If you play audio in the guest, you should keep the VM window as the foreground window in order to give the VM threads highest priority.

The sound is still not quite as good as playing directly on the host, but this may be due in part to HD audio sound effects available in the host driver.

 

Edit [8/20/2009]: Uploaded version 1.0.1 - see post #8.

Edit [8/20/2009]: I added an installer (EnsoniqAudioPCI.mpkg.tar.gz). There are two installation options - either install the full AppleAC97Audio.kext, or EnsoniqAudioPCI.kext as a plugin to an existing AppleAC97Audio.kext.

 

Credits:

  • Primarily a reconstruction of MaxxussAC97AudioES137x.kext.
  • Maxxuss' driver is a hybrid of existing Apple AC97 drivers for other chipsets and the es137x driver in the FreeBSD source tree. I took much of the source code from these sources directly instead of decompiling.
  • The FreeBSD driver is based on an older Linux driver.

 

Edit: (11/8/2009) Attachments removed. See this page for the most recent version.

 

Previous Download Counts:

  • AppleAC97Audio.kext.tar.gz 194
  • AppleAC97Audio-5.tar.gz 126
  • EnsoniqAudioPCI_Src.tar.gz 80
  • EnsoniqAudioPCI.mkpg.tar.gz 306

Link to comment
Share on other sites

Excellent! Would you mind if I include on the boot image used in VMware in this thread Also the SVGA driver?
Yes, sure, use any of the drivers I posted anyway you like.

 

Also sound can be tweaked by adding these settings to the VMX file:

 

sound.highPriority = "TRUE"

pciSoundDAC1InterruptsPerSec = 0

pciSoundDAC2InterruptsPerSec = 0

Thanks, I'll try and see if they help. The posted driver (as well as Maxxuss' driver) only uses DAC2. AppleAC97Audio doesn't support more than one output engine per AC97 codec too well, and I'm not sure the two DACs can be set up to simulate 4-channel audio.
Link to comment
Share on other sites

Yes, sure, use any of the drivers I posted anyway you like.

 

Thanks, I'll try and see if they help. The posted driver (as well as Maxxuss' driver) only uses DAC2. AppleAC97Audio doesn't support more than one output engine per AC97 codec too well, and I'm not sure the two DACs can be set up to simulate 4-channel audio.

 

Yes there are a fair few settings for hacking the sound. I tried your driver with a QT movie. The following 2 settings seemed to improve the experience:

 

pciSound.priorityBoost = "TRUE"

pciSound.DAC2InterruptsPerSec = "16"

Link to comment
Share on other sites

I'm getting an error when I try to download these: "Sorry, some required files are missing, if you intended to view a topic, it's possible that it's been moved or deleted. Please go back and try again."

 

Are they still available somewhere?

 

Donk, is this driver already included in your vmware-darwin package, or is that the old maxxus version?

Link to comment
Share on other sites

I'm getting an error when I try to download these: "Sorry, some required files are missing, if you intended to view a topic, it's possible that it's been moved or deleted. Please go back and try again."

 

Are they still available somewhere?

 

Donk, is this driver already included in your vmware-darwin package, or is that the old maxxus version?

 

Old Maxxuss version. I will include this one in the next update.

Link to comment
Share on other sites

I eventually did get this to download, and tried it out last night....

 

FWIW, I didn't see any improvement over the maxxuss driver. I tried a pretty much infinite variety of values for pciSoundDAC2InterruptsPerSec, but none helped - low values result in intelligible, but extremely stuttery audio - higher values resulted in heavily distored (to the point of uninteligiblity) output.

 

Are there any other variable I could try tweaking?

 

Out of curiosity, when you guys say you were able to get acceptable quality sound out of this driver, how are you definining "acceptable"? Are you getting occasional stuttering, just not as frequently as before? Or none at all?

 

Just wondering whether I'm an outlier.....

Link to comment
Share on other sites

  • 3 weeks later...

After much trial & error, I've figured out the reason for the choppy audio, and came up with a solution which appears to work. I've uploaded the new version and attached to the original post.

 

  1. Bumped version number for EnsoniqAudioPCI.kext from 1.0.0 to 1.0.1.
  2. Remove the old kext and install this one in its place.
  3. Remove any setting of "pciSound.DAC2InterruptsPerSec" from your vmx file.

 

I've also modified AppleAC97Audio.kext so that it can drive the chip at a 44.1KHz sample rate. Previously it was limited to driving the chip at 48KHz. This isn't critical, since both sample rates appear to work just fine. You can still use EnsoniqAudioPCI.kext with an existing AppleAC97Audio.kext.

Link to comment
Share on other sites

After much trial & error, I've figured out the reason for the choppy audio, and came up with a solution which appears to work. I've uploaded the new version and attached to the original post.

 

  1. Bumped version number for EnsoniqAudioPCI.kext from 1.0.0 to 1.0.1.
  2. Remove the old kext and install this one in its place.
  3. Remove any setting of "pciSound.DAC2InterruptsPerSec" from your vmx file.

 

I've also modified AppleAC97Audio.kext so that it can drive the chip at a 44.1KHz sample rate. Previously it was limited to driving the chip at 48KHz. This isn't critical, since both sample rates appear to work just fine. You can still use EnsoniqAudioPCI.kext with an existing AppleAC97Audio.kext.

 

Excellent news! Unfortunately won't be able to try until next week.

Link to comment
Share on other sites

After much trial & error, I've figured out the reason for the choppy audio, and came up with a solution which appears to work. I've uploaded the new version and attached to the original post.

 

  1. Bumped version number for EnsoniqAudioPCI.kext from 1.0.0 to 1.0.1.
  2. Remove the old kext and install this one in its place.
  3. Remove any setting of "pciSound.DAC2InterruptsPerSec" from your vmx file.

 

I've also modified AppleAC97Audio.kext so that it can drive the chip at a 44.1KHz sample rate. Previously it was limited to driving the chip at 48KHz. This isn't critical, since both sample rates appear to work just fine. You can still use EnsoniqAudioPCI.kext with an existing AppleAC97Audio.kext.

 

installed on 10.5.8 and works beautifully. Incredible work Zenith! I did not make any changes to my vmx file and it works right out of the box! Cheers to you!

Link to comment
Share on other sites

I used the installer inside a virtual machine using Donk's template, which works great by the way Donk, but I'm still getting minor stuttering and occasional popping. Has anyone else heard popping?

 

That's the original Maxxuss driver. Use Zenith's to get better sound.

Link to comment
Share on other sites

That's the original Maxxuss driver. Use Zenith's to get better sound.

 

I confirmed I'm using Zenith's 1.0.1 Ensoniq driver

 

Zenith, with your new Ensoniq driver, should I use the following options, or leave them alone?

 

sound.highPriority = "TRUE"

pciSound.priorityBoost = "TRUE"

Link to comment
Share on other sites

I confirmed I'm using Zenith's 1.0.1 Ensoniq driver

 

Zenith, with your new Ensoniq driver, should I use the following options, or leave them alone?

 

sound.highPriority = "TRUE"

pciSound.priorityBoost = "TRUE"

 

I took them out and it works fine.

Link to comment
Share on other sites

I used the installer inside a virtual machine using Donk's template, which works great by the way Donk, but I'm still getting minor stuttering and occasional popping. Has anyone else heard popping?

 

Yeah i also still get slight stuttering but it is way better than it was. Thanks Zenith!

Link to comment
Share on other sites

  • 2 weeks later...
Yeah i also still get slight stuttering but it is way better than it was. Thanks Zenith!

 

Yes, it is 98% perfekt. Is it known what causes the imperfections in quality?

 

Thanks again for posting your work, and I hope there is an update coming soon ;-)

Link to comment
Share on other sites

Thanks for the quick reply. Yes, I'd (and maybe others too) like to hear the long answer.
IOAudioEngine expects the chip driver to maintain a DMA ring buffer from which samples are fed to the playback channel. The driver today uses a 128KB buffer, which is enough for about 680 milliseconds using a 48KHz sample rate. The chip driver is expected to provide the following functions
  • report an interrupt every time the buffer wraps around.
  • report an accurate position of the DMA transfer pointer whenever IOAudioEngine asks for it.

IOAudioEngine maintains a software "erase head". It sets up a timer to trigger 4 times per buffer at regular intervals. The timer routine asks the chip driver for the position of the DMA pointer. It then runs an "erase head" that erases the buffer from the position of the last erasure to the current position of the DMA pointer. "Erasure" here means that it marks the part of the buffer that's already been played as empty, and also erases that part of the buffer to zero. The reason it needs to erase the buffer to zero is because IOAudioEngine supports software mixing - multiple user-clients can be active at the same time and come in and add their samples to the buffer.

IOAudioEngine reports three parameters to the user-clients via shared memory

  • The number of times the buffer has wrapped around since playback started.
  • A timestamp of the last time the buffer wrapped around (based on mach_absolute_time() - this is a nanosecond counter based on the TSC).
  • The last position of the erase head.

The user-clients are expected to time themselves based on these three parameters in such a way that they always stay ahead of the playback device and fill the buffer in advance to maintain continuous audio.

 

The ES137x chipset supports both needed features - generating interrupts and reporting a DMA pointer.

And now for the reason this doesn't work.... [are you ready?]

 

VMware doesn't emulate the ES137x's DMA pointer

 

I suspect the reason they don't is because they can't. They probably pass the buffer on to the host's audio driver and tell it how many samples to play. They can't tell where the DMA pointer is exacly, but they can generate interrupts in the guest whenever the sample counter completes. So what they do instead is

  • When the channel is off, the DMA pointer is always reported as zero.
  • When the channel is on, they report the last known value for the pointer when an interrupt fires. This value stays the same until the next interrupt or until the channel is turned off.

Fortunately, it's possible to compensate for this somewhat by increasing the number of interrupts per buffer. I've set the number of interrupts to two, so the system functions a little bit like a double-buffering system. The driver reports every half-buffer that the previous half-buffer is done via the DMA pointer, but only sends an interrupt notification up the stack when the whole buffer wraps around as the user-clients expect.

The first version (1.0.0) used a 64K buffer, the DMA pointer always stayed at zero. This means the erase head never got run, and the user-clients had no advance notification that any part of the buffer has already been played and can be refilled.

It's possible to increase the number of interrupts per buffer from the host with "pciSound.DAC2InterruptPerSec". For version 1.0.0, this caused the driver to report every interrupt up the stack, which isn't what the user-clients expect. The current version 1.0.1 always reports one interrupt per buffer up the stack, but multiple interrupt per buffer will cause the DMA pointer to have a correct value at a higher frequency per buffer. In theory, higher values of the number of interrupts per buffer should make the driver resemble an accurate DMA pointer more closely, but for some reason I can't figure out this doesn't work. If I increase the number of interrupt per buffer from 2 to 4, 8 or 16 things start getting worse.

There are still some other things that can be tried

  • Even at multiple interrupts per buffer, IOAudioEngine always runs its erase head 4 times per buffer. This means there can be a delay of up to a quarter-buffer between the time the interrupt is fired and the time IOAudioEngine performs the erasure. This means that the time window the user-clients have for detecting the erasure after an interrupt can be reduced down from half a buffer to as little as about a quarter of a buffer. One thing that can be done is to try to browbeat IOAudioEngine into running its erase-head "immediately" after an interrupt instead of on a timer. Due to the way AppleAC97Audio is designed, this requires some non-trivial redesigning of the code, or some ugly hacks. Accomplishing this can make sure that user-clients have about a half-buffer of advance notice to fill the buffer.
  • IOAudioEngine and IOAudioEngineUserClient have functions for helping the user-clients do their timing performClientOutput and calculateSampleTimeout. I haven't taken a good look at those. There might be a way to help prod the user-client into refilling the buffer sooner.

This analysis is based on the assumption that the guest OS can monopolize a processor core and run in real-time without yielding. Things get worse if it has to yield.

Ultimately the stuttering is caused by user-clients falling behind when filling the buffer. The duration of an audio sample is about 20 microseconds. Since the CPU/RAM system is about 4 orders of magnitude faster than that, once the user-client gets some CPU time, it quickly makes up the lag. That's why these imperfections sound the way they do - short and random. The goal is to get the user-client not to fall behind at all.

There's another issue - I'm testing the driver on a dual-core with hardware virtualization, and I'm not really hearing any stuttering at all anymore. I suspect people still hearing it are using software virtualization - although I can't be sure. The problem is that in order to test if modifications I make are helping, I need a machine that can reliably reproduce the problem, and I don't have one.

Link to comment
Share on other sites

There's another issue - I'm testing the driver on a dual-core with hardware virtualization, and I'm not really hearing any stuttering at all anymore. I suspect people still hearing it are using software virtualization - although I can't be sure. The problem is that in order to test if modifications I make are helping, I need a machine that can reliably reproduce the problem, and I don't have one.

Zenith, thanks for your detailed answer. I tried to find a setting for hardware virtualization in vmware. How do I know it's using this? I know my i7 920 is set for hardware virtualization, but does vmware use it?

Link to comment
Share on other sites

I tried to find a setting for hardware virtualization in vmware. How do I know it's using this? I know my i7 920 is set for hardware virtualization, but does vmware use it?

You need to make sure it's on in the BIOS -- boot and run BIOS setup. Look in the menus for "VT" or virtualization and make sure it's enabled (it might already be). You need to cycle the power after changing this setting.

The setting in VMware for the VM is in Devices->Processors->Execution Mode, "Preferred Mode" should be set to "Automatic".

Link to comment
Share on other sites

You need to make sure it's on in the BIOS -- boot and run BIOS setup. Look in the menus for "VT" or virtualization and make sure it's enabled (it might already be). You need to cycle the power after changing this setting.

The setting in VMware for the VM is in Devices->Processors->Execution Mode, "Preferred Mode" should be set to "Automatic".

 

 

I'm pretty sure that this is a requirement for Donk's guest package, I can't speak for any other way of running Osx in Vmware

Link to comment
Share on other sites

You need to make sure it's on in the BIOS -- boot and run BIOS setup. Look in the menus for "VT" or virtualization and make sure it's enabled (it might already be). You need to cycle the power after changing this setting.

The setting in VMware for the VM is in Devices->Processors->Execution Mode, "Preferred Mode" should be set to "Automatic".

ok, just wanted to make sure I'm not missing anything. Everything you listed is good on my system. Thanks for helping.

 

btw. I have a really hard time to notice problems. On my system they sound like small scratches on a vinyl.

Link to comment
Share on other sites

 Share

×
×
  • Create New...