Added support for driving the speaker line directly with the speaker gate, but

the square wave generator disabled. This feature has been used by old demos and
games to play digitized sound before soundcards with DSP became popular.
This commit is contained in:
Volker Ruppert 2018-05-10 10:50:42 +00:00
parent 53d703f6e1
commit c10e8feea6
7 changed files with 90 additions and 6 deletions

View File

@ -38,6 +38,8 @@ Changes after 2.6.9 release:
- Networking
- bxhub: Added DNS service support for the server "vnet" and connected
clients.
- Sound
- PC speaker now can play digitized sound by driving speaker gate.
- GUI and display libraries
- Added new win32 gui option "traphotkeys" for fullscreen mode.

View File

@ -324,6 +324,7 @@ public:
virtual void beep_off() {
bx_gui->beep_off();
}
virtual void set_line(bx_bool level) {}
};
#if BX_SUPPORT_PCI

View File

@ -2,7 +2,7 @@
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2017 The Bochs Project
// Copyright (C) 2001-2018 The Bochs Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -119,6 +119,7 @@ void bx_pit_c::init(void)
BX_PIT_THIS s.speaker_data_on = 0;
BX_PIT_THIS s.speaker_active = 0;
BX_PIT_THIS s.speaker_level = 0;
BX_PIT_THIS s.timer.init();
BX_PIT_THIS s.timer.set_OUT_handler(0, irq_handler);
@ -170,6 +171,7 @@ void bx_pit_c::register_state(void)
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pit", "8254 PIT State");
new bx_shadow_bool_c(list, "speaker_data_on", &BX_PIT_THIS s.speaker_data_on);
new bx_shadow_bool_c(list, "speaker_active", &BX_PIT_THIS s.speaker_active);
new bx_shadow_bool_c(list, "speaker_level", &BX_PIT_THIS s.speaker_level);
new bx_shadow_num_c(list, "last_usec", &BX_PIT_THIS s.last_usec);
new bx_shadow_num_c(list, "last_next_event_time", &BX_PIT_THIS s.last_next_event_time);
new bx_shadow_num_c(list, "total_ticks", &BX_PIT_THIS s.total_ticks);
@ -295,7 +297,7 @@ void bx_pit_c::write(Bit32u address, Bit32u dvalue, unsigned io_len)
Bit64u my_time_usec = bx_virt_timer.time_usec(BX_PIT_THIS is_realtime);
Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec;
Bit32u value32, time_passed32 = (Bit32u)time_passed;
bx_bool new_speaker_active;
bx_bool new_speaker_active, new_speaker_level;
if (time_passed32) {
periodic(time_passed32);
@ -342,6 +344,13 @@ void bx_pit_c::write(Bit32u address, Bit32u dvalue, unsigned io_len)
}
BX_PIT_THIS s.speaker_active = new_speaker_active;
}
if (!BX_PIT_THIS s.speaker_active) {
new_speaker_level = BX_PIT_THIS s.speaker_data_on & BX_PIT_THIS s.timer.read_OUT(2);
if (BX_PIT_THIS s.speaker_level != new_speaker_level) {
DEV_speaker_set_line(new_speaker_level);
BX_PIT_THIS s.speaker_level = new_speaker_level;
}
}
break;
default:

View File

@ -2,7 +2,7 @@
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2017 The Bochs Project
// Copyright (C) 2001-2018 The Bochs Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -59,6 +59,7 @@ private:
pit_82C54 timer;
bx_bool speaker_data_on;
bx_bool speaker_active;
bx_bool speaker_level;
Bit64u last_usec;
Bit32u last_next_event_time;
Bit64u total_ticks;

View File

