DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/innova.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include <string.h>
00020 #include "dosbox.h"
00021 #include "inout.h"
00022 #include "mixer.h"
00023 #include "pic.h"
00024 #include "setup.h"
00025 #include "control.h"
00026 
00027 #include "reSID/sid.h"
00028 
00029 #define SID_FREQ 894886
00030 
00031 static struct {
00032         SID2* sid;
00033         Bitu rate;
00034         Bitu basePort;
00035         Bitu last_used;
00036         MixerChannel * chan;
00037 } innova;
00038 
00039 static void innova_write(Bitu port,Bitu val,Bitu iolen) {
00040     (void)iolen;//UNUSED
00041         if (!innova.last_used) {
00042                 innova.chan->Enable(true);
00043         }
00044         innova.last_used=PIC_Ticks;
00045 
00046         Bitu sidPort = port-innova.basePort;
00047         innova.sid->write((reg8)sidPort, (reg8)val);
00048 }
00049 
00050 static Bitu innova_read(Bitu port,Bitu iolen) {
00051     (void)iolen;//UNUSED
00052         Bitu sidPort = port-innova.basePort;
00053         return innova.sid->read((reg8)sidPort);
00054 }
00055 
00056 
00057 static void INNOVA_CallBack(Bitu len) {
00058         if (!len) return;
00059 
00060         cycle_count delta_t = (cycle_count)(SID_FREQ*len/innova.rate);
00061         short* buffer = (short*)MixTemp;
00062         Bitu bufindex = 0;
00063 
00064         while(delta_t && bufindex != len) {
00065                 bufindex += (Bitu)innova.sid->clock(delta_t, buffer+bufindex, (int)(len-bufindex));
00066         }
00067         innova.chan->AddSamples_m16(len, buffer);
00068 
00069         if (innova.last_used+5000<PIC_Ticks) {
00070                 innova.last_used=0;
00071                 innova.chan->Enable(false);
00072         }
00073 }
00074 
00075 class INNOVA: public Module_base {
00076 private:
00077         IO_ReadHandleObject ReadHandler;
00078         IO_WriteHandleObject WriteHandler;
00079         MixerObject MixerChan;
00080 public:
00081         INNOVA(Section* configuration):Module_base(configuration) {
00082                 Section_prop * section=static_cast<Section_prop *>(configuration);
00083                 if(!section->Get_bool("innova")) return;
00084                 innova.rate = (unsigned int)section->Get_int("samplerate");
00085                 innova.basePort = (unsigned int)section->Get_hex("sidbase");
00086                 sampling_method method = SAMPLE_FAST;
00087                 int m = section->Get_int("quality");
00088                 switch(m) {
00089                 case 1: method = SAMPLE_INTERPOLATE; break;
00090                 case 2: method = SAMPLE_RESAMPLE_FAST; break;
00091                 case 3: method = SAMPLE_RESAMPLE_INTERPOLATE; break;
00092                 }
00093 
00094                 LOG_MSG("INNOVA:Initializing Innovation SSI-2001 (SID) emulation...");
00095 
00096                 WriteHandler.Install(innova.basePort,innova_write,IO_MB,0x20);
00097                 ReadHandler.Install(innova.basePort,innova_read,IO_MB,0x20);
00098         
00099                 innova.chan=MixerChan.Install(&INNOVA_CallBack,innova.rate,"INNOVA");
00100 
00101                 innova.sid = new SID2;
00102                 innova.sid->set_chip_model(MOS6581);
00103                 innova.sid->enable_filter(true);
00104                 innova.sid->enable_external_filter(true);
00105                 innova.sid->set_sampling_parameters(SID_FREQ, method, (double)innova.rate, -1, 0.97);
00106 
00107                 innova.last_used=0;
00108 
00109                 LOG_MSG("INNOVA:... finished.");
00110         }
00111         ~INNOVA(){
00112                 delete innova.sid;
00113         }
00114 };
00115 
00116 static INNOVA* test = NULL;
00117 
00118 static void INNOVA_ShutDown(Section* sec){
00119     (void)sec;//UNUSED
00120     if (test != NULL) {
00121         delete test;
00122         test = NULL;
00123     }
00124 }
00125 
00126 void INNOVA_OnReset(Section *sec) {
00127     (void)sec;//UNUSED
00128         if (test == NULL && !IS_PC98_ARCH) {
00129                 LOG(LOG_MISC,LOG_DEBUG)("Allocating Innova emulation");
00130                 test = new INNOVA(control->GetSection("innova"));
00131         }
00132 }
00133 
00134 void INNOVA_Init() {
00135         LOG(LOG_MISC,LOG_DEBUG)("Initializing INNOVA emulation");
00136 
00137         AddExitFunction(AddExitFunctionFuncPair(INNOVA_ShutDown),true);
00138         AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(INNOVA_OnReset));
00139 }
00140