VOGONS


Reply 20 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

It seems that no matter what cycle count I set (0-4000000 cycles), the credits of 8088MPH won't give any sound (Windows volume mixer does say it's going full volume though). It works fine during normal playback (square wave)?

Edit: It now generates sound with the Dosbox-style 1-cycle counting used every instruction, but it's still a quite garbled (the beat is noticable though). Is there still a problem in my PC speaker emulation?

PIT: https://bitbucket.org/superfury/x86emu/src/06 … pit.c?at=master
CPU core: https://bitbucket.org/superfury/x86emu/src/06 … cpu.c?at=master
Emulator core with CPU cycle slowdown: https://bitbucket.org/superfury/x86emu/src/06 … ore.c?at=master

Last edited by superfury on 2016-01-14, 08:53. Edited 1 time in total.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 21 of 57, by Scali

User metadata
Rank l33t
Rank
l33t

Well, if your PIT emulation and downsampling work correctly, you should just get a regular PCM stream as output.
I think you have to take it one step at a time...
How about converting a .WAV file with PCM data to a 1.19 MHz PWM stream first, and then convert it back, to see if it works?
You can make a simple PWM player for it for DOS/PC speaker (just set up a timer interrupt at your replay speed, and fire one PWM value to the one-shot counter at every interrupt), so you can test it on real hardware and emulators with known PWM emulation such as DOSBox.

Once you have verified that your PWM->PCM part works as expected, the problem must be in the PIT emulation. So I would suggest capturing the PWM buffer to a file, so you can study the output and see why it doesn't work like the PCM output you were expecting.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 22 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

I read the OSDev wiki again:

How It Works
The PC Speaker takes approximately 60 millionths of a second to change positions. This means that if the position of the speaker is changed from "in" to "out" and then changed back in less than 60 milliseconds, the speaker did not have enough time to fully reach the "out" position. By precisely adjusting the amount of time that the speaker is left "out", the speaker's position can be set to anywhere between "in" and "out", allowing the speaker to form more complex sounds.

So this would mean that the speaker only moves a fraction during an outputted 1 or 0 from the PIT. So if I would convert the 1s and 0s from the pit to relative movement to 0 or 1, it would be accurate speaker emulation? So process the stream and make each 1 or 0 pull the resulting 1.19Mhz down to 0 or push up until 1 at a constant rate((1/1190000)/(60/1000000) for each 0 or 1)? Then simply get the output stream by skipping the samples instead of averaging it(1.19 MHz to 44.1kHz conversion)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 23 of 57, by Scali

User metadata
Rank l33t
Rank
l33t
superfury wrote:

So this would mean that the speaker only moves a fraction during an outputted 1 or 0 from the PIT.

Yes, but you should see it as a square-wave, because you don't toggle 1s and 0s all the time... It is 1 during the countdown, and flips to 0 when the counter reaches 0.
It might be easier to look at this explanation: https://en.wikipedia.org/wiki/Pulse-width_modulation

I don't think you actually need to model the speaker or anything (besides, there are thousands of different types of speakers used, which have different properties, and PWM 'just works' on all of them, so I don't think physical modeling of a speaker is the answer. It's ).

You should just see it as an average over time.

PWM is also used in power supplies for example... By switching a fixed voltage on and off at a certain rate, you get a lower voltage on average. In PSUs you will generally use capacitors to filter the pulsed voltage down to a steady level.
In this case the inertia of the speaker cone is enough to 'filter'.

In our case, if we filter down the 1-bit 1.19 MHz stream to a 44.1 KHz stream, we should automatically perform the proper filtering anyway. Unless I'm missing something here...
I might experiment with some PWM<->PCM routines myself, because I want to use it for some demos in the future.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 24 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

Is there any other software where the CPU doesn't have to be cycle-exact, that produces sound using PCM over PWM? Which times it's PWM pulses using the PIT IRQ0 timer? That I can use to verify my PWM execution?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 25 of 57, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

I should have my speaker PWM file player somewhere, but it could take a while before I find it. Maybe some existing utilities or mod players work?

