diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 01cc1c2d3..fbe4bf05f 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -923,6 +923,24 @@ class ConcreteMachine: roms_[static_cast(type)] = data; } + // Obtains the system ROMs. + bool install_roms(const std::function>(const std::string &machine, const std::string &name)> &rom_with_name) override { + const char *os_files[] = { + "os464.rom", "basic464.rom", + "os664.rom", "basic664.rom", + "os6128.rom", "basic6128.rom", + "amsdos.rom" + }; + + for(size_t index = 0; index < sizeof(os_files) / sizeof(*os_files); ++index) { + auto data = rom_with_name("AmstradCPC", os_files[index]); + if(!data) return false; + set_rom(static_cast(index), *data); + } + + return true; + } + void set_component_is_sleeping(void *component, bool is_sleeping) override final { fdc_is_sleeping_ = fdc_.is_sleeping(); tape_player_is_sleeping_ = tape_player_.is_sleeping(); diff --git a/Machines/CRTMachine.hpp b/Machines/CRTMachine.hpp index 96f2ba7fd..6c5fb346c 100644 --- a/Machines/CRTMachine.hpp +++ b/Machines/CRTMachine.hpp @@ -35,6 +35,11 @@ class Machine { OpenGL context is bound. */ virtual void close_output() = 0; + + /*! + Provides the machine with a way to obtain such ROMs as it needs. + */ + virtual bool install_roms(const std::function>(const std::string &machine, const std::string &name)> &rom_with_name) { return true; } /// @returns The CRT this machine is drawing to. Should not be @c nullptr. virtual std::shared_ptr get_crt() = 0; diff --git a/Machines/Utility/MachineForTarget.cpp b/Machines/Utility/MachineForTarget.cpp index 9638f340b..3bd1ed25d 100644 --- a/Machines/Utility/MachineForTarget.cpp +++ b/Machines/Utility/MachineForTarget.cpp @@ -46,11 +46,21 @@ template class TypedDynamicMachine: public ::Machine::DynamicMachine ::Machine::DynamicMachine *::Machine::MachineForTarget(const StaticAnalyser::Target &target) { switch(target.machine) { case StaticAnalyser::Target::AmstradCPC: return new TypedDynamicMachine(AmstradCPC::Machine::AmstradCPC()); -// case StaticAnalyser::Target::Atari2600: return new TypedDynamicMachine(Atari2600::Machine::Atari2600()); -// case StaticAnalyser::Target::Electron: return new TypedDynamicMachine(Electron::Machine::Electron()); -// case StaticAnalyser::Target::Oric: return new TypedDynamicMachine(Oric::Machine::Oric()); -// case StaticAnalyser::Target::Vic20: return new TypedDynamicMachine(Commodore::Vic20::Machine::Vic20()); -// case StaticAnalyser::Target::ZX8081: return new TypedDynamicMachine(ZX8081::Machine::ZX8081(target)); - default: return nullptr; + case StaticAnalyser::Target::Atari2600: return new TypedDynamicMachine(Atari2600::Machine::Atari2600()); + case StaticAnalyser::Target::Electron: return new TypedDynamicMachine(Electron::Machine::Electron()); + case StaticAnalyser::Target::Oric: return new TypedDynamicMachine(Oric::Machine::Oric()); + case StaticAnalyser::Target::Vic20: return new TypedDynamicMachine(Commodore::Vic20::Machine::Vic20()); + case StaticAnalyser::Target::ZX8081: return new TypedDynamicMachine(ZX8081::Machine::ZX8081(target)); + } +} + +std::string Machine::NameForTarget(const StaticAnalyser::Target &target) { + switch(target.machine) { + case StaticAnalyser::Target::AmstradCPC: return "AmstradCPC"; + case StaticAnalyser::Target::Atari2600: return "Atari2600"; + case StaticAnalyser::Target::Electron: return "Electron"; + case StaticAnalyser::Target::Oric: return "Oric"; + case StaticAnalyser::Target::Vic20: return "Vic20"; + case StaticAnalyser::Target::ZX8081: return "ZX8081"; } } diff --git a/Machines/Utility/MachineForTarget.hpp b/Machines/Utility/MachineForTarget.hpp index 488382c35..14adcecf7 100644 --- a/Machines/Utility/MachineForTarget.hpp +++ b/Machines/Utility/MachineForTarget.hpp @@ -16,6 +16,8 @@ #include "../JoystickMachine.hpp" #include "../KeyboardMachine.hpp" +#include + namespace Machine { /*! @@ -36,6 +38,13 @@ struct DynamicMachine { */ DynamicMachine *MachineForTarget(const StaticAnalyser::Target &target); +/*! + Returns a short string name for the machine identified by the target, + which is guaranteed not to have any spaces or other potentially + filesystem-bothering contents. +*/ +std::string NameForTarget(const StaticAnalyser::Target &target); + } #endif /* MachineForTarget_hpp */ diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 9e3dda043..af170e8ef 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include "../../StaticAnalyser/StaticAnalyser.hpp" @@ -65,8 +67,8 @@ int main(int argc, char *argv[]) { // Create and configure a machine. std::unique_ptr<::Machine::DynamicMachine> machine(::Machine::MachineForTarget(targets.front())); - machine->configuration_target()->configure_as_target(targets.front()); - + + updater.set_clock_rate(machine->crt_machine()->get_clock_rate()); crt_delegate.best_effort_updater = &updater; best_effort_updater_delegate.machine = machine.get(); @@ -98,9 +100,50 @@ int main(int argc, char *argv[]) { SDL_GLContext gl_context = SDL_GL_CreateContext(window); SDL_GL_MakeCurrent(window, gl_context); + + // Create an audio pipe. +// SDL_AudioSpec desired_audio_spec; +// SDL_AudioSpec obtained_audio_spec; +// desired_audio_spec.freq = 192000; // An arbitrary high number. +// desired_audio_spec.format = AUDIO_S16; +// desired_audio_spec.channels = 1; // Setup output, assuming a CRT machine for now, and prepare a best-effort updater. machine->crt_machine()->setup_output(4.0 / 3.0); + machine->crt_machine()->get_crt()->set_output_gamma(2.2f); + + // For vanilla SDL purposes, assume system ROMs can be found in one of: + // + // /usr/local/share/CLK/[system]; or + // /usr/share/CLK/[system] + machine->crt_machine()->install_roms( [] (const std::string &machine, const std::string &name) -> std::unique_ptr> { + std::string local_path = "/usr/local/share/CLK/" + machine + "/" + name; + FILE *file = fopen(local_path.c_str(), "r"); + if(!file) { + std::string path = "/usr/share/CLK/" + machine + "/" + name; + file = fopen(path.c_str(), "r"); + } + + if(!file) return nullptr; + + std::unique_ptr> data(new std::vector); + + fseek(file, 0, SEEK_END); + data->resize(ftell(file)); + fseek(file, 0, SEEK_SET); + fread(data->data(), 1, data->size(), file); + fclose(file); + + return data; + }); + + machine->configuration_target()->configure_as_target(targets.front()); + + // For now, lie about audio output intentions. + auto speaker = machine->crt_machine()->get_speaker(); + if(speaker) { + speaker->set_output_rate(44100, 1024); + } // Run the main event loop until the OS tells us to quit. bool should_quit = false; @@ -109,7 +152,7 @@ int main(int argc, char *argv[]) { SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { - default: std::cout << "Unhandled " << event.type << std::endl; break; +// default: std::cout << "Unhandled " << event.type << std::endl; break; case SDL_QUIT: should_quit = true; break; case SDL_KEYDOWN: @@ -123,7 +166,7 @@ int main(int argc, char *argv[]) { updater.update(); int width, height; SDL_GetWindowSize(window, &width, &height); - machine->crt_machine()->get_crt()->draw_frame(static_cast(width), static_cast(height), true); + machine->crt_machine()->get_crt()->draw_frame(static_cast(width), static_cast(height), false); SDL_GL_SwapWindow(window); }