reactos/subsystems/ntvdm/hardware/speaker.c
Hermès Bélusca-Maïto d25d9ea618 [NTVDM]
- Enable experimental sound support (only PC speaker for the moment, aka. uses beep.sys).
- Introduce a #define WORKING_TIMER which aim is to disable the currently problematic approximate performance counter value calculation done in order not to call QueryPerformanceCounter each time.
  The problem is that we then compute a number of clock ticks for the PIT, which becomes negative, and therefore everything starts to hang.
  Disabling this code and calling each time QueryPerformanceCounter, fixes everything; we gain in precision but we loose in performance...
  A definitive fix must be found, [TheFlash] !!

This fixes sound (and hangs) in Advanced NetWars, Dangerous Dave, ElitePlus and Rescue Rover (the games that I've tested so far).

svn path=/branches/ntvdm/; revision=61875
2014-01-29 00:25:43 +00:00

146 lines
4.5 KiB
C

/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: speaker.c
* PURPOSE: PC Speaker emulation
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
#include "speaker.h"
#include "io.h"
#include "timer.h"
/* Extra PSDK/NDK Headers */
#include <ndk/iofuncs.h>
#include <ndk/obfuncs.h>
#include <ndk/rtlfuncs.h>
/* DDK Driver Headers */
#include <ntddbeep.h>
/* PRIVATE VARIABLES **********************************************************/
static HANDLE hBeep = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
/* PUBLIC FUNCTIONS ***********************************************************/
VOID SpeakerChange(VOID)
{
BYTE Port61hState = IOReadB(CONTROL_SYSTEM_PORT61H);
BOOLEAN IsConnectedToPITChannel2 = !!(Port61hState & 0x01);
BOOLEAN SpeakerDataOn = !!(Port61hState & 0x02);
if (PitChannel2 && IsConnectedToPITChannel2 && SpeakerDataOn)
{
/* Start beeping - Adapted from kernel32:Beep() */
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
BEEP_SET_PARAMETERS BeepSetParameters;
DWORD PitChannel2ReloadValue = PitChannel2->ReloadValue;
if (PitChannel2ReloadValue == 0) PitChannel2ReloadValue = 65536;
/* Set beep data */
BeepSetParameters.Frequency = (PIT_BASE_FREQUENCY / PitChannel2ReloadValue) *
(PitChannel2->Mode == PIT_MODE_SQUARE_WAVE ? 2 : 1);
BeepSetParameters.Duration = INFINITE;
/* Send the beep */
Status = NtDeviceIoControlFile(hBeep,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_BEEP_SET,
&BeepSetParameters,
sizeof(BeepSetParameters),
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
BeepSetParameters.Frequency,
BeepSetParameters.Duration,
Status);
}
}
else
{
/* Stop beeping */
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
BEEP_SET_PARAMETERS BeepSetParameters;
/* Set beep data */
BeepSetParameters.Frequency = 0x00;
BeepSetParameters.Duration = 0x00;
/* Send the beep */
Status = NtDeviceIoControlFile(hBeep,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_BEEP_SET,
&BeepSetParameters,
sizeof(BeepSetParameters),
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
BeepSetParameters.Frequency,
BeepSetParameters.Duration,
Status);
}
}
}
VOID SpeakerInitialize(VOID)
{
NTSTATUS Status;
UNICODE_STRING BeepDevice;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
/* Adapted from kernel32:Beep() */
//
// On TS systems, we need to Load Winsta.dll and call WinstationBeepOpen
// after doing a GetProcAddress for it
//
/* Open the device */
RtlInitUnicodeString(&BeepDevice, L"\\Device\\Beep");
InitializeObjectAttributes(&ObjectAttributes, &BeepDevice, 0, NULL, NULL);
Status = NtCreateFile(&hBeep,
FILE_READ_DATA | FILE_WRITE_DATA,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open Beep driver, Status 0x%08lx\n", Status);
}
}
VOID SpeakerCleanup(VOID)
{
NtClose(hBeep);
}
/* EOF */