diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 1947b1573..6c19233a7 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -8,7 +8,7 @@ * * Generic CD-ROM drive core. * - * Version: @(#)cdrom.c 1.0.8 2019/09/26 + * Version: @(#)cdrom.c 1.0.9 2019/12/13 * * Author: Miran Grca, * @@ -332,7 +332,7 @@ cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - pclog("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); + cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); cdrom_stop(dev); return 0; } diff --git a/src/cdrom/cdrom_dosbox.cpp b/src/cdrom/cdrom_dosbox.cpp deleted file mode 100644 index 95ee86e3d..000000000 --- a/src/cdrom/cdrom_dosbox.cpp +++ /dev/null @@ -1,884 +0,0 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * CD-ROM image file handling module. - * - * Re-hacked to remove the dirname() function, and to have this - * code using stdio instead of C++ fstream - fstream cannot deal - * with Unicode pathnames, and we need those. --FvK - * - * **NOTE** This code will very soon be replaced with a C variant, so - * no more changes will be done. - * - * Version: @(#)cdrom_dosbox.cpp 1.0.12 2019/10/22 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * The DOSBox Team, - * - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2019 Miran Grca. - * Copyright 2002-2019 The DOSBox Team. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. - */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -# include -#else -# include -#endif -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../plat.h" -#include "cdrom_dosbox.h" - -using namespace std; - - -#define MAX_LINE_LENGTH 512 -#define MAX_FILENAME_LENGTH 256 -#define CROSS_LEN 512 - - - -#ifdef ENABLE_CDROM_DOSBOX_LOG -int cdrom_dosbox_do_log = ENABLE_CDROM_DOSBOX_LOG; - - -void -cdrom_dosbox_log(const char *fmt, ...) -{ - va_list ap; - - if (cdrom_dosbox_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define cdrom_dosbox_log(fmt, ...) -#endif - - -CDROM_Interface_Image::BinaryFile::BinaryFile(const wchar_t *filename, bool &error) -{ - memset(fn, 0x00, sizeof(fn)); - wcscpy(fn, filename); - file = plat_fopen64(fn, L"rb"); - cdrom_dosbox_log("CDROM: binary_open(%ls) = %08lx\n", fn, file); - - if (file == NULL) - error = true; - else - error = false; -} - - -CDROM_Interface_Image::BinaryFile::~BinaryFile(void) -{ - if (file != NULL) { - fclose(file); - file = NULL; - } - memset(fn, 0x00, sizeof(fn)); -} - - -bool -CDROM_Interface_Image::BinaryFile::read(uint8_t *buffer, uint64_t seek, size_t count) -{ - cdrom_dosbox_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n", - file, seek, count); - if (file == NULL) return 0; - - fseeko64(file, seek, SEEK_SET); - if (fread(buffer, count, 1, file) != 1) { -#ifdef ENABLE_CDROM_DOSBOX_LOG - cdrom_dosbox_log("CDROM: binary_read failed!\n"); -#endif - return 0; - } - - return 1; -} - - -uint64_t -CDROM_Interface_Image::BinaryFile::getLength(void) -{ - off64_t len; - - cdrom_dosbox_log("CDROM: binary_length(%08lx)\n", file); - if (file == NULL) return 0; - - fseeko64(file, 0, SEEK_END); - len = ftello64(file); - cdrom_dosbox_log("CDROM: binary_length(%08lx) = %" PRIu64 "\n", file, len); - - return len; -} - - -CDROM_Interface_Image::CDROM_Interface_Image(void) -{ -} - - -CDROM_Interface_Image::~CDROM_Interface_Image(void) -{ - ClearTracks(); -} - - -void -CDROM_Interface_Image::InitNewMedia(void) -{ -} - - -bool -CDROM_Interface_Image::SetDevice(const wchar_t *path, int forceCD) -{ - (void)forceCD; - - if (CueLoadSheet(path)) return true; - - if (IsoLoadFile(path)) return true; - - return false; -} - - -bool -CDROM_Interface_Image::GetUPC(uint8_t& attr, char* upc) -{ - attr = 0; - strcpy(upc, this->mcn.c_str()); - - return true; -} - - -bool -CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) -{ - stTrack = 1; - end = (int)(tracks.size() - 1); - FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr); - - return true; -} - - -bool -CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, uint8_t& attr) -{ - if (track < 1 || track > (int)tracks.size()) return false; - - FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr); - track_number = tracks[track - 1].track_number; - attr = tracks[track - 1].attr; - - return true; -} - - -bool -CDROM_Interface_Image::GetAudioTrackEndInfo(int track, int& track_number, TMSF& start, unsigned char& attr) -{ - if (track < 1 || track > (int)tracks.size()) return false; - - FRAMES_TO_MSF(tracks[track - 1].start + tracks[track - 1].length + 150, &start.min, &start.sec, &start.fr); - track_number = tracks[track - 1].track_number; - attr = tracks[track - 1].attr; - - return true; -} - - -bool -CDROM_Interface_Image::GetAudioSub(int sector, uint8_t& attr, uint8_t& track, uint8_t& index, TMSF& relPos, TMSF& absPos) -{ - int cur_track = GetTrack(sector); - - if (cur_track < 1) return false; - - track = (uint8_t)cur_track; - attr = tracks[track - 1].attr; - index = 1; - - FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); - - /* Absolute position should be adjusted by 150, not the relative ones. */ - FRAMES_TO_MSF(sector - tracks[track - 1].start, &relPos.min, &relPos.sec, &relPos.fr); - - return true; -} - - -bool -CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) -{ - mediaPresent = true; - mediaChanged = false; - trayOpen = false; - - return true; -} - - -bool -CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, uint32_t sector, uint32_t num) -{ - int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; - uint8_t buflen = num * sectorSize; - uint8_t* buf = new uint8_t[buflen]; - bool success = true; /* reading 0 sectors is OK */ - uint32_t i; - - for (i = 0; i < num; i++) { - success = ReadSector(&buf[i * sectorSize], raw, sector + i); - if (! success) break; - } - - memcpy((void*)buffer, buf, buflen); - delete[] buf; - - return success; -} - - -bool -CDROM_Interface_Image::LoadUnloadMedia(bool unload) -{ - (void)unload; - - return true; -} - - -int -CDROM_Interface_Image::GetTrack(unsigned int sector) -{ - vector::iterator i = tracks.begin(); - vector::iterator end = tracks.end() - 1; - - while (i != end) { - Track &curr = *i; - Track &next = *(i + 1); - if (curr.start <= sector && sector < next.start) - return curr.number; - i++; - } - - return -1; -} - - -bool -CDROM_Interface_Image::ReadSector(uint8_t *buffer, bool raw, uint32_t sector) -{ - size_t length; - - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - uint64_t s = (uint64_t) sector; - uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); - if (tracks[track].mode2) - length = (raw ? RAW_SECTOR_SIZE : 2336); - else - length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); - if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false; - if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16; - if (tracks[track].mode2 && !raw) seek += 24; - - return tracks[track].file->read(buffer, seek, length); -} - - -bool -CDROM_Interface_Image::ReadSectorSub(uint8_t *buffer, uint32_t sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - uint64_t s = (uint64_t) sector; - uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); - if (tracks[track].sectorSize != 2448) return false; - - return tracks[track].file->read(buffer, seek, 2448); -} - - -int -CDROM_Interface_Image::GetSectorSize(uint32_t sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return 0; - - return tracks[track].sectorSize; -} - - -bool -CDROM_Interface_Image::IsMode2(uint32_t sector) -{ - int track = GetTrack(sector) - 1; - - if (track < 0) return false; - - if (tracks[track].mode2) - return true; - - return false; -} - - -int -CDROM_Interface_Image::GetMode2Form(uint32_t sector) -{ - int track = GetTrack(sector) - 1; - - if (track < 0) return false; - - return tracks[track].form; -} - - -bool -CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2) -{ - uint8_t pvd[COOKED_SECTOR_SIZE]; - uint64_t seek = 16 * sectorSize; // first vd is located at sector 16 - - if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16; - if (mode2) seek += 24; - - file->read(pvd, seek, COOKED_SECTOR_SIZE); - -#if 0 - pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) -#endif - - return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || - (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); -} - - -bool -CDROM_Interface_Image::IsoLoadFile(const wchar_t *filename) -{ - tracks.clear(); - - // data track - Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; - bool error; - track.file = new BinaryFile(filename, error); - if (error) { - delete track.file; - return false; - } - track.number = 1; - track.track_number = 1; //IMPORTANT: This is needed. - track.attr = DATA_TRACK; //data - track.form = 0; - - // try to detect iso type - if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) { - track.sectorSize = COOKED_SECTOR_SIZE; - track.mode2 = false; - } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) { - track.sectorSize = RAW_SECTOR_SIZE; - track.mode2 = false; - } else if (CanReadPVD(track.file, 2336, true)) { - track.sectorSize = 2336; - track.mode2 = true; - } else if (CanReadPVD(track.file, 2324, true)) { - track.sectorSize = 2324; - track.form = 2; - track.mode2 = true; - } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) { - track.sectorSize = RAW_SECTOR_SIZE; - track.mode2 = true; - } else { - /* Unknown mode: Assume regular 2048-byte sectors, this is needed so Apple Rhapsody ISO's can be mounted. */ - track.sectorSize = COOKED_SECTOR_SIZE; - track.mode2 = false; - } - - track.length = track.file->getLength() / track.sectorSize; - tracks.push_back(track); - - // leadout track - track.number = 2; - track.track_number = 0xAA; - track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ - track.start = track.length; - track.length = 0; - track.file = NULL; - tracks.push_back(track); - - return true; -} - - -bool -CDROM_Interface_Image::CueGetBuffer(char *str, char **line, bool up) -{ - char *s = *line; - char *p = str; - int quote = 0; - int done = 0; - int space = 1; - - /* Copy to local buffer until we have end of string or whitespace. */ - while (! done) { - switch(*s) { - case '\0': - if (quote) { - /* Ouch, unterminated string.. */ - return false; - } - done = 1; - break; - - case '\"': - quote ^= 1; - break; - - case ' ': - case '\t': - if (space) - break; - - if (! quote) { - done = 1; - break; - } - /*FALLTHROUGH*/ - - default: - if (up && islower((int) *s)) - *p++ = toupper((int) *s); - else - *p++ = *s; - space = 0; - break; - } - - if (! done) - s++; - } - *p = '\0'; - - *line = s; - - return true; -} - - -/* Get a filename string from the input line. */ -bool -CDROM_Interface_Image::CueGetString(string &dest, char **line) -{ - char temp[1024]; - bool success; - - success = CueGetBuffer(temp, line, false); - if (success) - dest = temp; - - return success; -} - - -bool -CDROM_Interface_Image::CueGetKeyword(string &dest, char **line) -{ - char temp[1024]; - bool success; - - success = CueGetBuffer(temp, line, true); - if (success) - dest = temp; - - return success; -} - - -/* Get a string from the input line, handling quotes properly. */ -uint64_t -CDROM_Interface_Image::CueGetNumber(char **line) -{ - char temp[128]; - uint64_t num; - - if (! CueGetBuffer(temp, line, false)) - return 0; - - if (sscanf(temp, "%" PRIu64, &num) != 1) - return 0; - - return num; -} - - -bool -CDROM_Interface_Image::CueGetFrame(uint64_t &frames, char **line) -{ - char temp[128]; - int min, sec, fr; - bool success; - - success = CueGetBuffer(temp, line, false); - if (! success) return false; - - success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3; - if (! success) return false; - - frames = MSF_TO_FRAMES(min, sec, fr); - - return true; -} - - -bool -CDROM_Interface_Image::CueLoadSheet(const wchar_t *cuefile) -{ - Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; - wchar_t pathname[MAX_FILENAME_LENGTH]; - uint64_t shift = 0; - uint64_t currPregap = 0; - uint64_t totalPregap = 0; - uint64_t prestart = 0; - int i; - bool canAddTrack = false; - bool success; - FILE *fp; - wstring name(L"r"); - - tracks.clear(); - - /* Get a copy of the filename into pathname, we need it later. */ - memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - plat_get_dirname(pathname, cuefile); - - /* Open the file. */ - fp = plat_fopen((wchar_t *) cuefile, (wchar_t *) name.c_str()); - if (fp == NULL) - return false; - - success = false; - - for (;;) { - char buf[MAX_LINE_LENGTH]; - char *line = buf; - - /* Read a line from the cuesheet file. */ - if (feof(fp) || fgets(buf, sizeof(buf), fp) == NULL || ferror(fp)) - break; - - /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, - but do checks to make sure we're not nuking other bytes. */ - for (i = 0; i < 2; i++) { - if (strlen(buf) > 0) { - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ - else if (buf[strlen(buf) - 1] == '\r') - buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ - } - } - - string command; - success = CueGetKeyword(command, &line); - - if (command == "TRACK") { - if (canAddTrack) - success = AddTrack(track, shift, prestart, totalPregap, currPregap); - else - success = true; - - track.start = 0; - track.skip = 0; - currPregap = 0; - prestart = 0; - - track.number = CueGetNumber(&line); - track.track_number = track.number; - string type; - success = CueGetKeyword(type, &line); - if (! success) break; - - track.form = 0; - - if (type == "AUDIO") { - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = AUDIO_TRACK; - track.mode2 = false; - } else if (type == "MODE1/2048") { - track.sectorSize = COOKED_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = false; - } else if (type == "MODE1/2352") { - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = false; - } else if (type == "MODE2/2048") { - track.form = 1; - track.sectorSize = 2048; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2324") { - track.form = 2; - track.sectorSize = 2324; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2336") { - track.sectorSize = 2336; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2352") { - track.form = 1; /* Assume this is XA Mode 2 Form 1. */ - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDG/2448") { - track.sectorSize = 2448; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDI/2336") { - track.sectorSize = 2336; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDI/2352") { - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = true; - } else - success = false; - - canAddTrack = true; - } else if (command == "INDEX") { - uint64_t frame = 0ULL, index; - index = CueGetNumber(&line); - success = CueGetFrame(frame, &line); - - switch(index) { - case 0: - prestart = frame; - break; - - case 1: - track.start = frame; - break; - - default: - /* ignore other indices */ - break; - } - } else if (command == "FILE") { - if (canAddTrack) - success = AddTrack(track, shift, prestart, totalPregap, currPregap); - else - success = true; - canAddTrack = false; - - char ansi[MAX_FILENAME_LENGTH]; - wchar_t filename[MAX_FILENAME_LENGTH]; - string type; - memset(ansi, 0, MAX_FILENAME_LENGTH); - memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - - success = CueGetBuffer(ansi, &line, false); - if (! success) break; - success = CueGetKeyword(type, &line); - if (! success) break; - - track.file = NULL; - bool error = true; - - if (type == "BINARY") { - wchar_t temp[MAX_FILENAME_LENGTH]; - memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); - mbstowcs(temp, ansi, sizeof_w(temp)); - plat_append_filename(filename, pathname, temp); - track.file = new BinaryFile(filename, error); - } - if (error) { -#ifdef ENABLE_CDROM_DOSBOX_LOG - cdrom_dosbox_log("CUE: cannot open fille '%ls' in cue sheet!\n", - filename); -#endif - delete track.file; - track.file = NULL; - success = false; - } - } else if (command == "PREGAP") - success = CueGetFrame(currPregap, &line); - else if (command == "CATALOG") { - success = CueGetString(mcn, &line); - // ignored commands - } else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC" - || command == "PERFORMER" || command == "POSTGAP" || command == "REM" - || command == "SONGWRITER" || command == "TITLE" || command == "") success = true; - // failure - else { -#ifdef ENABLE_CDROM_DOSBOX_LOG - cdrom_dosbox_log("CUE: unsupported command '%s' in cue sheet!\n", - command.c_str()); -#endif - success = false; - } - - if (! success) - break; - } - - fclose(fp); - if (! success) - return false; - - // add last track - if (! AddTrack(track, shift, prestart, totalPregap, currPregap)) - return false; - - // add leadout track - track.number++; - track.track_number = 0xAA; - // track.attr = 0;//sync with load iso - track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ - track.start = 0; - track.length = 0; - track.file = NULL; - if (! AddTrack(track, shift, 0, totalPregap, 0)) - return false; - - return true; -} - - -bool -CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap) -{ - // frames between index 0(prestart) and 1(curr.start) must be skipped - uint64_t skip; - - if (prestart > 0) { - if (prestart > curr.start) return false; - skip = curr.start - prestart; - } else skip = 0; - - // first track (track number must be 1) - if (tracks.empty()) { - if (curr.number != 1) return false; - curr.skip = skip * curr.sectorSize; - curr.start += currPregap; - totalPregap = currPregap; - tracks.push_back(curr); - return true; - } - - Track &prev = *(tracks.end() - 1); - - // current track consumes data from the same file as the previous - if (prev.file == curr.file) { - curr.start += shift; - prev.length = curr.start + totalPregap - prev.start - skip; - curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize); - totalPregap += currPregap; - curr.start += totalPregap; - // current track uses a different file as the previous track - } else { - uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip); - prev.length = tmp / ((uint64_t) prev.sectorSize); - if (tmp % prev.sectorSize != 0) prev.length++; // padding - - curr.start += prev.start + prev.length + currPregap; - curr.skip = skip * curr.sectorSize; - shift += prev.start + prev.length; - totalPregap = currPregap; - } - - // error checks - if (curr.number <= 1) return false; - if (prev.number + 1 != curr.number) return false; - if (curr.start < prev.start + prev.length) return false; - - tracks.push_back(curr); - - return true; -} - - -bool -CDROM_Interface_Image::HasDataTrack(void) -{ - //Data track has attribute 0x14 - for (track_it it = tracks.begin(); it != tracks.end(); it++) { - if ((*it).attr == DATA_TRACK) return true; - } - return false; -} - - -bool -CDROM_Interface_Image::HasAudioTracks(void) -{ - for (track_it it = tracks.begin(); it != tracks.end(); it++) { - if ((*it).attr == AUDIO_TRACK) return true; - } - return false; -} - - -void -CDROM_Interface_Image::ClearTracks(void) -{ - vector::iterator i = tracks.begin(); - vector::iterator end = tracks.end(); - - TrackFile* last = NULL; - while(i != end) { - Track &curr = *i; - if (curr.file != last) { - delete curr.file; - last = curr.file; - } - i++; - } - tracks.clear(); -} diff --git a/src/cdrom/cdrom_dosbox.h b/src/cdrom/cdrom_dosbox.h deleted file mode 100644 index 93b80340f..000000000 --- a/src/cdrom/cdrom_dosbox.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Definitions for the CD-ROM image file handling module. - * - * Version: @(#)cdrom_dosbox.h 1.0.3 2019/03/05 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * The DOSBox Team, - * - * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2002-2015 The DOSBox Team. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. - */ -#ifndef CDROM_INTERFACE -# define CDROM_INTERFACE - -#include -#include -#include -#include -#include -#include -#include - -//typedef signed int Bits; -//typedef unsigned int Bitu; -//typedef int8_t Bit8s; -//typedef int16_t Bit16s; -//typedef uint16_t Bit16u; -//typedef int32_t Bit32s; -//typedef uint32_t Bit32u; - -typedef size_t PhysPt; - - -#define RAW_SECTOR_SIZE 2352 -#define COOKED_SECTOR_SIZE 2048 - -#define DATA_TRACK 0x14 -#define AUDIO_TRACK 0x10 - -#define CD_FPS 75 -#define FRAMES_TO_MSF(f, M,S,F) { \ - uint64_t value = f; \ - *(F) = (value%CD_FPS) & 0xff; \ - value /= CD_FPS; \ - *(S) = (value%60) & 0xff; \ - value /= 60; \ - *(M) = value & 0xff; \ -} -#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) - - -typedef struct SMSF { - uint8_t min; - uint8_t sec; - uint8_t fr; -} TMSF; - -typedef struct SCtrl { - uint8_t out[4]; // output channel - uint8_t vol[4]; // channel volume -} TCtrl; - - -class CDROM_Interface { -public: -// CDROM_Interface(void); - - virtual ~CDROM_Interface(void) {}; - - virtual bool SetDevice(const wchar_t *path, int forceCD) = 0; - - virtual bool GetUPC(uint8_t& attr, char* upc) = 0; - - virtual bool GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) = 0; - virtual bool GetAudioTrackInfo(int track, int& number, TMSF& start, uint8_t& attr) = 0; - virtual bool GetAudioTrackEndInfo(int track, int& number, TMSF& start, unsigned char& attr) = 0; - virtual bool GetAudioSub(int sector, uint8_t& attr, uint8_t& track, uint8_t& index, TMSF& relPos, TMSF& absPos) = 0; - virtual bool GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; - - virtual bool ReadSectors(PhysPt buffer, bool raw, uint32_t sector, uint32_t num) = 0; - - virtual bool LoadUnloadMedia(bool unload) = 0; - - virtual void InitNewMedia(void) {}; -}; - - -class CDROM_Interface_Image : public CDROM_Interface { -private: - class TrackFile { - public: - virtual bool read(uint8_t *buffer, uint64_t seek, size_t count) = 0; - virtual uint64_t getLength() = 0; - virtual ~TrackFile() { }; - }; - - class BinaryFile : public TrackFile { - public: - BinaryFile(const wchar_t *filename, bool &error); - ~BinaryFile(); - bool read(uint8_t *buffer, uint64_t seek, size_t count); - uint64_t getLength(); - private: - BinaryFile(); - wchar_t fn[260]; - FILE *file; - }; - - struct Track { - int number; - int track_number; - int attr; - int form; - uint64_t start; - uint64_t length; - uint64_t skip; - int sectorSize; - bool mode2; - TrackFile *file; - }; - -public: - CDROM_Interface_Image(); - virtual ~CDROM_Interface_Image(void); - void InitNewMedia(void); - bool SetDevice(const wchar_t* path, int forceCD); - bool GetUPC(uint8_t& attr, char* upc); - bool GetAudioTracks(int& stTrack, int& end, TMSF& leadOut); - bool GetAudioTrackInfo(int track, int& number, TMSF& start, uint8_t& attr); - bool GetAudioTrackEndInfo(int track, int& number, TMSF& start, unsigned char& attr); - bool GetAudioSub(int sector, uint8_t& attr, uint8_t& track, uint8_t& index, TMSF& relPos, TMSF& absPos); - bool GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen); - bool ReadSectors(PhysPt buffer, bool raw, uint32_t sector, uint32_t num); - bool LoadUnloadMedia(bool unload); - bool ReadSector(uint8_t *buffer, bool raw, uint32_t sector); - bool ReadSectorSub(uint8_t *buffer, uint32_t sector); - int GetSectorSize(uint32_t sector); - bool IsMode2(uint32_t sector); - int GetMode2Form(uint32_t sector); - bool HasDataTrack(void); - bool HasAudioTracks(void); - - int GetTrack(unsigned int sector); - -private: - // player - static void CDAudioCallBack(unsigned int len); - - void ClearTracks(); - bool IsoLoadFile(const wchar_t *filename); - bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2); - - // cue sheet processing - bool CueGetBuffer(char *str, char **line, bool up); - bool CueGetString(std::string &str, char **line); - bool CueGetKeyword(std::string &keyword, char **line); - uint64_t CueGetNumber(char **line); - bool CueGetFrame(uint64_t &frames, char **line); - bool CueLoadSheet(const wchar_t *cuefile); - bool AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap); - - std::vector tracks; -typedef std::vector::iterator track_it; - std::string mcn; -}; - - -extern int CDROM_GetMountType(char* path, int force); - -extern void cdrom_image_log(const char *format, ...); - - -#endif /* __CDROM_INTERFACE__ */ diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.c similarity index 75% rename from src/cdrom/cdrom_image.cc rename to src/cdrom/cdrom_image.c index 4eb6c6499..34a2dcc29 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.c @@ -8,7 +8,7 @@ * * CD-ROM image support. * - * Version: @(#)cdrom_image.cc 1.0.10 2019/03/06 + * Version: @(#)cdrom_image.c 1.0.11 2019/03/06 * * Author: RichardG867, * Miran Grca, @@ -32,7 +32,7 @@ #include "../config.h" #include "../plat.h" #include "../scsi/scsi_device.h" -#include "cdrom_dosbox.h" +#include "cdrom_image_backend.h" #include "cdrom.h" #include "cdrom_image.h" @@ -60,29 +60,26 @@ cdrom_image_log(const char *fmt, ...) /* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) +#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) static void image_get_tracks(cdrom_t *dev, int *first, int *last) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; TMSF tmsf; - img->GetAudioTracks(*first, *last, tmsf); + cdi_get_audio_tracks(img, first, last, &tmsf); } static void image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; TMSF tmsf; - if (end) - img->GetAudioTrackEndInfo(track, ti->number, tmsf, ti->attr); - else - img->GetAudioTrackInfo(track, ti->number, tmsf, ti->attr); + cdi_get_audio_track_info(img, end, track, &ti->number, &tmsf, &ti->attr); ti->m = tmsf.min; ti->s = tmsf.sec; @@ -93,11 +90,11 @@ image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) static void image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; TMSF rel_pos, abs_pos; - img->GetAudioSub(lba, subc->attr, subc->track, subc->index, - rel_pos, abs_pos); + cdi_get_audio_sub(img, lba, &subc->attr, &subc->track, &subc->index, + &rel_pos, &abs_pos); subc->abs_m = abs_pos.min; subc->abs_s = abs_pos.sec; @@ -112,7 +109,7 @@ image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) static int image_get_capacity(cdrom_t *dev) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; int first_track, last_track; int number, c; unsigned char attr; @@ -123,10 +120,10 @@ image_get_capacity(cdrom_t *dev) if (!img) return 0; - img->GetAudioTracks(first_track, last_track, tmsf); + cdi_get_audio_tracks(img, &first_track, &last_track, &tmsf); for (c = 0; c <= last_track; c++) { - img->GetAudioTrackInfo(c+1, number, tmsf, attr); + cdi_get_audio_track_info(img, 0, c + 1, &number, &tmsf, &attr); address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ if (address > lb) lb = address; @@ -139,7 +136,7 @@ image_get_capacity(cdrom_t *dev) static int image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; uint8_t attr; TMSF tmsf; int m, s, f; @@ -156,7 +153,7 @@ image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) } /* GetTrack requires LBA. */ - img->GetAudioTrackInfo(img->GetTrack(pos), number, tmsf, attr); + cdi_get_audio_track_info(img, 0, cdi_get_track(img, pos), &number, &tmsf, &attr); return attr == AUDIO_TRACK; } @@ -165,27 +162,27 @@ image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) static int image_sector_size(struct cdrom *dev, uint32_t lba) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; - return img->GetSectorSize(lba); + return cdi_get_sector_size(img, lba); } static int image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; switch (type) { case CD_READ_DATA: - return img->ReadSector(b, false, lba); + return cdi_read_sector(img, b, 0, lba); case CD_READ_AUDIO: - return img->ReadSector(b, true, lba); + return cdi_read_sector(img, b, 1, lba); case CD_READ_RAW: - if (img->GetSectorSize(lba) == 2352) - return img->ReadSector(b, true, lba); + if (cdi_get_sector_size(img, lba) == 2352) + return cdi_read_sector(img, b, 1, lba); else - return img->ReadSectorSub(b, lba); + return cdi_read_sector_sub(img, b, lba); default: cdrom_image_log("CD-ROM %i: Unknown CD read type\n", dev->id); return 0; @@ -196,14 +193,14 @@ image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) static int image_track_type(cdrom_t *dev, uint32_t lba) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; if (img) { if (image_is_track_audio(dev, lba, 0)) return CD_TRACK_AUDIO; else { - if (img->IsMode2(lba)) - return CD_TRACK_MODE2 | img->GetMode2Form(lba); + if (cdi_is_mode2(img, lba)) + return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); } } @@ -214,13 +211,13 @@ image_track_type(cdrom_t *dev, uint32_t lba) static void image_exit(cdrom_t *dev) { - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + cd_img_t *img = (cd_img_t *)dev->image; cdrom_image_log("CDROM: image_exit(%ls)\n", dev->image_path); dev->cd_status = CD_STATUS_EMPTY; if (img) { - delete img; + cdi_close(img); dev->image = NULL; } @@ -252,22 +249,23 @@ image_open_abort(cdrom_t *dev) int cdrom_image_open(cdrom_t *dev, const wchar_t *fn) { - CDROM_Interface_Image *img; + cd_img_t *img; wcscpy(dev->image_path, fn); /* Create new instance of the CDROM_Image class. */ - img = new CDROM_Interface_Image(); + img = (cd_img_t *) malloc(sizeof(cd_img_t)); /* This guarantees that if ops is not NULL, then neither is the image pointer. */ if (!img) return image_open_abort(dev); + memset(img, 0, sizeof(cd_img_t)); dev->image = img; /* Open the image. */ - if (! img->SetDevice(fn, false)) + if (!cdi_set_device(img, fn)) return image_open_abort(dev); /* All good, reset state. */ diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c new file mode 100644 index 000000000..669989fc6 --- /dev/null +++ b/src/cdrom/cdrom_image_backend.c @@ -0,0 +1,937 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CD-ROM image file handling module, translated to C from + * cdrom_dosbox.cpp. + * + * Version: @(#)cdrom_image_backend.c 1.0.0 2019/12/19 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * The DOSBox Team, + * + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2002-2019 The DOSBox Team. + */ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat.h" +#include "cdrom_image_backend.h" + + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + + +#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG +int cdrom_image_backend_do_log = ENABLE_CDROM_IMAGE_BACKEND_LOG; + + +void +cdrom_image_backend_log(const char *fmt, ...) +{ + va_list ap; + + if (cdrom_image_backend_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cdrom_image_backend_log(fmt, ...) +#endif + + +/* Binary file functions. */ +static int +bin_read(void *p, uint8_t *buffer, uint64_t seek, size_t count) +{ + track_file_t *tf = (track_file_t *) p; + + cdrom_image_backend_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n", + tf->file, seek, count); + + if (tf->file == NULL) + return 0; + + fseeko64(tf->file, seek, SEEK_SET); + + if (fread(buffer, count, 1, tf->file) != 1) { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CDROM: binary_read failed!\n"); +#endif + return 0; + } + + return 1; +} + + +static uint64_t +bin_get_length(void *p) +{ + off64_t len; + track_file_t *tf = (track_file_t *) p; + + cdrom_image_backend_log("CDROM: binary_length(%08lx)\n", bf->file); + + if (tf->file == NULL) + return 0; + + fseeko64(tf->file, 0, SEEK_END); + len = ftello64(tf->file); + cdrom_image_backend_log("CDROM: binary_length(%08lx) = %" PRIu64 "\n", tf->file, len); + + return len; +} + + +static void +bin_close(void *p) +{ + track_file_t *tf = (track_file_t *) p; + + if (tf == NULL) + return; + + if (tf->file != NULL) { + fclose(tf->file); + tf->file = NULL; + } + + memset(tf->fn, 0x00, sizeof(tf->fn)); + + free(p); +} + + +static track_file_t * +bin_init(const wchar_t *filename, int *error) +{ + track_file_t *tf = (track_file_t *) malloc(sizeof(track_file_t)); + + memset(tf->fn, 0x00, sizeof(tf->fn)); + wcscpy(tf->fn, filename); + tf->file = plat_fopen64(tf->fn, L"rb"); + cdrom_image_backend_log("CDROM: binary_open(%ls) = %08lx\n", tf->fn, tf->file); + + *error = (tf->file == NULL); + + /* Set the function pointers. */ + if (!*error) { + tf->read = bin_read; + tf->get_length = bin_get_length; + tf->close = bin_close; + } + + return tf; +} + + +static track_file_t * +track_file_init(const wchar_t *filename, int *error) +{ + /* Current we only support .BIN files, either combined or one per + track. In the future, more is planned. */ + return bin_init(filename, error); +} + + +static void +track_file_close(track_t *trk) +{ + if (trk == NULL) + return; + + if (trk->file == NULL) + return; + + trk->file->close(trk->file); + trk->file = NULL; +} + + +/* Root functions. */ +static void +cdi_clear_tracks(cd_img_t *cdi) +{ + int i; + track_file_t *last = NULL; + track_t *cur = NULL; + + if ((cdi->tracks == NULL) || (cdi->tracks_num == 0)) + return; + + for (i = 0; i < cdi->tracks_num; i++) { + cur = &cdi->tracks[i]; + + if (cur->file != last) { + track_file_close(cur); + last = cur->file; + } + } + + /* Now free the array. */ + free(cdi->tracks); + cdi->tracks = NULL; + + /* Mark that there's no tracks. */ + cdi->tracks_num = 0; +} + + +void +cdi_close(cd_img_t *cdi) +{ + cdi_clear_tracks(cdi); + free(cdi); +} + + +int +cdi_set_device(cd_img_t *cdi, const wchar_t *path) +{ + if (cdi_load_cue(cdi, path)) + return 1; + + if (cdi_load_iso(cdi, path)) + return 1; + + return 0; +} + + +/* TODO: This never returns anything other than 1, should it even be an int? */ +int +cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out) +{ + *st_track = 1; + *end = cdi->tracks_num - 1; + FRAMES_TO_MSF(cdi->tracks[*end].start + 150, &lead_out->min, &lead_out->sec, &lead_out->fr); + + return 1; +} + + +/* This replaces both Info and EndInfo, they are specified by a variable. */ +int +cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr) +{ + track_t *trk = &cdi->tracks[track - 1]; + int pos = trk->start + 150; + + if ((track < 1) || (track > cdi->tracks_num)) + return 0; + + pos = trk->start + 150; + + FRAMES_TO_MSF(pos, &start->min, &start->sec, &start->fr); + *track_num = trk->track_number; + *attr = trk->attr; + + return 1; +} + + +int +cdi_get_track(cd_img_t *cdi, uint32_t sector) +{ + int i; + track_t *cur, *next; + + /* There must be at least two tracks - data and lead out. */ + if (cdi->tracks_num < 2) + return -1; + + /* This has a problem - the code skips the last track, which is + lead out - is that correct? */ + for (i = 0; i < (cdi->tracks_num - 1); i++) { + cur = &cdi->tracks[i]; + next = &cdi->tracks[i + 1]; + if ((cur->start <= sector) && (sector < next->start)) + return cur->number; + } + + return -1; +} + + +/* TODO: See if track start is adjusted by 150 or not. */ +int +cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos) +{ + int cur_track = cdi_get_track(cdi, sector); + track_t *trk; + + if (cur_track < 1) + return 0; + + *track = (uint8_t) cur_track; + trk = &cdi->tracks[*track - 1]; + *attr = trk->attr; + *index = 1; + + FRAMES_TO_MSF(sector + 150, &abs_pos->min, &abs_pos->sec, &abs_pos->fr); + + /* Absolute position should be adjusted by 150, not the relative ones. */ + FRAMES_TO_MSF(sector - trk->start, &rel_pos->min, &rel_pos->sec, &rel_pos->fr); + + return 1; +} + + +int +cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) +{ + size_t length; + int track = cdi_get_track(cdi, sector) - 1; + uint64_t s = (uint64_t) sector, seek; + track_t *trk; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + seek = trk->skip + ((s - trk->start) * trk->sector_size); + + /* TODO: Is this correct? Is cooked sector size 2336 for all Mode 2 variants? */ + if (trk->mode2 && (trk->form != 1)) { + if (trk->form == 2) + length = (raw ? RAW_SECTOR_SIZE : 2324); + else + length = (raw ? RAW_SECTOR_SIZE : 2336); + } else + length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); + + if (raw && (trk->sector_size != RAW_SECTOR_SIZE)) + return 0; + if (!raw && !trk->mode2 && (trk->sector_size == RAW_SECTOR_SIZE)) + seek += 16ULL; + /* TODO: See if Mode 2 is handled correctly here. */ + if (!raw && trk->mode2) + seek += 24ULL; + + return trk->file->read(trk->file, buffer, seek, length); +} + + +int +cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num) +{ + int sector_size, success = 1; + uint8_t buf_len, *buf; + uint32_t i; + + /* TODO: This fails to account for Mode 2. Shouldn't we have a function + to get sector size? */ + sector_size = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; + buf_len = num * sector_size; + buf = (uint8_t *) malloc(buf_len * sizeof(uint8_t)); + + for (i = 0; i < num; i++) { + success = cdi_read_sector(cdi, &buf[i * sector_size], raw, sector + i); + if (!success) + break; + } + + memcpy((void *) buffer, buf, buf_len); + free(buf); + buf = NULL; + + return success; +} + + +/* TODO: Do CUE+BIN images with a sector size of 2448 even exist? */ +int +cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + uint64_t s = (uint64_t) sector, seek; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + seek = trk->skip + ((s - trk->start) * trk->sector_size); + if (trk->sector_size != 2448) + return 0; + + return trk->file->read(trk->file, buffer, seek, 2448); +} + + +int +cdi_get_sector_size(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + return trk->sector_size; +} + + +int +cdi_is_mode2(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + + return !!(trk->mode2); +} + + +int +cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector) +{ + int track = cdi_get_track(cdi, sector) - 1; + track_t *trk; + + if (track < 0) + return 0; + + trk = &cdi->tracks[track]; + + return trk->form; +} + + +int +cdi_can_read_pvd(track_file_t *file, uint64_t sector_size, int mode2) +{ + uint8_t pvd[COOKED_SECTOR_SIZE]; + uint64_t seek = 16ULL * sector_size; /* First VD is located at sector 16. */ + + if (!mode2 && (sector_size == RAW_SECTOR_SIZE)) + seek += 16; + if (mode2) + seek += 24; + + file->read(file, pvd, seek, COOKED_SECTOR_SIZE); + + return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || + (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); +} + + +/* This reallocates the array and returns the pointer to the last track. */ +static void +cdi_track_push_back(cd_img_t *cdi, track_t *trk) +{ + /* This has to be done so situations in which realloc would misbehave + can be detected and reported to the user. */ + if ((cdi->tracks != NULL) && (cdi->tracks_num == 0)) + fatal("CD-ROM Image: Non-null tracks array at 0 loaded tracks\n"); + if ((cdi->tracks == NULL) && (cdi->tracks_num != 0)) + fatal("CD-ROM Image: Null tracks array at non-zero loaded tracks\n"); + + cdi->tracks = realloc(cdi->tracks, (cdi->tracks_num + 1) * sizeof(track_t)); + memcpy(&(cdi->tracks[cdi->tracks_num]), trk, sizeof(track_t)); + cdi->tracks_num++; +} + + +int +cdi_load_iso(cd_img_t *cdi, const wchar_t *filename) +{ + int error; + track_t trk; + + cdi->tracks = NULL; + cdi->tracks_num = 0; + + memset(&trk, 0, sizeof(track_t)); + + /* Data track (shouldn't there be a lead in track?). */ + trk.file = bin_init(filename, &error); + if (error) { + if (trk.file != NULL) + trk.file->close(trk.file); + return 0; + } + trk.number = 1; + trk.track_number = 1; + trk.attr = DATA_TRACK; + + /* Try to detect ISO type. */ + trk.form = 0; + trk.mode2 = 0; + /* TODO: Merge the first and last cases since they result in the same thing. */ + if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 0)) + trk.sector_size = RAW_SECTOR_SIZE; + else if (cdi_can_read_pvd(trk.file, 2336, 1)) { + trk.sector_size = 2336; + trk.mode2 = 1; + } else if (cdi_can_read_pvd(trk.file, 2324, 1)) { + trk.sector_size = 2324; + trk.mode2 = 1; + trk.form = 2; + } else if (cdi_can_read_pvd(trk.file, RAW_SECTOR_SIZE, 1)) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.mode2 = 1; + } else { + /* We use 2048 mode 1 as the default. */ + trk.sector_size = COOKED_SECTOR_SIZE; + } + + trk.length = trk.file->get_length(trk.file) / trk.sector_size; + cdi_track_push_back(cdi, &trk); + + /* Lead out track. */ + trk.number = 2; + trk.track_number = 0xAA; + trk.attr = 0x16; /* Was originally 0x00, but I believe 0x16 is appropriate. */ + trk.start = trk.length; + trk.length = 0; + trk.file = NULL; + cdi_track_push_back(cdi, &trk); + + return 1; +} + + +static int +cdi_cue_get_buffer(char *str, char **line, int up) +{ + char *s = *line; + char *p = str; + int quote = 0; + int done = 0; + int space = 1; + + /* Copy to local buffer until we have end of string or whitespace. */ + while (! done) { + switch(*s) { + case '\0': + if (quote) { + /* Ouch, unterminated string.. */ + return 0; + } + done = 1; + break; + + case '\"': + quote ^= 1; + break; + + case ' ': + case '\t': + if (space) + break; + + if (! quote) { + done = 1; + break; + } + /*FALLTHROUGH*/ + + default: + if (up && islower((int) *s)) + *p++ = toupper((int) *s); + else + *p++ = *s; + space = 0; + break; + } + + if (! done) + s++; + } + *p = '\0'; + + *line = s; + + return 1; +} + + +static int +cdi_cue_get_keyword(char **dest, char **line) +{ + char temp[1024]; + int success; + + success = cdi_cue_get_buffer(temp, line, 1); + if (success) + *dest = temp; + + return success; +} + + +/* Get a string from the input line, handling quotes properly. */ +static uint64_t +cdi_cue_get_number(char **line) +{ + char temp[128]; + uint64_t num; + + if (!cdi_cue_get_buffer(temp, line, 0)) + return 0; + + if (sscanf(temp, "%" PRIu64, &num) != 1) + return 0; + + return num; +} + + +static int +cdi_cue_get_frame(uint64_t *frames, char **line) +{ + char temp[128]; + int min, sec, fr; + int success; + + success = cdi_cue_get_buffer(temp, line, 0); + if (! success) return 0; + + success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3; + if (! success) return 0; + + *frames = MSF_TO_FRAMES(min, sec, fr); + + return 1; +} + + +static int +cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, uint64_t *total_pregap, uint64_t cur_pregap) +{ + /* Frames between index 0 (prestart) and 1 (current track start) must be skipped. */ + uint64_t skip, temp; + track_t *prev = NULL; + + if (prestart > 0) { + if (prestart > cur->start) + return 0; + skip = cur->start - prestart; + } else + skip = 0ULL; + + if ((cdi->tracks != NULL) && (cdi->tracks_num != 0)) + prev = &cdi->tracks[cdi->tracks_num - 1]; + + /* First track (track number must be 1). */ + if (cdi->tracks_num == 0) { + /* I guess this makes sure the structure is not filled with invalid data. */ + if (cur->number != 1) + return 0; + cur->skip = skip * cur->sector_size; + cur->start += cur_pregap; + *total_pregap = cur_pregap; + cdi_track_push_back(cdi, cur); + return 1; + } + + /* Current track consumes data from the same file as the previous. */ + if (prev->file == cur->file) { + cur->start += *shift; + prev->length = cur->start + *total_pregap - prev->start - skip; + cur->skip += prev->skip + (prev->length * prev->sector_size) + (skip * cur->sector_size); + *total_pregap += cur_pregap; + cur->start += *total_pregap; + } else { + temp = prev->file->get_length(prev->file) - ((uint64_t) prev->skip); + prev->length = temp / ((uint64_t) prev->sector_size); + if ((temp % prev->sector_size) != 0) + prev->length++; /* Padding. */ + + cur->start += prev->start + prev->length + cur_pregap; + cur->skip = skip * cur->sector_size; + *shift += prev->start + prev->length; + *total_pregap = cur_pregap; + } + + /* Error checks. */ + if (cur->number <= 1) + return 0; + if ((prev->number + 1) != cur->number) + return 0; + if (cur->start < (prev->start + prev->length)) + return 0; + + cdi_track_push_back(cdi, cur); + + return 1; +} + + +int +cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile) +{ + track_t trk; + wchar_t pathname[MAX_FILENAME_LENGTH], filename[MAX_FILENAME_LENGTH]; + wchar_t temp[MAX_FILENAME_LENGTH]; + uint64_t shift = 0ULL, prestart = 0ULL; + uint64_t cur_pregap = 0ULL, total_pregap = 0ULL; + uint64_t frame = 0ULL, index; + int i, success; + int error, can_add_track = 0; + FILE *fp; + char buf[MAX_LINE_LENGTH], ansi[MAX_FILENAME_LENGTH]; + char *line, *command; + char *type; + + cdi->tracks = NULL; + cdi->tracks_num = 0; + + memset(&trk, 0, sizeof(track_t)); + + /* Get a copy of the filename into pathname, we need it later. */ + memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); + plat_get_dirname(pathname, cuefile); + + /* Open the file. */ + fp = plat_fopen((wchar_t *) cuefile, L"r"); + if (fp == NULL) + return 0; + + success = 0; + + for (;;) { + line = buf; + + /* Read a line from the cuesheet file. */ + if (feof(fp) || fgets(buf, sizeof(buf), fp) == NULL || ferror(fp)) + break; + + /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, + but do checks to make sure we're not nuking other bytes. */ + for (i = 0; i < 2; i++) { + if (strlen(buf) > 0) { + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ + else if (buf[strlen(buf) - 1] == '\r') + buf[strlen(buf) - 1] = '\0'; /* nuke trailing newline */ + } + } + + success = cdi_cue_get_keyword(&command, &line); + + if (!strcmp(command, "TRACK")) { + if (can_add_track) + success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); + else + success = 1; + + trk.start = 0; + trk.skip = 0; + cur_pregap = 0; + prestart = 0; + + trk.number = cdi_cue_get_number(&line); + trk.track_number = trk.number; + success = cdi_cue_get_keyword(&type, &line); + if (!success) + break; + + trk.form = 0; + trk.mode2 = 0; + + if (!strcmp(type, "AUDIO")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = AUDIO_TRACK; + } else if (!strcmp(type, "MODE1/2048")) { + trk.sector_size = COOKED_SECTOR_SIZE; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE1/2352")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + } else if (!strcmp(type, "MODE2/2048")) { + trk.form = 1; + trk.sector_size = COOKED_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2324")) { + trk.form = 2; + trk.sector_size = 2324; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2336")) { + trk.sector_size = 2336; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "MODE2/2352")) { + trk.form = 1; /* Assume this is XA Mode 2 Form 1. */ + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDG/2448")) { + trk.sector_size = 2448; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDI/2336")) { + trk.sector_size = 2336; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else if (!strcmp(type, "CDI/2352")) { + trk.sector_size = RAW_SECTOR_SIZE; + trk.attr = DATA_TRACK; + trk.mode2 = 1; + } else + success = 0; + + can_add_track = 1; + } else if (!strcmp(command, "INDEX")) { + index = cdi_cue_get_number(&line); + success = cdi_cue_get_frame(&frame, &line); + + switch(index) { + case 0: + prestart = frame; + break; + + case 1: + trk.start = frame; + break; + + default: + /* ignore other indices */ + break; + } + } else if (!strcmp(command, "FILE")) { + if (can_add_track) + success = cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap); + else + success = 1; + can_add_track = 0; + + memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char)); + memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); + + success = cdi_cue_get_buffer(ansi, &line, 0); + if (!success) + break; + success = cdi_cue_get_keyword(&type, &line); + if (!success) + break; + + trk.file = NULL; + error = 1; + + if (!strcmp(type, "BINARY")) { + memset(temp, 0, MAX_FILENAME_LENGTH * sizeof(wchar_t)); + mbstowcs(temp, ansi, sizeof_w(temp)); + plat_append_filename(filename, pathname, temp); + trk.file = track_file_init(filename, &error); + } + if (error) { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CUE: cannot open fille '%ls' in cue sheet!\n", + filename); +#endif + if (trk.file != NULL) { + trk.file->close(trk.file); + trk.file = NULL; + } + success = 0; + } + } else if (!strcmp(command, "FILE")) + success = cdi_cue_get_frame(&cur_pregap, &line); + else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || !strcmp(command, "FLAGS") || !strcmp(command, "ISRC") || + !strcmp(command, "PERFORMER") || !strcmp(command, "POSTGAP") || !strcmp(command, "REM") || + !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || !strcmp(command, "")) { + /* Ignored commands. */ + success = 1; + } else { +#ifdef ENABLE_cdrom_image_backend_log + cdrom_image_backend_log("CUE: unsupported command '%s' in cue sheet!\n", + command.c_str()); +#endif + success = 0; + } + + if (!success) + break; + } + + fclose(fp); + if (!success) + return 0; + + /* Add last track. */ + if (!cdi_add_track(cdi, &trk, &shift, prestart, &total_pregap, cur_pregap)) + return 0; + + /* Add lead out track. */ + trk.number++; + trk.track_number = 0xAA; + trk.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + trk.start = 0; + trk.length = 0; + trk.file = NULL; + if (!cdi_add_track(cdi, &trk, &shift, 0, &total_pregap, 0)) + return 0; + + return 1; +} + + +int +cdi_has_data_track(cd_img_t *cdi) +{ + int i; + + if ((cdi == NULL) || (cdi->tracks == NULL)) + return 0; + + /* Data track has attribute 0x14. */ + for (i = 0; i < cdi->tracks_num; i++) { + if (cdi->tracks[i].attr == DATA_TRACK) + return 1; + } + + return 0; +} + + +int +cdi_has_audio_track(cd_img_t *cdi) +{ + int i; + + if ((cdi == NULL) || (cdi->tracks == NULL)) + return 0; + + /* Audio track has attribute 0x14. */ + for (i = 0; i < cdi->tracks_num; i++) { + if (cdi->tracks[i].attr == AUDIO_TRACK) + return 1; + } + + return 0; +} diff --git a/src/cdrom/cdrom_image_backend.h b/src/cdrom/cdrom_image_backend.h new file mode 100644 index 000000000..39d5b701d --- /dev/null +++ b/src/cdrom/cdrom_image_backend.h @@ -0,0 +1,94 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CD-ROM image file handling module header , translated to C + * from cdrom_dosbox.h. + * + * Version: @(#)cdrom_image_backend.h 1.0.0 2019/12/19 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * The DOSBox Team, + * + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2002-2019 The DOSBox Team. + */ +#ifndef CDROM_IMAGE_BACKEND_H +#define CDROM_IMAGE_BACKEND_H + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define DATA_TRACK 0x14 +#define AUDIO_TRACK 0x10 + +#define CD_FPS 75 +#define FRAMES_TO_MSF(f, M,S,F) { \ + uint64_t value = f; \ + *(F) = (value%CD_FPS) & 0xff; \ + value /= CD_FPS; \ + *(S) = (value%60) & 0xff; \ + value /= 60; \ + *(M) = value & 0xff; \ +} +#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) + + +typedef struct SMSF { + uint8_t min; + uint8_t sec; + uint8_t fr; +} TMSF; + +/* Track file struct. */ +typedef struct { + int (*read)(void *p, uint8_t *buffer, uint64_t seek, size_t count); + uint64_t (*get_length)(void *p); + void (*close)(void *p); + + wchar_t fn[260]; + FILE *file; +} track_file_t; + +typedef struct { + int number, track_number, attr, sector_size, + mode2, form; + uint64_t start, length, + skip; + track_file_t *file; +} track_t; + +typedef struct { + int tracks_num; + track_t *tracks; +} cd_img_t; + + +/* Binary file functions. */ +extern void cdi_close(cd_img_t *cdi); +extern int cdi_set_device(cd_img_t *cdi, const wchar_t *path); +extern int cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out); +extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr); +extern int cdi_get_track(cd_img_t *cdi, uint32_t sector); +extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); +extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector); +extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num); +extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector); +extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector); +extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector); +extern int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector); +extern int cdi_can_read_pvd(track_file_t *file, uint64_t sector_size, int mode2); +extern int cdi_load_iso(cd_img_t *cdi, const wchar_t *filename); +extern int cdi_load_cue(cd_img_t *cdi, const wchar_t *cuefile); +extern int cdi_has_data_track(cd_img_t *cdi); +extern int cdi_has_audio_track(cd_img_t *cdi); + + + +#endif /* ! CDROM_IMAGE_BACKEND_H */ diff --git a/src/config.c b/src/config.c index 9b09e7a8f..583605583 100644 --- a/src/config.c +++ b/src/config.c @@ -8,7 +8,7 @@ * * Configuration file handler. * - * Version: @(#)config.c 1.0.65 2019/12/05 + * Version: @(#)config.c 1.0.66 2019/12/21 * * Authors: Sarah Walker, * Miran Grca, @@ -57,9 +57,7 @@ #include "disk/zip.h" #include "sound/sound.h" #include "sound/midi.h" -#include "sound/snd_dbopl.h" #include "sound/snd_mpu401.h" -#include "sound/snd_opl.h" #include "sound/sound.h" #include "video/video.h" #include "plat.h" @@ -657,14 +655,6 @@ load_sound(void) GAMEBLASTER = !!config_get_int(cat, "gameblaster", 0); GUS = !!config_get_int(cat, "gus", 0); - memset(temp, '\0', sizeof(temp)); - p = config_get_string(cat, "opl_type", "dbopl"); - strcpy(temp, p); - if (!strcmp(temp, "nukedopl") || !strcmp(temp, "1")) - opl_type = 1; - else - opl_type = 0; - memset(temp, '\0', sizeof(temp)); p = config_get_string(cat, "sound_type", "float"); strcpy(temp, p); @@ -1271,7 +1261,6 @@ config_load(void) fdd_set_check_bpb(i, 1); } mem_size = 640; - opl_type = 0; isartc_type = 0; for (i = 0; i < ISAMEM_MAX; i++) isamem_type[i] = 0; @@ -1562,11 +1551,6 @@ save_sound(void) else config_set_int(cat, "gus", GUS); - if (opl_type == 0) - config_delete_var(cat, "opl_type"); - else - config_set_string(cat, "opl_type", (opl_type == 1) ? "nukedopl" : "dbopl"); - if (sound_is_float == 1) config_delete_var(cat, "sound_type"); else diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index f989d7423..5527dae0e 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -248,7 +248,7 @@ #define CHECK_READY 2 #define ALLOW_UA 1 -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) +#define MSFtoLBA(m,s,f) ((((m * 60) + s) * 75) + f) #define MSG_COMMAND_COMPLETE 0x00 diff --git a/src/sound/dbopl.cpp b/src/sound/dbopl.cpp deleted file mode 100644 index 85228ae10..000000000 --- a/src/sound/dbopl.cpp +++ /dev/null @@ -1,1512 +0,0 @@ -/* Copyright holders: The DOSBox Team - see COPYING for more details -*/ - -/* - DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. - Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 - Except for the table generation it's all integer math - Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms - The generation was based on the MAME implementation but tried to have it use less memory and be faster in general - MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times - - //TODO Don't delay first operator 1 sample in opl3 mode - //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter - //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? - //TODO Check if having the same accuracy in all frequency multipliers sounds better or not - - //DUNNO Keyon in 4op, switch to 2op without keyoff. -*/ - -/* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */ - -#include -#include -#include -#include "dbopl.h" - - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -namespace DBOPL { - -#define OPLRATE ((double)(14318180.0 / 288.0)) -#define TREMOLO_TABLE 52 - -//Try to use most precision for frequencies -//Else try to keep different waves in synch -//#define WAVE_PRECISION 1 -#ifndef WAVE_PRECISION -//Wave bits available in the top of the 32bit range -//Original adlib uses 10.10, we use 10.22 -#define WAVE_BITS 10 -#else -//Need some extra bits at the top to have room for octaves and frequency multiplier -//We support to 8 times lower rate -//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits -#define WAVE_BITS 14 -#endif -#define WAVE_SH ( 32 - WAVE_BITS ) -#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 ) - -//Use the same accuracy as the waves -#define LFO_SH ( WAVE_SH - 10 ) -//LFO is controlled by our tremolo 256 sample limit -#define LFO_MAX ( 256 << ( LFO_SH ) ) - - -//Maximum amount of attenuation bits -//Envelope goes to 511, 9 bits -#if (DBOPL_WAVE == WAVE_TABLEMUL ) -//Uses the value directly -#define ENV_BITS ( 9 ) -#else -//Add 3 bits here for more accuracy and would have to be shifted up either way -#define ENV_BITS ( 9 ) -#endif -//Limits of the envelope with those bits and when the envelope goes silent -#define ENV_MIN 0 -#define ENV_EXTRA ( ENV_BITS - 9 ) -#define ENV_MAX ( 511 << ENV_EXTRA ) -#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) ) -#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT ) - -//Attack/decay/release rate counter shift -#define RATE_SH 24 -#define RATE_MASK ( ( 1 << RATE_SH ) - 1 ) -//Has to fit within 16bit lookuptable -#define MUL_SH 16 - -//Check some ranges -#if ENV_EXTRA > 3 -#error Too many envelope bits -#endif - - -//How much to substract from the base value for the final attenuation -static const Bit8u KslCreateTable[16] = { - //0 will always be be lower than 7 * 8 - 64, 32, 24, 19, - 16, 12, 11, 10, - 8, 6, 5, 4, - 3, 2, 1, 0, -}; - -#define M(_X_) ((Bit8u)( (_X_) * 2)) -static const Bit8u FreqCreateTable[16] = { - M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), - M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) -}; -#undef M - -//We're not including the highest attack rate, that gets a special value -static const Bit8u AttackSamplesTable[13] = { - 69, 55, 46, 40, - 35, 29, 23, 20, - 19, 15, 11, 10, - 9 -}; -//On a real opl these values take 8 samples to reach and are based upon larger tables -static const Bit8u EnvelopeIncreaseTable[13] = { - 4, 5, 6, 7, - 8, 10, 12, 14, - 16, 20, 24, 28, - 32, -}; - -#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) -static Bit16u ExpTable[ 256 ]; -#endif - -#if ( DBOPL_WAVE == WAVE_HANDLER ) -//PI table used by WAVEHANDLER -static Bit16u SinTable[ 512 ]; -#endif - -#if ( DBOPL_WAVE > WAVE_HANDLER ) -//Layout of the waveform table in 512 entry intervals -//With overlapping waves we reduce the table to half it's size - -// | |//\\|____|WAV7|//__|/\ |____|/\/\| -// |\\//| | |WAV7| | \/| | | -// |06 |0126|17 |7 |3 |4 |4 5 |5 | - -//6 is just 0 shifted and masked - -static Bit16s WaveTable[ 8 * 512 ]; -//Distance into WaveTable the wave starts -static const Bit16u WaveBaseTable[8] = { - 0x000, 0x200, 0x200, 0x800, - 0xa00, 0xc00, 0x100, 0x400, - -}; -//Mask the counter with this -static const Bit16u WaveMaskTable[8] = { - 1023, 1023, 511, 511, - 1023, 1023, 512, 1023, -}; - -//Where to start the counter on at keyon -static const Bit16u WaveStartTable[8] = { - 512, 0, 0, 0, - 0, 512, 512, 256, -}; -#endif - -#if ( DBOPL_WAVE == WAVE_TABLEMUL ) -static Bit16u MulTable[ 384 ]; -#endif - -static Bit8u KslTable[ 8 * 16 ]; -static Bit8u TremoloTable[ TREMOLO_TABLE ]; -//Start of a channel behind the chip struct start -static Bit16u ChanOffsetTable[32]; -//Start of an operator behind the chip struct start -static Bit16u OpOffsetTable[64]; - -//The lower bits are the shift of the operator vibrato value -//The highest bit is right shifted to generate -1 or 0 for negation -//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 -static const Bit8s VibratoTable[ 8 ] = { - 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, - 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 -}; - -//Shift strength for the ksl value determined by ksl strength -static const Bit8u KslShiftTable[4] = { - 31,1,2,0 -}; - -//Generate a table index and table shift value using input value from a selected rate -static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { - if ( val < 13 * 4 ) { //Rate 0 - 12 - shift = 12 - ( val >> 2 ); - index = val & 3; - } else if ( val < 15 * 4 ) { //rate 13 - 14 - shift = 0; - index = val - 12 * 4; - } else { //rate 15 and up - shift = 0; - index = 12; - } -} - -#if ( DBOPL_WAVE == WAVE_HANDLER ) -/* - Generate the different waveforms out of the sine/exponetial table using handlers -*/ -static inline Bits MakeVolume( Bitu wave, Bitu volume ) { - Bitu total = wave + volume; - Bitu index = total & 0xff; - Bitu sig = ExpTable[ index ]; - Bitu exp = total >> 8; -#if 0 - //Check if we overflow the 31 shift limit - if ( exp >= 32 ) { - LOG_MSG( "WTF %d %d", total, exp ); - } -#endif - return (sig >> exp); -}; - -static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - Bitu wave = SinTable[i & 511]; - return (MakeVolume( wave, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { - Bit32u wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { - Bitu wave = SinTable[i & 511]; - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { - Bitu wave = SinTable[i & 255]; - wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { - //Twice as fast - i <<= 1; - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - Bitu wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return (MakeVolume( wave, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { - //Twice as fast - i <<= 1; - Bitu wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - return (MakeVolume( 0, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { - //Negative is reversed here - Bits neg = (( i >> 9) & 1) - 1; - Bitu wave = (i << 3); - //When negative the volume also runs backwards - wave = ((wave ^ neg) - neg) & 4095; - return (MakeVolume( wave, volume ) ^ neg) - neg; -} - -static const WaveHandler WaveHandlerTable[8] = { - WaveForm0, WaveForm1, WaveForm2, WaveForm3, - WaveForm4, WaveForm5, WaveForm6, WaveForm7 -}; - -#endif - -/* - Operator -*/ - -//We zero out when rate == 0 -inline void Operator::UpdateAttack( const Chip* chip ) { - Bit8u rate = reg60 >> 4; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - attackAdd = chip->attackRates[ val ]; - rateZero &= ~(1 << ATTACK); - } else { - attackAdd = 0; - rateZero |= (1 << ATTACK); - } -} -inline void Operator::UpdateDecay( const Chip* chip ) { - Bit8u rate = reg60 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - decayAdd = chip->linearRates[ val ]; - rateZero &= ~(1 << DECAY); - } else { - decayAdd = 0; - rateZero |= (1 << DECAY); - } -} -inline void Operator::UpdateRelease( const Chip* chip ) { - Bit8u rate = reg80 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - releaseAdd = chip->linearRates[ val ]; - rateZero &= ~(1 << RELEASE); - if ( !(reg20 & MASK_SUSTAIN ) ) { - rateZero &= ~( 1 << SUSTAIN ); - } - } else { - rateZero |= (1 << RELEASE); - releaseAdd = 0; - if ( !(reg20 & MASK_SUSTAIN ) ) { - rateZero |= ( 1 << SUSTAIN ); - } - } -} - -inline void Operator::UpdateAttenuation( ) { - Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); - Bit32u tl = reg40 & 0x3f; - Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; - //Make sure the attenuation goes to the right bits - totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max - totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; -} - -void Operator::UpdateFrequency( ) { - Bit32u freq = chanData & (( 1 << 10 ) - 1); - Bit32u block = (chanData >> 10) & 0xff; -#ifdef WAVE_PRECISION - block = 7 - block; - waveAdd = ( freq * freqMul ) >> block; -#else - waveAdd = ( freq << block ) * freqMul; -#endif - if ( reg20 & MASK_VIBRATO ) { - vibStrength = (Bit8u)(freq >> 7); - -#ifdef WAVE_PRECISION - vibrato = ( vibStrength * freqMul ) >> block; -#else - vibrato = ( vibStrength << block ) * freqMul; -#endif - } else { - vibStrength = 0; - vibrato = 0; - } -} - -void Operator::UpdateRates( const Chip* chip ) { - //Mame seems to reverse this where enabling ksr actually lowers - //the rate, but pdf manuals says otherwise? - Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); - if ( !( reg20 & MASK_KSR ) ) { - newKsr >>= 2; - } - if ( ksr == newKsr ) - return; - ksr = newKsr; - UpdateAttack( chip ); - UpdateDecay( chip ); - UpdateRelease( chip ); -} - -INLINE Bit32s Operator::RateForward( Bit32u add ) { - rateIndex += add; - Bit32s ret = rateIndex >> RATE_SH; - rateIndex = rateIndex & RATE_MASK; - return ret; -} - -template< Operator::State yes> -Bits Operator::TemplateVolume( ) { - Bit32s vol = volume; - Bit32s change; - switch ( yes ) { - case OFF: - return ENV_MAX; - case ATTACK: - change = RateForward( attackAdd ); - if ( !change ) - return vol; - vol += ( (~vol) * change ) >> 3; - if ( vol < ENV_MIN ) { - volume = ENV_MIN; - rateIndex = 0; - SetState( DECAY ); - return ENV_MIN; - } - break; - case DECAY: - vol += RateForward( decayAdd ); - if ( GCC_UNLIKELY(vol >= sustainLevel) ) { - //Check if we didn't overshoot max attenuation, then just go off - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - volume = ENV_MAX; - SetState( OFF ); - return ENV_MAX; - } - //Continue as sustain - rateIndex = 0; - SetState( SUSTAIN ); - } - break; - case SUSTAIN: - if ( reg20 & MASK_SUSTAIN ) { - return vol; - } - //In sustain phase, but not sustaining, do regular release - case RELEASE: - vol += RateForward( releaseAdd );; - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - volume = ENV_MAX; - SetState( OFF ); - return ENV_MAX; - } - break; - } - volume = vol; - return vol; -} - -static const VolumeHandler VolumeHandlerTable[5] = { - &Operator::TemplateVolume< Operator::OFF >, - &Operator::TemplateVolume< Operator::RELEASE >, - &Operator::TemplateVolume< Operator::SUSTAIN >, - &Operator::TemplateVolume< Operator::DECAY >, - &Operator::TemplateVolume< Operator::ATTACK > -}; - -INLINE Bitu Operator::ForwardVolume() { - return currentLevel + (this->*volHandler)(); -} - - -INLINE Bitu Operator::ForwardWave() { - waveIndex += waveCurrent; - return waveIndex >> WAVE_SH; -} - -void Operator::Write20( const Chip* chip, Bit8u val ) { - Bit8u change = (reg20 ^ val ); - if ( !change ) - return; - reg20 = val; - //Shift the tremolo bit over the entire register, saved a branch, YES! - tremoloMask = (Bit8s)(val) >> 7; - tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); - //Update specific features based on changes - if ( change & MASK_KSR ) { - UpdateRates( chip ); - } - //With sustain enable the volume doesn't change - if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) { - rateZero |= ( 1 << SUSTAIN ); - } else { - rateZero &= ~( 1 << SUSTAIN ); - } - //Frequency multiplier or vibrato changed - if ( change & (0xf | MASK_VIBRATO) ) { - freqMul = chip->freqMul[ val & 0xf ]; - UpdateFrequency(); - } -} - -void Operator::Write40( const Chip* /*chip*/, Bit8u val ) { - if (!(reg40 ^ val )) - return; - reg40 = val; - UpdateAttenuation( ); -} - -void Operator::Write60( const Chip* chip, Bit8u val ) { - Bit8u change = reg60 ^ val; - reg60 = val; - if ( change & 0x0f ) { - UpdateDecay( chip ); - } - if ( change & 0xf0 ) { - UpdateAttack( chip ); - } -} - -void Operator::Write80( const Chip* chip, Bit8u val ) { - Bit8u change = (reg80 ^ val ); - if ( !change ) - return; - reg80 = val; - Bit8u sustain = val >> 4; - //Turn 0xf into 0x1f - sustain |= ( sustain + 1) & 0x10; - sustainLevel = sustain << ( ENV_BITS - 5 ); - if ( change & 0x0f ) { - UpdateRelease( chip ); - } -} - -void Operator::WriteE0( const Chip* chip, Bit8u val ) { - if ( !(regE0 ^ val) ) - return; - //in opl3 mode you can always selet 7 waveforms regardless of waveformselect - Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); - regE0 = val; -#if ( DBOPL_WAVE == WAVE_HANDLER ) - waveHandler = WaveHandlerTable[ waveForm ]; -#else - waveBase = WaveTable + WaveBaseTable[ waveForm ]; - waveStart = WaveStartTable[ waveForm ] << WAVE_SH; - waveMask = WaveMaskTable[ waveForm ]; -#endif -} - -INLINE void Operator::SetState( Bit8u s ) { - state = s; - volHandler = VolumeHandlerTable[ s ]; -} - -INLINE bool Operator::Silent() const { - if ( !ENV_SILENT( totalLevel + volume ) ) - return false; - if ( !(rateZero & ( 1 << state ) ) ) - return false; - return true; -} - -INLINE void Operator::Prepare( const Chip* chip ) { - currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); - waveCurrent = waveAdd; - if ( vibStrength >> chip->vibratoShift ) { - Bit32s add = vibrato >> chip->vibratoShift; - //Sign extend over the shift value - Bit32s neg = chip->vibratoSign; - //Negate the add with -1 or 0 - add = ( add ^ neg ) - neg; - waveCurrent += add; - } -} - -void Operator::KeyOn( Bit8u mask ) { - if ( !keyOn ) { - //Restart the frequency generator -#if ( DBOPL_WAVE > WAVE_HANDLER ) - waveIndex = waveStart; -#else - waveIndex = 0; -#endif - rateIndex = 0; - SetState( ATTACK ); - } - keyOn |= mask; -} - -void Operator::KeyOff( Bit8u mask ) { - keyOn &= ~mask; - if ( !keyOn ) { - if ( state != OFF ) { - SetState( RELEASE ); - } - } -} - -INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { -#if ( DBOPL_WAVE == WAVE_HANDLER ) - return waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); -#elif ( DBOPL_WAVE == WAVE_TABLEMUL ) - return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; -#elif ( DBOPL_WAVE == WAVE_TABLELOG ) - Bit32s wave = waveBase[ index & waveMask ]; - Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); - Bit32s sig = ExpTable[ total & 0xff ]; - Bit32u exp = total >> 8; - Bit32s neg = wave >> 16; - return ((sig ^ neg) - neg) >> exp; -#else -#error "No valid wave routine" -#endif -} - -Bits INLINE Operator::GetSample( Bits modulation ) { - Bitu vol = ForwardVolume(); - if ( ENV_SILENT( vol ) ) { - //Simply forward the wave - waveIndex += waveCurrent; - return 0; - } else { - Bitu index = ForwardWave(); - index += modulation; - return GetWave( index, vol ); - } -} - -Operator::Operator() { - chanData = 0; - freqMul = 0; - waveIndex = 0; - waveAdd = 0; - waveCurrent = 0; - keyOn = 0; - ksr = 0; - reg20 = 0; - reg40 = 0; - reg60 = 0; - reg80 = 0; - regE0 = 0; - SetState( OFF ); - rateZero = (1 << OFF); - sustainLevel = ENV_MAX; - currentLevel = ENV_MAX; - totalLevel = ENV_MAX; - volume = ENV_MAX; - releaseAdd = 0; -} - -/* - Channel -*/ - -Channel::Channel() { - old[0] = old[1] = 0; - chanData = 0; - regB0 = 0; - regC0 = 0; - maskLeft = -1; - maskRight = -1; - feedback = 31; - fourMask = 0; - synthHandler = &Channel::BlockTemplate< sm2FM >; -}; - -void Channel::SetChanData( const Chip* chip, Bit32u data ) { - Bit32u change = chanData ^ data; - chanData = data; - Op( 0 )->chanData = data; - Op( 1 )->chanData = data; - //Since a frequency update triggered this, always update frequency - Op( 0 )->UpdateFrequency(); - Op( 1 )->UpdateFrequency(); - if ( change & ( 0xff << SHIFT_KSLBASE ) ) { - Op( 0 )->UpdateAttenuation(); - Op( 1 )->UpdateAttenuation(); - } - if ( change & ( 0xff << SHIFT_KEYCODE ) ) { - Op( 0 )->UpdateRates( chip ); - Op( 1 )->UpdateRates( chip ); - } -} - -void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) { - //Extrace the frequency bits - Bit32u data = chanData & 0xffff; - Bit32u kslBase = KslTable[ data >> 6 ]; - Bit32u keyCode = ( data & 0x1c00) >> 9; - if ( chip->reg08 & 0x40 ) { - keyCode |= ( data & 0x100)>>8; /* notesel == 1 */ - } else { - keyCode |= ( data & 0x200)>>9; /* notesel == 0 */ - } - //Add the keycode and ksl into the highest bits of chanData - data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); - ( this + 0 )->SetChanData( chip, data ); - if ( fourOp & 0x3f ) { - ( this + 1 )->SetChanData( chip, data ); - } -} - -void Channel::WriteA0( const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - Bit32u change = (chanData ^ val ) & 0xff; - if ( change ) { - chanData ^= change; - UpdateFrequency( chip, fourOp ); - } -} - -void Channel::WriteB0( const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00; - if ( change ) { - chanData ^= change; - UpdateFrequency( chip, fourOp ); - } - //Check for a change in the keyon/off state - if ( !(( val ^ regB0) & 0x20)) - return; - regB0 = val; - if ( val & 0x20 ) { - Op(0)->KeyOn( 0x1 ); - Op(1)->KeyOn( 0x1 ); - if ( fourOp & 0x3f ) { - ( this + 1 )->Op(0)->KeyOn( 1 ); - ( this + 1 )->Op(1)->KeyOn( 1 ); - } - } else { - Op(0)->KeyOff( 0x1 ); - Op(1)->KeyOff( 0x1 ); - if ( fourOp & 0x3f ) { - ( this + 1 )->Op(0)->KeyOff( 1 ); - ( this + 1 )->Op(1)->KeyOff( 1 ); - } - } -} - -void Channel::WriteC0( const Chip* chip, Bit8u val ) { - Bit8u change = val ^ regC0; - if ( !change ) - return; - regC0 = val; - feedback = ( val >> 1 ) & 7; - if ( feedback ) { - //We shift the input to the right 10 bit wave index value - feedback = 9 - feedback; - } else { - feedback = 31; - } - //Select the new synth mode - if ( chip->opl3Active ) { - //4-op mode enabled for this channel - if ( (chip->reg104 & fourMask) & 0x3f ) { - Channel* chan0, *chan1; - //Check if it's the 2nd channel in a 4-op - if ( !(fourMask & 0x80 ) ) { - chan0 = this; - chan1 = this + 1; - } else { - chan0 = this - 1; - chan1 = this; - } - - Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); - switch ( synth ) { - case 0: - chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; - break; - case 1: - chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; - break; - case 2: - chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; - break; - case 3: - chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; - break; - } - //Disable updating percussion channels - } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { - - //Regular dual op, am or fm - } else if ( val & 1 ) { - synthHandler = &Channel::BlockTemplate< sm3AM >; - } else { - synthHandler = &Channel::BlockTemplate< sm3FM >; - } - maskLeft = ( val & 0x10 ) ? -1 : 0; - maskRight = ( val & 0x20 ) ? -1 : 0; - //opl2 active - } else { - //Disable updating percussion channels - if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { - - //Regular dual op, am or fm - } else if ( val & 1 ) { - synthHandler = &Channel::BlockTemplate< sm2AM >; - } else { - synthHandler = &Channel::BlockTemplate< sm2FM >; - } - } -} - -void Channel::ResetC0( const Chip* chip ) { - Bit8u val = regC0; - regC0 ^= 0xff; - WriteC0( chip, val ); -}; - -template< bool opl3Mode> -INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) { - Channel* chan = this; - - //BassDrum - Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; - old[0] = old[1]; - old[1] = Op(0)->GetSample( mod ); - - //When bassdrum is in AM mode first operator is ignoed - if ( chan->regC0 & 1 ) { - mod = 0; - } else { - mod = old[0]; - } - Bit32s sample = Op(1)->GetSample( mod ); - - - //Precalculate stuff used by other outputs - Bit32u noiseBit = chip->ForwardNoise() & 0x1; - Bit32u c2 = Op(2)->ForwardWave(); - Bit32u c5 = Op(5)->ForwardWave(); - Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; - - //Hi-Hat - Bit32u hhVol = Op(2)->ForwardVolume(); - if ( !ENV_SILENT( hhVol ) ) { - Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); - sample += Op(2)->GetWave( hhIndex, hhVol ); - } - //Snare Drum - Bit32u sdVol = Op(3)->ForwardVolume(); - if ( !ENV_SILENT( sdVol ) ) { - Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); - sample += Op(3)->GetWave( sdIndex, sdVol ); - } - //Tom-tom - sample += Op(4)->GetSample( 0 ); - - //Top-Cymbal - Bit32u tcVol = Op(5)->ForwardVolume(); - if ( !ENV_SILENT( tcVol ) ) { - Bit32u tcIndex = (1 + phaseBit) << 8; - sample += Op(5)->GetWave( tcIndex, tcVol ); - } - sample <<= 1; - if ( opl3Mode ) { - output[0] += sample; - output[1] += sample; - } else { - output[0] += sample; - } -} - -template -Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { - switch( mode ) { - case sm2AM: - case sm3AM: - if ( Op(0)->Silent() && Op(1)->Silent() ) { - old[0] = old[1] = 0; - return (this + 1); - } - break; - case sm2FM: - case sm3FM: - if ( Op(1)->Silent() ) { - old[0] = old[1] = 0; - return (this + 1); - } - break; - case sm3FMFM: - if ( Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3AMFM: - if ( Op(0)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3FMAM: - if ( Op(1)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3AMAM: - if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm2Percussion: - case sm3Percussion: - break; - } - //Init the operators with the the current vibrato and tremolo values - Op( 0 )->Prepare( chip ); - Op( 1 )->Prepare( chip ); - if ( mode > sm4Start ) { - Op( 2 )->Prepare( chip ); - Op( 3 )->Prepare( chip ); - } - if ( mode > sm6Start ) { - Op( 4 )->Prepare( chip ); - Op( 5 )->Prepare( chip ); - } - for ( Bitu i = 0; i < samples; i++ ) { - //Early out for percussion handlers - if ( mode == sm2Percussion ) { - GeneratePercussion( chip, output + i ); - continue; //Prevent some unitialized value bitching - } else if ( mode == sm3Percussion ) { - GeneratePercussion( chip, output + i * 2 ); - continue; //Prevent some unitialized value bitching - } - - //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise - Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; - old[0] = old[1]; - old[1] = Op(0)->GetSample( mod ); - Bit32s sample; - Bit32s out0 = old[0]; - if ( mode == sm2AM || mode == sm3AM ) { - sample = out0 + Op(1)->GetSample( 0 ); - } else if ( mode == sm2FM || mode == sm3FM ) { - sample = Op(1)->GetSample( out0 ); - } else if ( mode == sm3FMFM ) { - Bits next = Op(1)->GetSample( out0 ); - next = Op(2)->GetSample( next ); - sample = Op(3)->GetSample( next ); - } else if ( mode == sm3AMFM ) { - sample = out0; - Bits next = Op(1)->GetSample( 0 ); - next = Op(2)->GetSample( next ); - sample += Op(3)->GetSample( next ); - } else if ( mode == sm3FMAM ) { - sample = Op(1)->GetSample( out0 ); - Bits next = Op(2)->GetSample( 0 ); - sample += Op(3)->GetSample( next ); - } else if ( mode == sm3AMAM ) { - sample = out0; - Bits next = Op(1)->GetSample( 0 ); - sample += Op(2)->GetSample( next ); - sample += Op(3)->GetSample( 0 ); - } - switch( mode ) { - case sm2AM: - case sm2FM: - if (chip->is_opl3) - { - output[ i * 2 + 0 ] += sample; - output[ i * 2 + 1 ] += sample; - } - else - output[ i ] += sample; - break; - case sm3AM: - case sm3FM: - case sm3FMFM: - case sm3AMFM: - case sm3FMAM: - case sm3AMAM: - output[ i * 2 + 0 ] += sample & maskLeft; - output[ i * 2 + 1 ] += sample & maskRight; - break; - case sm2Percussion: - case sm3Percussion: - break; - } - } - switch( mode ) { - case sm2AM: - case sm2FM: - case sm3AM: - case sm3FM: - return ( this + 1 ); - case sm3FMFM: - case sm3AMFM: - case sm3FMAM: - case sm3AMAM: - return( this + 2 ); - case sm2Percussion: - case sm3Percussion: - return( this + 3 ); - } - return 0; -} - -/* - Chip -*/ - -Chip::Chip() { - reg08 = 0; - reg04 = 0; - regBD = 0; - reg104 = 0; - opl3Active = 0; -} - -INLINE Bit32u Chip::ForwardNoise() { - noiseCounter += noiseAdd; - Bitu count = noiseCounter >> LFO_SH; - noiseCounter &= WAVE_MASK; - for ( ; count > 0; --count ) { - //Noise calculation from mame - noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) ); - noiseValue >>= 1; - } - return noiseValue; -} - -INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) { - //Current vibrato value, runs 4x slower than tremolo - vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7; - vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; - tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; - - //Check hom many samples there can be done before the value changes - Bit32u todo = LFO_MAX - lfoCounter; - Bit32u count = (todo + lfoAdd - 1) / lfoAdd; - if ( count > samples ) { - count = samples; - lfoCounter += count * lfoAdd; - } else { - lfoCounter += count * lfoAdd; - lfoCounter &= (LFO_MAX - 1); - //Maximum of 7 vibrato value * 4 - vibratoIndex = ( vibratoIndex + 1 ) & 31; - //Clip tremolo to the the table size - if ( tremoloIndex + 1 < TREMOLO_TABLE ) - ++tremoloIndex; - else - tremoloIndex = 0; - } - return count; -} - - -void Chip::WriteBD( Bit8u val ) { - Bit8u change = regBD ^ val; - if ( !change ) - return; - regBD = val; - //TODO could do this with shift and xor? - vibratoStrength = (val & 0x40) ? 0x00 : 0x01; - tremoloStrength = (val & 0x80) ? 0x00 : 0x02; - if ( val & 0x20 ) { - //Drum was just enabled, make sure channel 6 has the right synth - if ( change & 0x20 ) { - // if ( opl3Active ) { - if ( is_opl3 ) { - chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; - } else { - chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; - } - } - //Bass Drum - if ( val & 0x10 ) { - chan[6].op[0].KeyOn( 0x2 ); - chan[6].op[1].KeyOn( 0x2 ); - } else { - chan[6].op[0].KeyOff( 0x2 ); - chan[6].op[1].KeyOff( 0x2 ); - } - //Hi-Hat - if ( val & 0x1 ) { - chan[7].op[0].KeyOn( 0x2 ); - } else { - chan[7].op[0].KeyOff( 0x2 ); - } - //Snare - if ( val & 0x8 ) { - chan[7].op[1].KeyOn( 0x2 ); - } else { - chan[7].op[1].KeyOff( 0x2 ); - } - //Tom-Tom - if ( val & 0x4 ) { - chan[8].op[0].KeyOn( 0x2 ); - } else { - chan[8].op[0].KeyOff( 0x2 ); - } - //Top Cymbal - if ( val & 0x2 ) { - chan[8].op[1].KeyOn( 0x2 ); - } else { - chan[8].op[1].KeyOff( 0x2 ); - } - //Toggle keyoffs when we turn off the percussion - } else if ( change & 0x20 ) { - //Trigger a reset to setup the original synth handler - chan[6].ResetC0( this ); - chan[6].op[0].KeyOff( 0x2 ); - chan[6].op[1].KeyOff( 0x2 ); - chan[7].op[0].KeyOff( 0x2 ); - chan[7].op[1].KeyOff( 0x2 ); - chan[8].op[0].KeyOff( 0x2 ); - chan[8].op[1].KeyOff( 0x2 ); - } -} - - -#define REGOP( _FUNC_ ) \ - index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ - if ( OpOffsetTable[ index ] ) { \ - Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \ - regOp->_FUNC_( this, val ); \ - } - -#define REGCHAN( _FUNC_ ) \ - index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ - if ( ChanOffsetTable[ index ] ) { \ - Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \ - regChan->_FUNC_( this, val ); \ - } - -void Chip::WriteReg( Bit32u reg, Bit8u val ) { - Bitu index; - switch ( (reg & 0xf0) >> 4 ) { - case 0x00 >> 4: - if ( reg == 0x01 ) { - waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; - } else if ( reg == 0x104 ) { - //Only detect changes in lowest 6 bits - if ( !((reg104 ^ val) & 0x3f) ) - return; - //Always keep the highest bit enabled, for checking > 0x80 - reg104 = 0x80 | ( val & 0x3f ); - } else if ( reg == 0x105 ) { - //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register - if ( !((opl3Active ^ val) & 1 ) ) - return; - opl3Active = ( val & 1 ) ? 0xff : 0; - //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers - for ( int i = 0; i < 18;i++ ) { - chan[i].ResetC0( this ); - } - } else if ( reg == 0x08 ) { - reg08 = val; - } - case 0x10 >> 4: - break; - case 0x20 >> 4: - case 0x30 >> 4: - REGOP( Write20 ); - break; - case 0x40 >> 4: - case 0x50 >> 4: - REGOP( Write40 ); - break; - case 0x60 >> 4: - case 0x70 >> 4: - REGOP( Write60 ); - break; - case 0x80 >> 4: - case 0x90 >> 4: - REGOP( Write80 ); - break; - case 0xa0 >> 4: - REGCHAN( WriteA0 ); - break; - case 0xb0 >> 4: - if ( reg == 0xbd ) { - WriteBD( val ); - } else { - REGCHAN( WriteB0 ); - } - break; - case 0xc0 >> 4: - REGCHAN( WriteC0 ); - case 0xd0 >> 4: - break; - case 0xe0 >> 4: - case 0xf0 >> 4: - REGOP( WriteE0 ); - break; - } -} - - -Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) { - switch ( port & 3 ) { - case 0: - return val; - case 2: - if ( opl3Active || (val == 0x05) ) - return 0x100 | val; - else - return val; - } - return 0; -} - -void Chip::GenerateBlock2( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( total ); - memset(output, 0, sizeof(Bit32s) * samples); - int count = 0; - for( Channel* ch = chan; ch < chan + 9; ) { - count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples; - } -} - -void Chip::GenerateBlock3( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( total ); - memset(output, 0, sizeof(Bit32s) * samples *2); - int count = 0; - for( Channel* ch = chan; ch < chan + 18; ) { - count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples * 2; - } -} - -void Chip::Setup( Bit32u rate, int chip_is_opl3 ) { - double original = OPLRATE; -// double original = rate; - double scale = original / (double)rate; - - is_opl3 = chip_is_opl3; - - //Noise counter is run at the same precision as general waves - noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - noiseCounter = 0; - noiseValue = 1; //Make sure it triggers the noise xor the first time - //The low frequency oscillation counter - //Every time his overflows vibrato and tremoloindex are increased - lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - lfoCounter = 0; - vibratoIndex = 0; - tremoloIndex = 0; - - //With higher octave this gets shifted up - //-1 since the freqCreateTable = *2 -#ifdef WAVE_PRECISION - double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); - for ( int i = 0; i < 16; i++ ) { - freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); - } -#else - Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); - for ( int i = 0; i < 16; i++ ) { - freqMul[i] = freqScale * FreqCreateTable[ i ]; - } -#endif - - //-3 since the real envelope takes 8 steps to reach the single value we supply - for ( Bit8u i = 0; i < 76; i++ ) { - Bit8u index, shift; - EnvelopeSelect( i, index, shift ); - linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); - } - //Generate the best matching attack rate - for ( Bit8u i = 0; i < 62; i++ ) { - Bit8u index, shift; - EnvelopeSelect( i, index, shift ); - //Original amount of samples the attack would take - Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); - - Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); - Bit32s bestAdd = guessAdd; - Bit32u bestDiff = 1 << 30; - for( Bit32u passes = 0; passes < 16; passes ++ ) { - Bit32s volume = ENV_MAX; - Bit32s samples = 0; - Bit32u count = 0; - while ( volume > 0 && samples < original * 2 ) { - count += guessAdd; - Bit32s change = count >> RATE_SH; - count &= RATE_MASK; - if ( GCC_UNLIKELY(change) ) { // less than 1 % - volume += ( ~volume * change ) >> 3; - } - samples++; - - } - Bit32s diff = original - samples; - Bit32u lDiff = labs( diff ); - //Init last on first pass - if ( lDiff < bestDiff ) { - bestDiff = lDiff; - bestAdd = guessAdd; - if ( !bestDiff ) - break; - } - //Below our target - if ( diff < 0 ) { - //Better than the last time - Bit32s mul = ((original - diff) << 12) / original; - guessAdd = ((guessAdd * mul) >> 12); - guessAdd++; - } else if ( diff > 0 ) { - Bit32s mul = ((original - diff) << 12) / original; - guessAdd = (guessAdd * mul) >> 12; - guessAdd--; - } - } - attackRates[i] = bestAdd; - } - for ( Bit8u i = 62; i < 76; i++ ) { - //This should provide instant volume maximizing - attackRates[i] = 8 << RATE_SH; - } - //Setup the channels with the correct four op flags - //Channels are accessed through a table so they appear linear here - chan[ 0].fourMask = 0x00 | ( 1 << 0 ); - chan[ 1].fourMask = 0x80 | ( 1 << 0 ); - chan[ 2].fourMask = 0x00 | ( 1 << 1 ); - chan[ 3].fourMask = 0x80 | ( 1 << 1 ); - chan[ 4].fourMask = 0x00 | ( 1 << 2 ); - chan[ 5].fourMask = 0x80 | ( 1 << 2 ); - - chan[ 9].fourMask = 0x00 | ( 1 << 3 ); - chan[10].fourMask = 0x80 | ( 1 << 3 ); - chan[11].fourMask = 0x00 | ( 1 << 4 ); - chan[12].fourMask = 0x80 | ( 1 << 4 ); - chan[13].fourMask = 0x00 | ( 1 << 5 ); - chan[14].fourMask = 0x80 | ( 1 << 5 ); - - //mark the percussion channels - chan[ 6].fourMask = 0x40; - chan[ 7].fourMask = 0x40; - chan[ 8].fourMask = 0x40; - - //Clear Everything in opl3 mode - WriteReg( 0x105, 0x1 ); - for ( int i = 0; i < 512; i++ ) { - if ( i == 0x105 ) - continue; - WriteReg( i, 0xff ); - WriteReg( i, 0x0 ); - } - WriteReg( 0x105, 0x0 ); - //Clear everything in opl2 mode - for ( int i = 0; i < 255; i++ ) { - WriteReg( i, 0xff ); - WriteReg( i, 0x0 ); - } -} - -static bool doneTables = false; -void InitTables( void ) { - if ( doneTables ) - return; - doneTables = true; -#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) - //Exponential volume table, same as the real adlib - for ( int i = 0; i < 256; i++ ) { - //Save them in reverse - ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); - ExpTable[i] += 1024; //or remove the -1 oh well :) - //Preshift to the left once so the final volume can shift to the right - ExpTable[i] *= 2; - } -#endif -#if ( DBOPL_WAVE == WAVE_HANDLER ) - //Add 0.5 for the trunc rounding of the integer cast - //Do a PI sinetable instead of the original 0.5 PI - for ( int i = 0; i < 512; i++ ) { - SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); - } -#endif -#if ( DBOPL_WAVE == WAVE_TABLEMUL ) - //Multiplication based tables - for ( int i = 0; i < 384; i++ ) { - int s = i * 8; - //TODO maybe keep some of the precision errors of the original table? - double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); - MulTable[i] = (Bit16u)(val); - } - - //Sine Wave Base - for ( int i = 0; i < 512; i++ ) { - WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); - WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; - } - //Exponential wave - for ( int i = 0; i < 256; i++ ) { - WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); - WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; - } -#endif -#if ( DBOPL_WAVE == WAVE_TABLELOG ) - //Sine Wave Base - for ( int i = 0; i < 512; i++ ) { - WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); - WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; - } - //Exponential wave - for ( int i = 0; i < 256; i++ ) { - WaveTable[ 0x700 + i ] = i * 8; - WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; - } -#endif - - // | |//\\|____|WAV7|//__|/\ |____|/\/\| - // |\\//| | |WAV7| | \/| | | - // |06 |0126|27 |7 |3 |4 |4 5 |5 | - -#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) - for ( int i = 0; i < 256; i++ ) { - //Fill silence gaps - WaveTable[ 0x400 + i ] = WaveTable[0]; - WaveTable[ 0x500 + i ] = WaveTable[0]; - WaveTable[ 0x900 + i ] = WaveTable[0]; - WaveTable[ 0xc00 + i ] = WaveTable[0]; - WaveTable[ 0xd00 + i ] = WaveTable[0]; - //Replicate sines in other pieces - WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; - //double speed sines - WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; - WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; - WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; - WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; - } -#endif - - //Create the ksl table - for ( int oct = 0; oct < 8; oct++ ) { - int base = oct * 8; - for ( int i = 0; i < 16; i++ ) { - int val = base - KslCreateTable[i]; - if ( val < 0 ) - val = 0; - //*4 for the final range to match attenuation range - KslTable[ oct * 16 + i ] = val * 4; - } - } - //Create the Tremolo table, just increase and decrease a triangle wave - for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { - Bit8u val = i << ENV_EXTRA; - TremoloTable[i] = val; - TremoloTable[TREMOLO_TABLE - 1 - i] = val; - } - //Create a table with offsets of the channels from the start of the chip - DBOPL::Chip* chip = 0; - for ( Bitu i = 0; i < 32; i++ ) { - Bitu index = i & 0xf; - if ( index >= 9 ) { - ChanOffsetTable[i] = 0; - continue; - } - //Make sure the four op channels follow eachother - if ( index < 6 ) { - index = (index % 3) * 2 + ( index / 3 ); - } - //Add back the bits for highest ones - if ( i >= 16 ) - index += 9; - intptr_t blah = reinterpret_cast( &(chip->chan[ index ]) ); - ChanOffsetTable[i] = blah; - } - //Same for operators - for ( Bitu i = 0; i < 64; i++ ) { - if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { - OpOffsetTable[i] = 0; - continue; - } - Bitu chNum = (i / 8) * 3 + (i % 8) % 3; - //Make sure we use 16 and up for the 2nd range to match the chanoffset gap - if ( chNum >= 12 ) - chNum += 16 - 12; - Bitu opNum = ( i % 8 ) / 3; - DBOPL::Channel* chan = 0; - intptr_t blah = reinterpret_cast( &(chan->op[opNum]) ); - OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah; - } -#if 0 - //Stupid checks if table's are correct - for ( Bitu i = 0; i < 18; i++ ) { - Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); - for ( Bitu c = 0; c < 32; c++ ) { - if ( ChanOffsetTable[c] == find ) { - find = 0; - break; - } - } - if ( find ) { - find = find; - } - } - for ( Bitu i = 0; i < 36; i++ ) { - Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) ); - for ( Bitu c = 0; c < 64; c++ ) { - if ( OpOffsetTable[c] == find ) { - find = 0; - break; - } - } - if ( find ) { - find = find; - } - } -#endif -} - -/*Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { - return chip.WriteAddr( port, val ); - -} -void Handler::WriteReg( Bit32u addr, Bit8u val ) { - chip.WriteReg( addr, val ); -} - -void Handler::Generate( MixerChannel* chan, Bitu samples ) { - Bit32s buffer[ 512 * 2 ]; - if ( GCC_UNLIKELY(samples > 512) ) - samples = 512; - if ( !chip.opl3Active ) { - chip.GenerateBlock2( samples, buffer ); - chan->AddSamples_m32( samples, buffer ); - } else { - chip.GenerateBlock3( samples, buffer ); - chan->AddSamples_s32( samples, buffer ); - } -} - -void Handler::Init( Bitu rate ) { - InitTables(); - chip.Setup( rate ); -}*/ - - -}; //Namespace DBOPL - diff --git a/src/sound/dbopl.h b/src/sound/dbopl.h deleted file mode 100644 index 7507dd1a4..000000000 --- a/src/sound/dbopl.h +++ /dev/null @@ -1,259 +0,0 @@ -/* Copyright holders: The DOSBox Team - see COPYING for more details -*/ - -//#include "adlib.h" -//#include "dosbox.h" -#include -typedef signed int Bits; -typedef unsigned int Bitu; -typedef int8_t Bit8s; -typedef uint8_t Bit8u; -typedef int16_t Bit16s; -typedef uint16_t Bit16u; -typedef int32_t Bit32s; -typedef uint32_t Bit32u; - -#define INLINE inline - -#define GCC_UNLIKELY(x) (x) - -//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume -#define WAVE_HANDLER 10 -//Use a logarithmic wavetable with an exponential table for volume -#define WAVE_TABLELOG 11 -//Use a linear wavetable with a multiply table for volume -#define WAVE_TABLEMUL 12 - -//Select the type of wave generator routine -#define DBOPL_WAVE WAVE_TABLEMUL - -namespace DBOPL { - -struct Chip; -struct Operator; -struct Channel; - -#if (DBOPL_WAVE == WAVE_HANDLER) -typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); -#endif - -typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); -typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); - -//Different synth modes that can generate blocks of data -typedef enum { - sm2AM, - sm2FM, - sm3AM, - sm3FM, - sm4Start, - sm3FMFM, - sm3AMFM, - sm3FMAM, - sm3AMAM, - sm6Start, - sm2Percussion, - sm3Percussion, -} SynthMode; - -//Shifts for the values contained in chandata variable -enum { - SHIFT_KSLBASE = 16, - SHIFT_KEYCODE = 24, -}; - -struct Operator { -public: - //Masks for operator 20 values - enum { - MASK_KSR = 0x10, - MASK_SUSTAIN = 0x20, - MASK_VIBRATO = 0x40, - MASK_TREMOLO = 0x80, - }; - - typedef enum { - OFF, - RELEASE, - SUSTAIN, - DECAY, - ATTACK, - } State; - - VolumeHandler volHandler; - -#if (DBOPL_WAVE == WAVE_HANDLER) - WaveHandler waveHandler; //Routine that generate a wave -#else - Bit16s* waveBase; - Bit32u waveMask; - Bit32u waveStart; -#endif - Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index - Bit32u waveAdd; //The base frequency without vibrato - Bit32u waveCurrent; //waveAdd + vibratao - - Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this - Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? - Bit32u vibrato; //Scaled up vibrato strength - Bit32s sustainLevel; //When stopping at sustain level stop here - Bit32s totalLevel; //totalLevel is added to every generated volume - Bit32u currentLevel; //totalLevel + tremolo - Bit32s volume; //The currently active volume - - Bit32u attackAdd; //Timers for the different states of the envelope - Bit32u decayAdd; - Bit32u releaseAdd; - Bit32u rateIndex; //Current position of the evenlope - - Bit8u rateZero; //Bits for the different states of the envelope having no changes - Bit8u keyOn; //Bitmask of different values that can generate keyon - //Registers, also used to check for changes - Bit8u reg20, reg40, reg60, reg80, regE0; - //Active part of the envelope we're in - Bit8u state; - //0xff when tremolo is enabled - Bit8u tremoloMask; - //Strength of the vibrato - Bit8u vibStrength; - //Keep track of the calculated KSR so we can check for changes - Bit8u ksr; -private: - void SetState( Bit8u s ); - void UpdateAttack( const Chip* chip ); - void UpdateRelease( const Chip* chip ); - void UpdateDecay( const Chip* chip ); -public: - void UpdateAttenuation(); - void UpdateRates( const Chip* chip ); - void UpdateFrequency( ); - - void Write20( const Chip* chip, Bit8u val ); - void Write40( const Chip* chip, Bit8u val ); - void Write60( const Chip* chip, Bit8u val ); - void Write80( const Chip* chip, Bit8u val ); - void WriteE0( const Chip* chip, Bit8u val ); - - bool Silent() const; - void Prepare( const Chip* chip ); - - void KeyOn( Bit8u mask); - void KeyOff( Bit8u mask); - - template< State state> - Bits TemplateVolume( ); - - Bit32s RateForward( Bit32u add ); - Bitu ForwardWave(); - Bitu ForwardVolume(); - - Bits GetSample( Bits modulation ); - Bits GetWave( Bitu index, Bitu vol ); -public: - Operator(); -}; - -struct Channel { - Operator op[2]; - inline Operator* Op( Bitu index ) { - return &( ( this + (index >> 1) )->op[ index & 1 ]); - } - SynthHandler synthHandler; - Bit32u chanData; //Frequency/octave and derived values - Bit32s old[2]; //Old data for feedback - - Bit8u feedback; //Feedback shift - Bit8u regB0; //Register values to check for changes - Bit8u regC0; - //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel - Bit8u fourMask; - Bit8s maskLeft; //Sign extended values for both channel's panning - Bit8s maskRight; - - //Forward the channel data to the operators of the channel - void SetChanData( const Chip* chip, Bit32u data ); - //Change in the chandata, check for new values and if we have to forward to operators - void UpdateFrequency( const Chip* chip, Bit8u fourOp ); - void WriteA0( const Chip* chip, Bit8u val ); - void WriteB0( const Chip* chip, Bit8u val ); - void WriteC0( const Chip* chip, Bit8u val ); - void ResetC0( const Chip* chip ); - - //call this for the first channel - template< bool opl3Mode > - void GeneratePercussion( Chip* chip, Bit32s* output ); - - //Generate blocks of data in specific modes - template - Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); - Channel(); -}; - -struct Chip { - //This is used as the base counter for vibrato and tremolo - Bit32u lfoCounter; - Bit32u lfoAdd; - - - Bit32u noiseCounter; - Bit32u noiseAdd; - Bit32u noiseValue; - - //Frequency scales for the different multiplications - Bit32u freqMul[16]; - //Rates for decay and release for rate of this chip - Bit32u linearRates[76]; - //Best match attack rates for the rate of this chip - Bit32u attackRates[76]; - - //18 channels with 2 operators each - Channel chan[18]; - - Bit8u reg104; - Bit8u reg08; - Bit8u reg04; - Bit8u regBD; - Bit8u vibratoIndex; - Bit8u tremoloIndex; - Bit8s vibratoSign; - Bit8u vibratoShift; - Bit8u tremoloValue; - Bit8u vibratoStrength; - Bit8u tremoloStrength; - //Mask for allowed wave forms - Bit8u waveFormMask; - //0 or -1 when enabled - Bit8s opl3Active; - - int is_opl3; - - //Return the maximum amount of samples before and LFO change - Bit32u ForwardLFO( Bit32u samples ); - Bit32u ForwardNoise(); - - void WriteBD( Bit8u val ); - void WriteReg(Bit32u reg, Bit8u val ); - - Bit32u WriteAddr( Bit32u port, Bit8u val ); - - void GenerateBlock2( Bitu samples, Bit32s* output ); - void GenerateBlock3( Bitu samples, Bit32s* output ); - - void Generate( Bit32u samples ); - void Setup( Bit32u r, int chip_is_opl3 ); - - Chip(); -}; - -/*struct Handler : public Adlib::Handler { - DBOPL::Chip chip; - virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); - virtual void WriteReg( Bit32u addr, Bit8u val ); - virtual void Generate( MixerChannel* chan, Bitu samples ); - virtual void Init( Bitu rate ); -};*/ - -void InitTables( void ); - -}; //Namespace diff --git a/src/sound/nukedopl.cpp b/src/sound/nukedopl.c similarity index 94% rename from src/sound/nukedopl.cpp rename to src/sound/nukedopl.c index 0039a63bc..a2bc192c5 100644 --- a/src/sound/nukedopl.cpp +++ b/src/sound/nukedopl.c @@ -179,7 +179,7 @@ static const Bit8u ch_slot[18] = { // typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(opl3_slot *slott); +typedef void(*envelope_genfunc)(struct opl3_slot *slott); static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) { @@ -346,7 +346,7 @@ enum envelope_gen_num envelope_gen_num_release = 3 }; -static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) +static void OPL3_EnvelopeUpdateKSL(struct opl3_slot *slot) { Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); @@ -357,7 +357,7 @@ static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) slot->eg_ksl = (Bit8u)ksl; } -static void OPL3_EnvelopeCalc(opl3_slot *slot) +static void OPL3_EnvelopeCalc(struct opl3_slot *slot) { Bit8u nonzero; Bit8u rate; @@ -504,12 +504,12 @@ static void OPL3_EnvelopeCalc(opl3_slot *slot) } } -static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) +static void OPL3_EnvelopeKeyOn(struct opl3_slot *slot, Bit8u type) { slot->key |= type; } -static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) +static void OPL3_EnvelopeKeyOff(struct opl3_slot *slot, Bit8u type) { slot->key &= ~type; } @@ -518,9 +518,9 @@ static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) // Phase Generator // -static void OPL3_PhaseGenerate(opl3_slot *slot) +static void OPL3_PhaseGenerate(struct opl3_slot *slot) { - opl3_chip *chip; + struct opl3_chip *chip; Bit16u f_num; Bit32u basefreq; Bit8u rm_xor, n_bit; @@ -612,7 +612,7 @@ static void OPL3_PhaseGenerate(opl3_slot *slot) // Slot // -static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWrite20(struct opl3_slot *slot, Bit8u data) { if ((data >> 7) & 0x01) { @@ -628,20 +628,20 @@ static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) slot->reg_mult = data & 0x0f; } -static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWrite40(struct opl3_slot *slot, Bit8u data) { slot->reg_ksl = (data >> 6) & 0x03; slot->reg_tl = data & 0x3f; OPL3_EnvelopeUpdateKSL(slot); } -static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWrite60(struct opl3_slot *slot, Bit8u data) { slot->reg_ar = (data >> 4) & 0x0f; slot->reg_dr = data & 0x0f; } -static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWrite80(struct opl3_slot *slot, Bit8u data) { slot->reg_sl = (data >> 4) & 0x0f; if (slot->reg_sl == 0x0f) @@ -651,7 +651,7 @@ static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) slot->reg_rr = data & 0x0f; } -static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) +static void OPL3_SlotWriteE0(struct opl3_slot *slot, Bit8u data) { slot->reg_wf = data & 0x07; if (slot->chip->newm == 0x00) @@ -660,12 +660,12 @@ static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) } } -static void OPL3_SlotGenerate(opl3_slot *slot) +static void OPL3_SlotGenerate(struct opl3_slot *slot) { slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); } -static void OPL3_SlotCalcFB(opl3_slot *slot) +static void OPL3_SlotCalcFB(struct opl3_slot *slot) { if (slot->channel->fb != 0x00) { @@ -682,13 +682,13 @@ static void OPL3_SlotCalcFB(opl3_slot *slot) // Channel // -static void OPL3_ChannelSetupAlg(opl3_channel *channel); +static void OPL3_ChannelSetupAlg(struct opl3_channel *channel); -static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) +static void OPL3_ChannelUpdateRhythm(struct opl3_chip *chip, Bit8u data) { - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; + struct opl3_channel *channel6; + struct opl3_channel *channel7; + struct opl3_channel *channel8; Bit8u chnum; chip->rhy = data & 0x3f; @@ -776,7 +776,7 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) } } -static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) +static void OPL3_ChannelWriteA0(struct opl3_channel *channel, Bit8u data) { if (channel->chip->newm && channel->chtype == ch_4op2) { @@ -796,7 +796,7 @@ static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) } } -static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) +static void OPL3_ChannelWriteB0(struct opl3_channel *channel, Bit8u data) { if (channel->chip->newm && channel->chtype == ch_4op2) { @@ -818,7 +818,7 @@ static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) } } -static void OPL3_ChannelSetupAlg(opl3_channel *channel) +static void OPL3_ChannelSetupAlg(struct opl3_channel *channel) { if (channel->chtype == ch_drum) { @@ -919,7 +919,7 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel) } } -static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) +static void OPL3_ChannelWriteC0(struct opl3_channel *channel, Bit8u data) { channel->fb = (data & 0x0e) >> 1; channel->con = data & 0x01; @@ -958,7 +958,7 @@ static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) } } -static void OPL3_ChannelKeyOn(opl3_channel *channel) +static void OPL3_ChannelKeyOn(struct opl3_channel *channel) { if (channel->chip->newm) { @@ -982,7 +982,7 @@ static void OPL3_ChannelKeyOn(opl3_channel *channel) } } -static void OPL3_ChannelKeyOff(opl3_channel *channel) +static void OPL3_ChannelKeyOff(struct opl3_channel *channel) { if (channel->chip->newm) { @@ -1006,7 +1006,7 @@ static void OPL3_ChannelKeyOff(opl3_channel *channel) } } -static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data) +static void OPL3_ChannelSet4Op(struct opl3_chip *chip, Bit8u data) { Bit8u bit; Bit8u chnum; @@ -1043,7 +1043,7 @@ static Bit16s OPL3_ClipSample(Bit32s sample) return (Bit16s)sample; } -void OPL3_Generate(opl3_chip *chip, Bit16s *buf) +void OPL3_Generate(struct opl3_chip *chip, Bit16s *buf) { Bit8u ii; Bit8u jj; @@ -1175,7 +1175,7 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) chip->writebuf_samplecnt++; } -void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) +void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf) { while (chip->samplecnt >= chip->rateratio) { @@ -1184,19 +1184,19 @@ void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) OPL3_Generate(chip, chip->samples); chip->samplecnt -= chip->rateratio; } - buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + buf[0] = (Bit32s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + chip->samples[0] * chip->samplecnt) / chip->rateratio); - buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + buf[1] = (Bit32s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + chip->samples[1] * chip->samplecnt) / chip->rateratio); chip->samplecnt += 1 << RSM_FRAC; } -void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) +void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate) { Bit8u slotnum; Bit8u channum; - memset(chip, 0, sizeof(opl3_chip)); + memset(chip, 0, sizeof(struct opl3_chip)); for (slotnum = 0; slotnum < 36; slotnum++) { chip->slot[slotnum].chip = chip; @@ -1238,7 +1238,7 @@ void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) chip->vibshift = 1; } -Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val) +Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val) { Bit16u addr; addr = val; @@ -1248,7 +1248,7 @@ Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val) return addr; } -void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) +void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v) { Bit8u high = (reg >> 8) & 0x01; Bit8u regm = reg & 0xff; @@ -1347,7 +1347,7 @@ void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) } } -void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) +void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v) { Bit64u time1, time2; @@ -1375,7 +1375,7 @@ void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; } -void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) +void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples) { Bit32u i; diff --git a/src/sound/nukedopl.h b/src/sound/nukedopl.h index 9570298fb..6b3f09228 100644 --- a/src/sound/nukedopl.h +++ b/src/sound/nukedopl.h @@ -46,11 +46,12 @@ typedef uint64_t Bit64u; struct opl3_slot; struct opl3_channel; +struct opl3_writebuf; struct opl3_chip; struct opl3_slot { - opl3_channel *channel; - opl3_chip *chip; + struct opl3_channel *channel; + struct opl3_chip *chip; Bit16s out; Bit16s fbmod; Bit16s *mod; @@ -81,9 +82,9 @@ struct opl3_slot { }; struct opl3_channel { - opl3_slot *slots[2]; - opl3_channel *pair; - opl3_chip *chip; + struct opl3_slot *slots[2]; + struct opl3_channel *pair; + struct opl3_chip *chip; Bit16s *out[4]; Bit8u chtype; Bit16u f_num; @@ -103,8 +104,8 @@ struct opl3_writebuf { }; struct opl3_chip { - opl3_channel channel[18]; - opl3_slot slot[36]; + struct opl3_channel channel[18]; + struct opl3_slot slot[36]; Bit16u timer; Bit64u eg_timer; Bit8u eg_timerrem; @@ -137,14 +138,14 @@ struct opl3_chip { Bit32u writebuf_cur; Bit32u writebuf_last; Bit64u writebuf_lasttime; - opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; + struct opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; }; -void OPL3_Generate(opl3_chip *chip, Bit16s *buf); -void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); -void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); -Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val); -void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); +void OPL3_Generate(struct opl3_chip *chip, Bit16s *buf); +void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf); +void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate); +Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val); +void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples); #endif diff --git a/src/sound/snd_dbopl.cc b/src/sound/snd_dbopl.cc deleted file mode 100644 index 2ccc9e56c..000000000 --- a/src/sound/snd_dbopl.cc +++ /dev/null @@ -1,187 +0,0 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -#include "dbopl.h" -#include "nukedopl.h" -#include "sound.h" -#include "snd_dbopl.h" - - -int opl_type = 0; - - -static struct -{ - DBOPL::Chip chip; - opl3_chip opl3chip; - int addr; - int timer[2]; - uint8_t timer_ctrl; - uint8_t status_mask; - uint8_t status; - int is_opl3; - - void (*timer_callback)(void *param, int timer, uint64_t period); - void *timer_param; -} opl[2]; - -enum -{ - STATUS_TIMER_1 = 0x40, - STATUS_TIMER_2 = 0x20, - STATUS_TIMER_ALL = 0x80 -}; - -enum -{ - CTRL_IRQ_RESET = 0x80, - CTRL_TIMER1_MASK = 0x40, - CTRL_TIMER2_MASK = 0x20, - CTRL_TIMER2_CTRL = 0x02, - CTRL_TIMER1_CTRL = 0x01 -}; - -void opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3) -{ - opl[nr].timer_callback = timer_callback; - opl[nr].timer_param = timer_param; - opl[nr].is_opl3 = is_opl3; - - if (!opl_type) - { - DBOPL::InitTables(); - opl[nr].chip.Setup(48000, is_opl3); - } - else - { - opl[nr].opl3chip.newm = 0; - OPL3_Reset(&opl[nr].opl3chip, 48000); - } -} - -void opl_status_update(int nr) -{ - if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) - opl[nr].status |= STATUS_TIMER_ALL; - else - opl[nr].status &= ~STATUS_TIMER_ALL; -} - -void opl_timer_over(int nr, int timer) -{ - if (!timer) - { - opl[nr].status |= STATUS_TIMER_1; - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - } - else - { - opl[nr].status |= STATUS_TIMER_2; - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - } - - opl_status_update(nr); -} - -void opl_write(int nr, uint16_t addr, uint8_t val) -{ - if (!(addr & 1)) - { - if (!opl_type) - opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & 0x1ff; - else - opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; - if (!opl[nr].is_opl3) - opl[nr].addr &= 0xff; - } - else - { - if (!opl_type) - opl[nr].chip.WriteReg(opl[nr].addr, val); - else { - OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); - if (opl[nr].addr == 0x105) - opl[nr].opl3chip.newm = opl[nr].addr & 0x01; - } - - switch (opl[nr].addr) - { - case 0x02: /*Timer 1*/ - opl[nr].timer[0] = 256 - val; - break; - case 0x03: /*Timer 2*/ - opl[nr].timer[1] = 256 - val; - break; - case 0x04: /*Timer control*/ - if (val & CTRL_IRQ_RESET) /*IRQ reset*/ - { - opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); - opl_status_update(nr); - return; - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) - { - if (val & CTRL_TIMER1_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - else - opl[nr].timer_callback(opl[nr].timer_param, 0, 0); - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) - { - if (val & CTRL_TIMER2_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - else - opl[nr].timer_callback(opl[nr].timer_param, 1, 0); - } - opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; - opl[nr].timer_ctrl = val; - break; - } - } - -} - -uint8_t opl_read(int nr, uint16_t addr) -{ - if (!(addr & 1)) - { - return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); - } - return opl[nr].is_opl3 ? 0 : 0xff; -} - -void opl2_update(int nr, int16_t *buffer, int samples) -{ - int c; - Bit32s buffer_32[samples]; - - if (opl_type) - { - OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); - } - else - { - opl[nr].chip.GenerateBlock2(samples, buffer_32); - - for (c = 0; c < samples; c++) - buffer[c*2] = (int16_t)buffer_32[c]; - } -} - -void opl3_update(int nr, int16_t *buffer, int samples) -{ - int c; - Bit32s buffer_32[samples*2]; - - if (opl_type) - { - OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); - } - else - { - opl[nr].chip.GenerateBlock3(samples, buffer_32); - - for (c = 0; c < samples*2; c++) - buffer[c] = (int16_t)buffer_32[c]; - } -} diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index f89a81a04..437ea62b5 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -12,70 +12,93 @@ #include "../timer.h" #include "sound.h" #include "snd_opl.h" -#include "snd_dbopl.h" +#include "snd_opl_backend.h" /*Interfaces between 86Box and the actual OPL emulator*/ -uint8_t opl2_read(uint16_t a, void *priv) +uint8_t +opl2_read(uint16_t a, void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *opl = (opl_t *)priv; - sub_cycles((int)(isa_timing * 8)); - opl2_update2(opl); - return opl_read(0, a); -} -void opl2_write(uint16_t a, uint8_t v, void *priv) -{ - opl_t *opl = (opl_t *)priv; + sub_cycles((int) (isa_timing * 8)); + opl2_update2(opl); - opl2_update2(opl); - opl_write(0, a, v); - opl_write(1, a, v); + return opl_read(0, a); } -uint8_t opl2_l_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - sub_cycles((int)(isa_timing * 8)); - opl2_update2(opl); - return opl_read(0, a); -} -void opl2_l_write(uint16_t a, uint8_t v, void *priv) +void +opl2_write(uint16_t a, uint8_t v, void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *opl = (opl_t *)priv; - opl2_update2(opl); - opl_write(0, a, v); + opl2_update2(opl); + opl_write(0, a, v); + opl_write(1, a, v); } -uint8_t opl2_r_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - sub_cycles((int)(isa_timing * 8)); - opl2_update2(opl); - return opl_read(1, a); -} -void opl2_r_write(uint16_t a, uint8_t v, void *priv) +uint8_t +opl2_l_read(uint16_t a, void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *opl = (opl_t *)priv; - opl2_update2(opl); - opl_write(1, a, v); + sub_cycles((int)(isa_timing * 8)); + opl2_update2(opl); + + return opl_read(0, a); } -uint8_t opl3_read(uint16_t a, void *priv) -{ - opl_t *opl = (opl_t *)priv; - sub_cycles((int)(isa_timing * 8)); - opl3_update2(opl); - return opl_read(0, a); +void +opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); } -void opl3_write(uint16_t a, uint8_t v, void *priv) + + +uint8_t +opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + sub_cycles((int)(isa_timing * 8)); + opl2_update2(opl); + + return opl_read(1, a); +} + + +void +opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(1, a, v); +} + + +uint8_t +opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + sub_cycles((int)(isa_timing * 8)); + opl3_update2(opl); + + return opl_read(0, a); +} + + +void +opl3_write(uint16_t a, uint8_t v, void *priv) { opl_t *opl = (opl_t *)priv; @@ -84,93 +107,116 @@ void opl3_write(uint16_t a, uint8_t v, void *priv) } -void opl2_update2(opl_t *opl) +void +opl2_update2(opl_t *opl) { - if (opl->pos < sound_pos_global) - { - opl2_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); - opl2_update(1, &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) - { - opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); - opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); - } - } + if (opl->pos < sound_pos_global) { + opl2_update(0, &opl->buffer[opl->pos << 1], sound_pos_global - opl->pos); + opl2_update(1, &opl->buffer2[opl->pos << 1], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) { + opl->buffer[(opl->pos << 1) + 1] = opl->buffer2[(opl->pos << 1) + 1]; + opl->filtbuf[0] = opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); + opl->filtbuf[1] = opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); + } + } } -void opl3_update2(opl_t *opl) + +void +opl3_update2(opl_t *opl) { - if (opl->pos < sound_pos_global) - { - opl3_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) - { - opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); - opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); - } - } + if (opl->pos < sound_pos_global) { + opl3_update(0, &opl->buffer[(opl->pos << 1)], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) { + opl->filtbuf[0] = opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); + opl->filtbuf[1] = opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); + } + } } -void ym3812_timer_set_0(void *param, int timer, uint64_t period) -{ - opl_t *opl = (opl_t *)param; - - if (period) - timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[0][timer]); -} -void ym3812_timer_set_1(void *param, int timer, uint64_t period) -{ - opl_t *opl = (opl_t *)param; - if (period) - timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[1][timer]); +void +ym3812_timer_set_0(void *param, int timer, uint64_t period) +{ + opl_t *opl = (opl_t *)param; + + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][timer]); } -void ymf262_timer_set(void *param, int timer, uint64_t period) -{ - opl_t *opl = (opl_t *)param; - if (period) - timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[0][timer]); +void +ym3812_timer_set_1(void *param, int timer, uint64_t period) +{ + opl_t *opl = (opl_t *)param; + + if (period) + timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[1][timer]); } -static void opl_timer_callback00(void *p) + +void +ymf262_timer_set(void *param, int timer, uint64_t period) { - opl_timer_over(0, 0); -} -static void opl_timer_callback01(void *p) -{ - opl_timer_over(0, 1); -} -static void opl_timer_callback10(void *p) -{ - opl_timer_over(1, 0); -} -static void opl_timer_callback11(void *p) -{ - opl_timer_over(1, 1); -} - -void opl2_init(opl_t *opl) -{ - opl_init(ym3812_timer_set_0, opl, 0, 0); - opl_init(ym3812_timer_set_1, opl, 1, 0); - timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); - timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); - timer_add(&opl->timers[1][0], opl_timer_callback10, (void *)opl, 0); - timer_add(&opl->timers[1][1], opl_timer_callback11, (void *)opl, 0); + opl_t *opl = (opl_t *)param; + + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][timer]); } -void opl3_init(opl_t *opl) + +static void +opl_timer_callback00(void *p) { - opl_init(ymf262_timer_set, opl, 0, 1); - timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); - timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); + opl_timer_over(0, 0); } + +static void +opl_timer_callback01(void *p) +{ + opl_timer_over(0, 1); +} + + +static void +opl_timer_callback10(void *p) +{ + opl_timer_over(1, 0); +} + + +static void +opl_timer_callback11(void *p) +{ + opl_timer_over(1, 1); +} + + +void +opl2_init(opl_t *opl) +{ + opl_init(ym3812_timer_set_0, opl, 0, 0); + opl_init(ym3812_timer_set_1, opl, 1, 0); + + timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); + timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); + timer_add(&opl->timers[1][0], opl_timer_callback10, (void *)opl, 0); + timer_add(&opl->timers[1][1], opl_timer_callback11, (void *)opl, 0); +} + + +void +opl3_init(opl_t *opl) +{ + opl_init(ymf262_timer_set, opl, 0, 1); + + timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); + timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); +} diff --git a/src/sound/snd_opl.h b/src/sound/snd_opl.h index 628d8b55f..aff429e77 100644 --- a/src/sound/snd_opl.h +++ b/src/sound/snd_opl.h @@ -3,30 +3,30 @@ */ typedef struct opl_t { - int chip_nr[2]; - - pc_timer_t timers[2][2]; + int pos, chip_nr[2]; - int16_t filtbuf[2]; + int32_t filtbuf[2], + buffer[SOUNDBUFLEN * 2], + buffer2[SOUNDBUFLEN * 2]; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; + pc_timer_t timers[2][2]; } opl_t; -uint8_t opl2_read(uint16_t a, void *priv); -void opl2_write(uint16_t a, uint8_t v, void *priv); -uint8_t opl2_l_read(uint16_t a, void *priv); -void opl2_l_write(uint16_t a, uint8_t v, void *priv); -uint8_t opl2_r_read(uint16_t a, void *priv); -void opl2_r_write(uint16_t a, uint8_t v, void *priv); -uint8_t opl3_read(uint16_t a, void *priv); -void opl3_write(uint16_t a, uint8_t v, void *priv); -void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); -void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +extern uint8_t opl2_read(uint16_t a, void *priv); +extern void opl2_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t opl2_l_read(uint16_t a, void *priv); +extern void opl2_l_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t opl2_r_read(uint16_t a, void *priv); +extern void opl2_r_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t opl3_read(uint16_t a, void *priv); +extern void opl3_write(uint16_t a, uint8_t v, void *priv); -void opl2_init(opl_t *opl); -void opl3_init(opl_t *opl); +extern void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +extern void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); -void opl2_update2(opl_t *opl); -void opl3_update2(opl_t *opl); +extern void opl2_init(opl_t *opl); +extern void opl3_init(opl_t *opl); + +extern void opl2_update2(opl_t *opl); +extern void opl3_update2(opl_t *opl); diff --git a/src/sound/snd_opl_backend.c b/src/sound/snd_opl_backend.c new file mode 100644 index 000000000..0a0e08d8e --- /dev/null +++ b/src/sound/snd_opl_backend.c @@ -0,0 +1,147 @@ +/* Copyright holders: Sarah Walker, SA1988 + see COPYING for more details +*/ +#include "nukedopl.h" +#include "sound.h" +#include "snd_opl_backend.h" + + +int opl_type = 0; + + +static struct +{ + struct opl3_chip opl3chip; + int addr; + int timer[2]; + uint8_t timer_ctrl; + uint8_t status_mask; + uint8_t status; + int is_opl3; + + void (*timer_callback)(void *param, int timer, uint64_t period); + void *timer_param; +} opl[2]; + + +enum +{ + STATUS_TIMER_1 = 0x40, + STATUS_TIMER_2 = 0x20, + STATUS_TIMER_ALL = 0x80 +}; + +enum +{ + CTRL_IRQ_RESET = 0x80, + CTRL_TIMER1_MASK = 0x40, + CTRL_TIMER2_MASK = 0x20, + CTRL_TIMER2_CTRL = 0x02, + CTRL_TIMER1_CTRL = 0x01 +}; + + +void +opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3) +{ + opl[nr].timer_callback = timer_callback; + opl[nr].timer_param = timer_param; + opl[nr].is_opl3 = is_opl3; + + opl[nr].opl3chip.newm = 0; + OPL3_Reset(&opl[nr].opl3chip, 48000); +} + + +void +opl_status_update(int nr) +{ + if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) + opl[nr].status |= STATUS_TIMER_ALL; + else + opl[nr].status &= ~STATUS_TIMER_ALL; +} + + +void +opl_timer_over(int nr, int timer) +{ + if (!timer) { + opl[nr].status |= STATUS_TIMER_1; + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + } else { + opl[nr].status |= STATUS_TIMER_2; + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + } + + opl_status_update(nr); +} + + +void +opl_write(int nr, uint16_t addr, uint8_t val) +{ + if (!(addr & 1)) { + opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; + if (!opl[nr].is_opl3) + opl[nr].addr &= 0xff; + } else { + OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); + if (opl[nr].addr == 0x105) + opl[nr].opl3chip.newm = opl[nr].addr & 0x01; + + switch (opl[nr].addr) { + case 0x02: /*Timer 1*/ + opl[nr].timer[0] = 256 - val; + break; + case 0x03: /*Timer 2*/ + opl[nr].timer[1] = 256 - val; + break; + case 0x04: /*Timer control*/ + if (val & CTRL_IRQ_RESET) { /*IRQ reset*/ + opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); + opl_status_update(nr); + return; + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) { + if (val & CTRL_TIMER1_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + else + opl[nr].timer_callback(opl[nr].timer_param, 0, 0); + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) { + if (val & CTRL_TIMER2_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + else + opl[nr].timer_callback(opl[nr].timer_param, 1, 0); + } + opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; + opl[nr].timer_ctrl = val; + break; + } + } +} + + +uint8_t +opl_read(int nr, uint16_t addr) +{ + if (!(addr & 1)) + return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); + + return opl[nr].is_opl3 ? 0 : 0xff; +} + + +void +opl2_update(int nr, int32_t *buffer, int samples) +{ + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); +} + + +void +opl3_update(int nr, int32_t *buffer, int samples) +{ + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); +} diff --git a/src/sound/snd_dbopl.h b/src/sound/snd_opl_backend.h similarity index 77% rename from src/sound/snd_dbopl.h rename to src/sound/snd_opl_backend.h index e95a2becd..24120d036 100644 --- a/src/sound/snd_dbopl.h +++ b/src/sound/snd_opl_backend.h @@ -8,8 +8,8 @@ extern "C" { void opl_write(int nr, uint16_t addr, uint8_t val); uint8_t opl_read(int nr, uint16_t addr); void opl_timer_over(int nr, int timer); - void opl2_update(int nr, int16_t *buffer, int samples); - void opl3_update(int nr, int16_t *buffer, int samples); + void opl2_update(int nr, int32_t *buffer, int samples); + void opl3_update(int nr, int32_t *buffer, int samples); extern int opl_type; #ifdef __cplusplus diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index b16078467..b927e54e4 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -33,7 +33,6 @@ #include "../device.h" #include "sound.h" #include "filters.h" -#include "snd_dbopl.h" #include "snd_emu8k.h" #include "snd_mpu401.h" #include "snd_opl.h" @@ -203,7 +202,7 @@ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { int32_t out = 0; if (sb->opl_enabled) - out = ((sb->opl.buffer[c] * 51000) >> 16); + out = ((sb->opl.buffer[c] * (sb->opl_emu ? 47000 : 51000)) >> 16); //TODO: Recording: Mic and line In with AGC out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * 65536) / 3) >> 16; @@ -231,7 +230,7 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) int32_t out = 0; if (sb->opl_enabled) - out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * 51000) >> 15); + out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); /* TODO: Recording : I assume it has direct mic and line in like sb2 */ /* It is unclear from the docs if it has a filter, but it probably does */ out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice) / 3) >> 15; diff --git a/src/win/86Box.rc b/src/win/86Box.rc index d9f73af4b..294e813b9 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)86Box.rc 1.0.55 2019/12/05 + * Version: @(#)86Box.rc 1.0.56 2019/12/21 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -391,11 +391,8 @@ BEGIN CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 - CONTROL "Use Nuked OPL",IDC_CHECK_NUKEDOPL,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,81,94,10 - CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,147,81,94,10 END DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 @@ -903,7 +900,6 @@ BEGIN IDS_2120 "Unable to initialize SDL, SDL2.dll is required" IDS_2121 "Are you sure you want to hard reset the emulated machine?" IDS_2122 "Are you sure you want to quit 86Box?" - IDS_2123 "Unable to initialize Ghostscript, gsdll32.dll is required for automatic convertion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript files (.ps)." END STRINGTABLE DISCARDABLE diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index a05863a35..79647a697 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.139 2019/12/05 +# Version: @(#)Makefile.mingw 1.0.140 2019/12/21 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -604,7 +604,7 @@ HDDOBJ := hdd.o \ hdc_ide_sff8038i.o CDROMOBJ := cdrom.o \ - cdrom_dosbox.o cdrom_image.o + cdrom_image_backend.o cdrom_image.o ZIPOBJ := zip.o @@ -633,8 +633,8 @@ PRINTOBJ := png.o prt_cpmap.o \ SNDOBJ := sound.o \ openal.o \ - snd_opl.o snd_dbopl.o \ - dbopl.o nukedopl.o \ + snd_opl.o snd_opl_backend.o \ + nukedopl.o \ snd_resid.o \ convolve.o convolve-sse.o envelope.o extfilt.o \ filter.o pot.o sid.o voice.o wave6581__ST.o \ @@ -691,12 +691,8 @@ VIDOBJ := video.o \ PLATOBJ := win.o \ win_dynld.o win_thread.o \ win_cdrom.o win_keyboard.o \ - win_midi.o -ifeq ($(DINPUT), y) - PLATOBJ += win_mouse.o win_joystick.o -else - PLATOBJ += win_mouse_rawinput.o win_joystick.o -endif + win_midi.o \ + win_mouse.o win_joystick.o OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw index fa175ca60..560d6fdbb 100644 --- a/src/win/Makefile_ndr.mingw +++ b/src/win/Makefile_ndr.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.139 2019/12/05 +# Version: @(#)Makefile.mingw 1.0.140 2019/12/21 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -610,7 +610,7 @@ HDDOBJ := hdd.o \ hdc_ide_sff8038i.o CDROMOBJ := cdrom.o \ - cdrom_dosbox.o cdrom_image.o + cdrom_image_backend.o cdrom_image.o ZIPOBJ := zip.o @@ -639,8 +639,8 @@ PRINTOBJ := png.o prt_cpmap.o \ SNDOBJ := sound.o \ openal.o \ - snd_opl.o snd_dbopl.o \ - dbopl.o nukedopl.o \ + snd_opl.o snd_opl_backend.o \ + nukedopl.o \ snd_resid.o \ convolve.o convolve-sse.o envelope.o extfilt.o \ filter.o pot.o sid.o voice.o wave6581__ST.o \ @@ -697,12 +697,8 @@ VIDOBJ := video.o \ PLATOBJ := win.o \ win_dynld.o win_thread.o \ win_cdrom.o win_keyboard.o \ - win_midi.o -ifeq ($(DINPUT), y) - PLATOBJ += win_mouse.o win_joystick.o -else - PLATOBJ += win_mouse_rawinput.o win_joystick.o -endif + win_midi.o \ + win_mouse.o win_joystick.o OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ diff --git a/src/win/resource.h b/src/win/resource.h index 4922df81b..e34f6a1be 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -8,7 +8,7 @@ * * Windows resource defines. * - * Version: @(#)resource.h 1.0.31 2019/12/05 + * Version: @(#)resource.h 1.0.32 2019/12/21 * * Authors: Sarah Walker, * Miran Grca, @@ -144,12 +144,11 @@ #define IDC_CHECK_SSI 1072 #define IDC_CHECK_CMS 1073 #define IDC_CHECK_GUS 1074 -#define IDC_CHECK_NUKEDOPL 1075 -#define IDC_COMBO_MIDI 1076 -#define IDC_CHECK_MPU401 1077 -#define IDC_CONFIGURE_MPU401 1078 -#define IDC_CHECK_FLOAT 1079 -#define IDC_CHECK_GUSMAX 1080 +#define IDC_COMBO_MIDI 1075 +#define IDC_CHECK_MPU401 1076 +#define IDC_CONFIGURE_MPU401 1077 +#define IDC_CHECK_FLOAT 1078 +#define IDC_CHECK_GUSMAX 1079 #define IDC_COMBO_NET_TYPE 1090 /* network config */ #define IDC_COMBO_PCAP 1091 diff --git a/src/win/win_mouse_rawinput.cpp b/src/win/win_mouse.c similarity index 98% rename from src/win/win_mouse_rawinput.cpp rename to src/win/win_mouse.c index fc983d24d..2ca004e9f 100644 --- a/src/win/win_mouse_rawinput.cpp +++ b/src/win/win_mouse.c @@ -63,8 +63,9 @@ win_mouse_handle(LPARAM lParam, int infocus) uint32_t ri_size = 0; UINT size; RAWINPUT *raw; - RAWMOUSE state; - + RAWMOUSE state; + static int x, y; + if (! infocus) return; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, @@ -109,7 +110,7 @@ win_mouse_handle(LPARAM lParam, int infocus) * seems to work fine for RDP on Windows 10 * Not sure about other environments. */ - static int x=state.lLastX, y=state.lLastY; + x=state.lLastX, y=state.lLastY; mousestate.dx += (state.lLastX - x)/100; mousestate.dy += (state.lLastY - y)/100; x=state.lLastX; diff --git a/src/win/win_mouse.cpp b/src/win/win_mouse.cpp deleted file mode 100644 index a57969196..000000000 --- a/src/win/win_mouse.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Mouse interface to host device. - * - * Version: @(#)win_mouse.cpp 1.0.6 2017/11/25 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. - */ -#define DIRECTINPUT_VERSION 0x0800 -#include -#include -#include -#include "../86box.h" -#include "../mouse.h" -#include "../plat.h" -#include "win.h" - - -int mouse_capture; - - -static LPDIRECTINPUT8 lpdi; -static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; -static DIMOUSESTATE mousestate; - - -void -win_mouse_init(void) -{ - atexit(win_mouse_close); - - mouse_capture = 0; - - if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, - IID_IDirectInput8A, (void **) &lpdi, NULL))) - fatal("plat_mouse_init: DirectInputCreate failed\n"); - - if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL))) - fatal("plat_mouse_init: CreateDevice failed\n"); - - if (FAILED(lpdi_mouse->SetCooperativeLevel(hwndMain, - DISCL_FOREGROUND | (video_fullscreen ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE)))) - fatal("plat_mouse_init: SetCooperativeLevel failed\n"); - - if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) - fatal("plat_mouse_init: SetDataFormat failed\n"); -} - - -void -win_mouse_close(void) -{ - if (lpdi_mouse != NULL) { - lpdi_mouse->Release(); - lpdi_mouse = NULL; - } -} - - -void -mouse_poll(void) -{ - static int buttons = 0; - static int x = 0, y = 0, z = 0; - int b; - - if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), - (LPVOID)&mousestate))) { - lpdi_mouse->Acquire(); - lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); - } - - if (mouse_capture || video_fullscreen) { - if (x != mousestate.lX || y != mousestate.lY || z != mousestate.lZ) { - mouse_x += mousestate.lX; - mouse_y += mousestate.lY; - mouse_z += mousestate.lZ/120; - - x = mousestate.lX; - y = mousestate.lY; - z = mousestate.lZ/120; - } - - b = 0; - if (mousestate.rgbButtons[0] & 0x80) b |= 1; - if (mousestate.rgbButtons[1] & 0x80) b |= 2; - if (mousestate.rgbButtons[2] & 0x80) b |= 4; - if (buttons != b) { - mouse_buttons = b; - buttons = b; - } - } -} diff --git a/src/win/win_settings.c b/src/win/win_settings.c index ed6747d5a..f2a716a8c 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.62 2019/11/19 + * Version: @(#)win_settings.c 1.0.63 2019/12/21 * * Authors: Miran Grca, * David Hrdlička, @@ -55,7 +55,6 @@ #include "../network/network.h" #include "../sound/sound.h" #include "../sound/midi.h" -#include "../sound/snd_dbopl.h" #include "../sound/snd_mpu401.h" #include "../video/video.h" #include "../video/vid_voodoo.h" @@ -85,7 +84,7 @@ static int temp_gfxcard, temp_voodoo; static int temp_mouse, temp_joystick; /* Sound category */ -static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl_type; +static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS; static int temp_float; /* Network category */ @@ -223,7 +222,6 @@ win_settings_init(void) temp_SSI2001 = SSI2001; temp_GAMEBLASTER = GAMEBLASTER; temp_GUS = GUS; - temp_opl_type = opl_type; temp_float = sound_is_float; /* Network category */ @@ -335,7 +333,6 @@ win_settings_changed(void) i = i || (SSI2001 != temp_SSI2001); i = i || (GAMEBLASTER != temp_GAMEBLASTER); i = i || (GUS != temp_GUS); - i = i || (opl_type != temp_opl_type); i = i || (sound_is_float != temp_float); /* Network category */ @@ -438,7 +435,6 @@ win_settings_save(void) SSI2001 = temp_SSI2001; GAMEBLASTER = temp_GAMEBLASTER; GUS = temp_GUS; - opl_type = temp_opl_type; sound_is_float = temp_float; /* Network category */ @@ -1215,9 +1211,6 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h=GetDlgItem(hdlg, IDC_CHECK_SSI); SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); - h=GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); - SendMessage(h, BM_SETCHECK, temp_opl_type, 0); - h=GetDlgItem(hdlg, IDC_CHECK_FLOAT); SendMessage(h, BM_SETCHECK, temp_float, 0); @@ -1311,9 +1304,6 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_CHECK_SSI); temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); - temp_opl_type = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_CHECK_FLOAT); temp_float = SendMessage(h, BM_GETCHECK, 0, 0);