@ -195,6 +195,12 @@ void bx_speaker_c::init(void)
waveout = DEV_sound_get_waveout(0);
if (waveout != NULL) {
beep_active = 0;
#if BX_HAVE_REALTIME_USEC
dsp_active = 0;
dsp_start_usec = bx_get_realtime64_usec();
dsp_cb_usec = 0;
dsp_count = 0;
#endif
BX_INIT_MUTEX(beep_mutex);
beep_callback_id = waveout->register_wave_callback(theSpeaker, beep_callback);
BX_INFO(("Using lowlevel sound support for output"));
@ -234,7 +240,7 @@ void bx_speaker_c::reset(unsigned type)
#if BX_SUPPORT_SOUNDLOW
Bit32u bx_speaker_c::beep_generator(Bit16u rate, Bit8u *buffer, Bit32u len)
{
Bit32u j = 0;
Bit32u j = 0, ret = 0;
Bit16u beep_samples;
static Bit8u beep_level = 0x40;
static Bit16u beep_pos = 0;
@ -246,8 +252,13 @@ Bit32u bx_speaker_c::beep_generator(Bit16u rate, Bit8u *buffer, Bit32u len)
beep_samples = (Bit32u)((float)rate / beep_frequency / 2);
}
if (beep_samples == 0) {
#if BX_SUPPORT_SOUNDLOW && BX_HAVE_REALTIME_USEC
if (dsp_active) {
ret = dsp_generator(rate, buffer, len);
}
#endif
BX_UNLOCK(beep_mutex);
return 0;
return ret;
}
do {
buffer[j++] = 0;
@ -265,6 +276,37 @@ Bit32u bx_speaker_c::beep_generator(Bit16u rate, Bit8u *buffer, Bit32u len)
return len;
}
#if BX_SUPPORT_SOUNDLOW && BX_HAVE_REALTIME_USEC
Bit32u bx_speaker_c::dsp_generator(Bit16u rate, Bit8u *buffer, Bit32u len)
{
Bit32u i = 0, j = 0;
double tmp_dsp_usec, step_usec;
static Bit8u dsp_level = 0x40;
Bit64u new_dsp_cb_usec = bx_get_realtime64_usec() - dsp_start_usec;
if (dsp_cb_usec == 0) {
dsp_cb_usec = new_dsp_cb_usec - 25000;
}
tmp_dsp_usec = (double)dsp_cb_usec;
step_usec = 1000000.0 / (double)rate;
do {
if ((i < dsp_count) && (dsp_event_buffer[i] < (Bit64u)tmp_dsp_usec)) {
dsp_level ^= 0x80;
i++;
}
buffer[j++] = 0;
buffer[j++] = dsp_level;
buffer[j++] = 0;
buffer[j++] = dsp_level;
tmp_dsp_usec += step_usec;
} while (j < len);
dsp_active = 0;
dsp_count = 0;
dsp_cb_usec = new_dsp_cb_usec;
return len;
}
#endif
Bit32u beep_callback(void *dev, Bit16u rate, Bit8u *buffer, Bit32u len)
{
return ((bx_speaker_c*)dev)->beep_generator(rate, buffer, len);
@ -367,3 +409,20 @@ void bx_speaker_c::beep_off()
}
beep_frequency = 0.0;
}
void bx_speaker_c::set_line(bx_bool level)
{
if (output_mode == BX_SPK_MODE_SOUND) {
#if BX_SUPPORT_SOUNDLOW && BX_HAVE_REALTIME_USEC
BX_LOCK(beep_mutex);
Bit64u timestamp = bx_get_realtime64_usec() - dsp_start_usec;
dsp_active = 1;
if (dsp_count < 500) {
dsp_event_buffer[dsp_count++] = timestamp;
} else {
BX_ERROR(("DSP event buffer full"));
}
BX_UNLOCK(beep_mutex);
#endif
}
}

View File

@ -3,7 +3,7 @@
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003 David N. Welton <davidw@dedasys.com>.
// Copyright (C) 2003-2015 The Bochs Project
// Copyright (C) 2003-2018 The Bochs Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@ -41,8 +41,12 @@ public:
void beep_on(float frequency);
void beep_off();
void set_line(bx_bool level);
#if BX_SUPPORT_SOUNDLOW
Bit32u beep_generator(Bit16u rate, Bit8u *buffer, Bit32u len);
#if BX_HAVE_REALTIME_USEC
Bit32u dsp_generator(Bit16u rate, Bit8u *buffer, Bit32u len);
#endif
#endif
private:
float beep_frequency; // 0 : beep is off
@ -58,6 +62,13 @@ private:
bx_soundlow_waveout_c *waveout;
int beep_callback_id;
bx_bool beep_active;
#if BX_HAVE_REALTIME_USEC
bx_bool dsp_active;
Bit64u dsp_start_usec;
Bit64u dsp_cb_usec;
Bit32u dsp_count;
Bit64u dsp_event_buffer[500];
#endif
#endif
};

View File

@ -256,6 +256,7 @@ extern "C" {
///////// Speaker macros
#define DEV_speaker_beep_on(frequency) bx_devices.pluginSpeaker->beep_on(frequency)
#define DEV_speaker_beep_off() bx_devices.pluginSpeaker->beep_off()
#define DEV_speaker_set_line(a) bx_devices.pluginSpeaker->set_line(a)
///////// Memory macros
#define DEV_register_memory_handlers(param,rh,wh,b,e) \