I also wrote a speaker music renderer for a friend but that was just a tool to write simulated PIT output to a raw audio data file, as square wave with either 0 or 16384. But all the other stuff was made with Audacity (high pass filter to remove DC offset, low pass filter to remove everything over 15kHz and downsample from 1193180Hz to 44100Hz. Sounded just as terrible as the real thing 😀 Same technique should apply to PWM output and PDM as well (this is what SACD DSD bitstream is). Btw, I suspect the friend used monotone to compose the song.

Reply 26 of 57, by Scali

User metadata
Rank l33t
Rank
l33t
superfury wrote:

Is there any other software where the CPU doesn't have to be cycle-exact, that produces sound using PCM over PWM? Which times it's PWM pulses using the PIT IRQ0 timer? That I can use to verify my PWM execution?

Links Golf is one.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 27 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just tried the Internal - "Samples" setting of Supaplex. When I click on the option "Samples" below "INTERNAL" I hear some gunshot (together with some high pitched 'random' sounds), just like https://www.youtube.com/watch?v=P58YvKRoYVw . Only the youtube video is without the random high-pitched sounds. Does that mean my emulation is (partly) correctly working?

Also, how do I make sure Links is using the PC speaker PCM/PWM as output? It's currently set to "REALSOUND (NO BOARD)". This should be correct?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 28 of 57, by Scali

User metadata
Rank l33t
Rank
l33t
superfury wrote:

Also, how do I make sure Links is using the PC speaker PCM/PWM as output? It's currently set to "REALSOUND (NO BOARD)".

That's it, RealSound(tm) was their patented technology for playing samples on PC speaker: https://en.wikipedia.org/wiki/RealSound

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 29 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

When is the music supposed to start? I'm currently in some loading menu with some "TORREY PINES 36 hole course" according to the describing text. The CPU is set to 8088, with default cycles (Use actual 8086 clock, but it will use 1 cycle/instruction atm).

Edit: Restarted with default cycles (equalling 8088 cycle speed synchronization with 1 cycle/instruction).

I've made a little recording of the audio (m4a file):

https://onedrive.live.com/redir?resid=2 ... file%2cm4a

I don't know if this is allowed to post here though. It's simply for reference on my PC speaker emulation in my emulator (It's a Windows recording of my emulator output during those two games(First Links, which doesn't seem to load well on 8088 speeds, then Supaplex, which seems to go slowly at first, but faster when returned to the main menu.)).

