1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00

Factor out machine wiring.

This commit is contained in:
Thomas Harte 2021-05-08 13:13:43 -04:00
parent 6d40549c0c
commit 8ae38991b0

View File

@ -479,6 +479,44 @@ class DynamicWindowTitler {
const std::string file_name_; const std::string file_name_;
}; };
/*!
Provides a wrapper for SDL_Joystick pointers that can keep track
of historic hat values.
*/
class SDLJoystick {
public:
SDLJoystick(SDL_Joystick *joystick) : joystick_(joystick) {
hat_values_.resize(SDL_JoystickNumHats(joystick));
}
~SDLJoystick() {
SDL_JoystickClose(joystick_);
}
/// @returns The underlying SDL_Joystick.
SDL_Joystick *get() {
return joystick_;
}
/// @returns A reference to the storage for the previous state of hat @c c.
Uint8 &last_hat_value(int c) {
return hat_values_[c];
}
/// @returns The logic OR of all stored hat states.
Uint8 hat_values() {
Uint8 value = 0;
for(const auto hat_value: hat_values_) {
value |= hat_value;
}
return value;
}
private:
SDL_Joystick *joystick_;
std::vector<Uint8> hat_values_;
};
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -844,91 +882,66 @@ int main(int argc, char *argv[]) {
// Setup output, assuming a CRT machine for now, and prepare a best-effort updater. // Setup output, assuming a CRT machine for now, and prepare a best-effort updater.
Outputs::Display::OpenGL::ScanTarget scan_target(target_framebuffer); Outputs::Display::OpenGL::ScanTarget scan_target(target_framebuffer);
machine->scan_producer()->set_scan_target(&scan_target); std::unique_ptr<ActivityObserver> activity_observer;
bool uses_mouse;
std::vector<SDLJoystick> joysticks;
// For now, lie about audio output intentions. const auto setup_machine_input_output = [&scan_target, &machine, &speaker_delegate, &activity_observer, &joysticks, &uses_mouse] {
auto speaker = machine->audio_producer()->get_speaker(); machine->scan_producer()->set_scan_target(&scan_target);
if(speaker) {
// Create an audio pipe.
SDL_AudioSpec desired_audio_spec;
SDL_AudioSpec obtained_audio_spec;
SDL_zero(desired_audio_spec); // For now, lie about audio output intentions.
desired_audio_spec.freq = 48000; // TODO: how can I get SDL to reveal the output rate of this machine? auto speaker = machine->audio_producer()->get_speaker();
desired_audio_spec.format = AUDIO_S16; if(speaker) {
desired_audio_spec.channels = 1 + int(speaker->get_is_stereo()); // Create an audio pipe.
desired_audio_spec.samples = Uint16(SpeakerDelegate::buffered_samples); SDL_AudioSpec desired_audio_spec;
desired_audio_spec.callback = SpeakerDelegate::SDL_audio_callback; SDL_AudioSpec obtained_audio_spec;
desired_audio_spec.userdata = &speaker_delegate;
speaker_delegate.audio_device = SDL_OpenAudioDevice(nullptr, 0, &desired_audio_spec, &obtained_audio_spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); SDL_zero(desired_audio_spec);
desired_audio_spec.freq = 48000; // TODO: how can I get SDL to reveal the output rate of this machine?
desired_audio_spec.format = AUDIO_S16;
desired_audio_spec.channels = 1 + int(speaker->get_is_stereo());
desired_audio_spec.samples = Uint16(SpeakerDelegate::buffered_samples);
desired_audio_spec.callback = SpeakerDelegate::SDL_audio_callback;
desired_audio_spec.userdata = &speaker_delegate;
speaker->set_output_rate(obtained_audio_spec.freq, desired_audio_spec.samples, obtained_audio_spec.channels == 2); speaker_delegate.audio_device = SDL_OpenAudioDevice(nullptr, 0, &desired_audio_spec, &obtained_audio_spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
speaker_delegate.is_stereo = obtained_audio_spec.channels == 2;
speaker->set_delegate(&speaker_delegate); speaker->set_output_rate(obtained_audio_spec.freq, desired_audio_spec.samples, obtained_audio_spec.channels == 2);
SDL_PauseAudioDevice(speaker_delegate.audio_device, 0); speaker_delegate.is_stereo = obtained_audio_spec.channels == 2;
} speaker->set_delegate(&speaker_delegate);
SDL_PauseAudioDevice(speaker_delegate.audio_device, 0);
}
/*
If the machine offers anything for activity observation,
create and register an activity observer.
*/
Activity::Source *const activity_source = machine->activity_source();
if(activity_source) {
activity_observer = std::make_unique<ActivityObserver>(activity_source, 4.0f / 3.0f);
} else {
activity_observer = nullptr;
}
// If this is a joystick machine, check for and open attached joysticks.
const auto joystick_machine = machine->joystick_machine();
if(joystick_machine) {
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
for(int c = 0; c < SDL_NumJoysticks(); ++c) {
joysticks.emplace_back(SDL_JoystickOpen(c));
}
} else {
joysticks.clear();
}
// Keep a record of whether mouse events can be forwarded.
uses_mouse = !!machine->mouse_machine();
};
setup_machine_input_output();
int window_width, window_height; int window_width, window_height;
SDL_GetWindowSize(window, &window_width, &window_height); SDL_GetWindowSize(window, &window_width, &window_height);
// If this is a joystick machine, check for and open attached joysticks.
/*!
Provides a wrapper for SDL_Joystick pointers that can keep track
of historic hat values.
*/
class SDLJoystick {
public:
SDLJoystick(SDL_Joystick *joystick) : joystick_(joystick) {
hat_values_.resize(SDL_JoystickNumHats(joystick));
}
~SDLJoystick() {
SDL_JoystickClose(joystick_);
}
/// @returns The underlying SDL_Joystick.
SDL_Joystick *get() {
return joystick_;
}
/// @returns A reference to the storage for the previous state of hat @c c.
Uint8 &last_hat_value(int c) {
return hat_values_[c];
}
/// @returns The logic OR of all stored hat states.
Uint8 hat_values() {
Uint8 value = 0;
for(const auto hat_value: hat_values_) {
value |= hat_value;
}
return value;
}
private:
SDL_Joystick *joystick_;
std::vector<Uint8> hat_values_;
};
std::vector<SDLJoystick> joysticks;
const auto joystick_machine = machine->joystick_machine();
if(joystick_machine) {
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
for(int c = 0; c < SDL_NumJoysticks(); ++c) {
joysticks.emplace_back(SDL_JoystickOpen(c));
}
}
/*
If the machine offers anything for activity observation,
create and register an activity observer.
*/
std::unique_ptr<ActivityObserver> activity_observer;
Activity::Source *const activity_source = machine->activity_source();
if(activity_source) {
activity_observer = std::make_unique<ActivityObserver>(activity_source, 4.0f / 3.0f);
}
// SDL 2.x delivers key up/down events and text inputs separately even when they're correlated; // SDL 2.x delivers key up/down events and text inputs separately even when they're correlated;
// this struct and map is used to correlate them by time. // this struct and map is used to correlate them by time.
struct KeyPress { struct KeyPress {
@ -945,7 +958,6 @@ int main(int argc, char *argv[]) {
std::vector<KeyPress> keypresses; std::vector<KeyPress> keypresses;
// Run the main event loop until the OS tells us to quit. // Run the main event loop until the OS tells us to quit.
const bool uses_mouse = !!machine->mouse_machine();
bool should_quit = false; bool should_quit = false;
Uint32 fullscreen_mode = 0; Uint32 fullscreen_mode = 0;
machine_runner.start(); machine_runner.start();