0:00 Attempt to start the Links Golf game.
2:40 Me having quit the emulator, restarting it (Turbo XT BIOS 2.5).
6:15 Supaplex main menu opened with old settings (I believe it's the PCM option). I misclick the options menu, starting the Demo game.
7:28 Having pressed ESC, the smiley blows up.
7:42 The first ball explodes, then the second shortly after it.
8:09 Return to the main menu. I go to the options screen correctly this time.
8:37 Re-selected the Samples option (PCM output). The bleepy gunshot plays and the music starts playing.
10:48 I clicked on the normal PC speaker output button for reference.
10:58 Disabled and Enabled SFX three times for comparison.
11:28 Sound somehow seems to continue 'playing' with Music option disabled, heard as ticks.
11:49 Disabled and Enabled SFX during normal PC speaker(appeggio) three times for comparison.

The Samples option seems to work fine, except for some sound effects (smiley blows up, bombs blows up, bleepy gunshot when enabling SFX and PCM rendering with SFX enabled)?

Last edited by superfury on 2016-01-14, 22:36. Edited 1 time in total.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 31 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

My last post now contains some recordings of my PC speaker emulation in action and descriptions of different parts and actions I took during recording.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 34 of 57, by Scali

User metadata
Rank l33t
Rank
l33t
superfury wrote:

But according to the system requirements I found of Links, it requires an 8088 CPU?
http://pcgamingwiki.com/wiki/Links:_The_Chall … em_requirements

It works on an 8088 CPU (as in, it probably doesn't use any instructions only available on newer CPUs), but they can go up to ~12 MHz.
I don't think it would work at 4.77 MHz.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 35 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just increased the speed, it's running at 2.94MIPS average according to MIPS 1.10 (compared to Dosbox's ~12MIPS). Both set to 3000 cycles.

Edit: I've tested actual timing: It's actually running at about 10% cycle speed according to calculations.

Edit: Doesn't PWM require accurate response? The CPU must be fast enough to (If we're sampling the output at 16666 2/3 kHz acording to the manual) to be able to respond to the PIT0 tick the moment it triggers? If it's too slow to respond (still executing the interrupt to setup the timer), the PWM will fail (as the output is in it's off state for too long, affecting the next sample).

The wiki uses the 16666 2/3Hz rate as an output stream for the samples. My emulation currently uses 44100Hz output stream. So the ammount of samples collected and averaged is different in my case (In my case every sample is made out of PIT RATE divided by 44100=27.05 PIT samples. But the example given on the wiki equates to PIT RATE divided by 16666 2/3=71,59092 PIT samples. So it uses ~2.6 times as much input data to average as my function does. Thus the PCM samples calculated are different. Is this what causes the strange noises in output (the remaining 1.6 PWM encoded samples being used as seperate PCM values (1 sample and 0.6 part of the next sample)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 36 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've made changes to increase speed on slow systems to allow multiple instructions to execute in one block before updating PIT and input. On fast enough systems it won't spin the emulated CPU(executing only 1 or no instruction. On slow systems it will now run faster due to blocking IRQ0 and other PIT timers(only once per instruction block).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 37 of 57, by Scali

User metadata
Rank l33t
Rank
l33t
superfury wrote:

Edit: Doesn't PWM require accurate response? The CPU must be fast enough to (If we're sampling the output at 16666 2/3 kHz acording to the manual) to be able to respond to the PIT0 tick the moment it triggers? If it's too slow to respond (still executing the interrupt to setup the timer), the PWM will fail (as the output is in it's off state for too long, affecting the next sample).

The CPU speed itself doesn't really matter. It may take longer between the interrupt to fire and the actual PIT value to be output by the CPU, but this time is constant. So all writes get the same delay, meaning that the actual sample rate is still the same as what the PIT0 tick is set to.
The only problem is that samples tend to be played at relatively high frequencies, and if your CPU is too slow, it cannot process the interrupts quickly enough, and it will lock up the machine.
So it depends on what sample rate the samples will be played at, and how complex the player is (it might have to decompress samples on-the-fly or something).
Basically, the faster the CPU, the better in this case 😀

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 38 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've improved the CPU to execute instructions in blocks(1+ instructions at a time, calculated using getnspassed_k before the block). If a instruction times out(total time executing the loop is past a 100us treshhold), it aborts the loop and continues into the main loop. I've also changed the PIT timing to use the actual instruction time(1 CPU cycle or the cycles executed by the current instruction(depending on cycle time and CPU cycles elapsed)) instead of realtime execution time. This should synchronize timing with the CPU. Since it's now executing batches of instructions, the input has some lag though(only updated after a block of instructions).

This should also solve the interrupt and PC speaker sampling problem, as it's based on CPU cycles instead of realtime. The realtime synchronization is now done by the CPU cycle counting itself.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 39 of 57, by superfury

User metadata
Rank l33t++
Rank
l33t++

Little capture after fixing the timing and other bugs with it, comparing x86EMU with Dosbox (according to MIPS):

The attachment Dosbox vs x86EMU.png is no longer available

It now detects much better timings. Although it's still pretty slow performance-wise according to running 8088MPH(slow text display).

MIPS 1.10 now detects Dosbox at about 2.75 MIPS compared to x86EMU 8.75MIPS. Although the XT, AT and Compaq 386 performance ratings are low compared to Dosbox and very low against the other ratings?

Both Dosbox and x86EMU(with 1 cycle/instruction or HALT state) have been set to 3000 cycles using 4.0GHz Intel i7-4790K with 8GB RAM.

Edit: I've now implemented accurate timing in all other hardware (Mouse, Keyboard, Adlib, ATA and DMA controllers). They will now use the same timing as the CPU clocks (which is already converted to realtime nanoseconds double-precision floating point). I do notice some timing differences between two PCs(2.93/2.94GHz Intel Core 2 Duo with 4GB RAM and the before mentioned Intel i7-4790K with 8GB RAM). Shouldn't this be the same, using the same cycle count and base timing clock(actual CPU cycle time, even though it's always 1 cycle per instruction)? The only realtime synchronization used is done in the emulator core, which executes instructions up to the current time and waits for the next instruction(block) to execute.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io