fine, here's your Pong

This commit is contained in:
tildearrow 2022-10-24 03:19:42 -05:00
parent 6ceac62015
commit 4acb6ccc09
8 changed files with 373 additions and 0 deletions

View file

@ -515,6 +515,7 @@ src/engine/platform/zxbeeper.cpp
src/engine/platform/bubsyswsg.cpp src/engine/platform/bubsyswsg.cpp
src/engine/platform/n163.cpp src/engine/platform/n163.cpp
src/engine/platform/pet.cpp src/engine/platform/pet.cpp
src/engine/platform/pong.cpp
src/engine/platform/vic20.cpp src/engine/platform/vic20.cpp
src/engine/platform/vrc6.cpp src/engine/platform/vrc6.cpp
src/engine/platform/scc.cpp src/engine/platform/scc.cpp

View file

@ -265,6 +265,7 @@ size | description
| - 0xc5: YM2610B CSM - 20 channels | - 0xc5: YM2610B CSM - 20 channels
| - 0xde: YM2610B extended - 19 channels | - 0xde: YM2610B extended - 19 channels
| - 0xe0: QSound - 19 channels | - 0xe0: QSound - 19 channels
| - 0xfc: Pong - 1 channel
| - 0xfd: Dummy System - 8 channels | - 0xfd: Dummy System - 8 channels
| - 0xfe: reserved for development | - 0xfe: reserved for development
| - 0xff: reserved for development | - 0xff: reserved for development

View file

@ -60,6 +60,7 @@
#include "platform/bubsyswsg.h" #include "platform/bubsyswsg.h"
#include "platform/n163.h" #include "platform/n163.h"
#include "platform/pet.h" #include "platform/pet.h"
#include "platform/pong.h"
#include "platform/vic20.h" #include "platform/vic20.h"
#include "platform/vrc6.h" #include "platform/vrc6.h"
#include "platform/fds.h" #include "platform/fds.h"
@ -365,6 +366,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
case DIV_SYSTEM_VIC20: case DIV_SYSTEM_VIC20:
dispatch=new DivPlatformVIC20; dispatch=new DivPlatformVIC20;
break; break;
case DIV_SYSTEM_PONG:
dispatch=new DivPlatformPong;
break;
case DIV_SYSTEM_VRC6: case DIV_SYSTEM_VRC6:
dispatch=new DivPlatformVRC6; dispatch=new DivPlatformVRC6;
break; break;

View file

@ -0,0 +1,267 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "pong.h"
#include "../engine.h"
#include "../../ta-log.h"
#define CHIP_DIVIDER 16
void DivPlatformPong::acquire(short* bufL, short* bufR, size_t start, size_t len) {
int out=0;
for (size_t i=start; i<start+len; i++) {
if (on) {
if (--pos<=0) {
pos=(freq?2:1)<<4;
flip=!flip;
}
out=(flip && !isMuted[0])?32767:0;
bufL[i]=out;
oscBuf->data[oscBuf->needle++]=out;
} else {
bufL[i]=0;
oscBuf->data[oscBuf->needle++]=0;
flip=false;
}
}
}
void DivPlatformPong::tick(bool sysTick) {
for (int i=0; i<1; i++) {
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol && chan[i].std.vol.val);
on=chan[i].outVol;
}
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
}
chan[i].freqChanged=true;
}
if (sysTick) {
flip=false;
pos=0;
}
if (chan[i].std.pitch.had) {
if (chan[i].std.pitch.mode) {
chan[i].pitch2+=chan[i].std.pitch.val;
CLAMP_VAR(chan[i].pitch2,-32768,32767);
} else {
chan[i].pitch2=chan[i].std.pitch.val;
}
chan[i].freqChanged=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER)-1;
if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>1) chan[i].freq=1;
if (chan[i].keyOn) {
on=true;
}
if (chan[i].keyOff) {
on=false;
}
freq=chan[i].freq;
if (chan[i].keyOn) chan[i].keyOn=false;
if (chan[i].keyOff) chan[i].keyOff=false;
chan[i].freqChanged=false;
}
}
}
int DivPlatformPong::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
chan[c.chan].keyOff=true;
chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
case DIV_CMD_ENV_RELEASE:
chan[c.chan].std.release();
break;
case DIV_CMD_INSTRUMENT:
if (chan[c.chan].ins!=c.value || c.value2==1) {
chan[c.chan].ins=c.value;
}
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) {
on=chan[c.chan].vol;
}
}
break;
case DIV_CMD_GET_VOLUME:
return chan[c.chan].vol;
break;
case DIV_CMD_PITCH:
chan[c.chan].pitch=c.value;
chan[c.chan].freqChanged=true;
break;
case DIV_CMD_NOTE_PORTA: {
int destFreq=NOTE_PERIODIC(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value;
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value;
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
}
chan[c.chan].freqChanged=true;
if (return2) {
chan[c.chan].inPorta=false;
return 2;
}
break;
}
case DIV_CMD_LEGATO:
if (c.chan==3) break;
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:
return 1;
break;
case DIV_ALWAYS_SET_VOLUME:
return 1;
break;
default:
break;
}
return 1;
}
void DivPlatformPong::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
}
void DivPlatformPong::forceIns() {
for (int i=0; i<1; i++) {
chan[i].insChanged=true;
}
}
void* DivPlatformPong::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformPong::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivDispatchOscBuffer* DivPlatformPong::getOscBuffer(int ch) {
return oscBuf;
}
void DivPlatformPong::reset() {
for (int i=0; i<1; i++) {
chan[i]=DivPlatformPong::Channel();
chan[i].std.setEngine(parent);
}
if (dumpWrites) {
addWrite(0xffffffff,0);
}
on=false;
lastOn=false;
freq=0;
pos=0;
flip=false;
memset(regPool,0,2);
}
bool DivPlatformPong::keyOffAffectsArp(int ch) {
return true;
}
void DivPlatformPong::setFlags(const DivConfig& flags) {
chipClock=15625;
rate=chipClock;
oscBuf->rate=rate;
}
void DivPlatformPong::notifyInsDeletion(void* ins) {
for (int i=0; i<1; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
}
void DivPlatformPong::poke(unsigned int addr, unsigned short val) {
// ???
}
void DivPlatformPong::poke(std::vector<DivRegWrite>& wlist) {
// ???
}
int DivPlatformPong::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p;
dumpWrites=false;
skipRegisterWrites=false;
for (int i=0; i<1; i++) {
isMuted[i]=false;
}
oscBuf=new DivDispatchOscBuffer;
setFlags(flags);
reset();
return 5;
}
void DivPlatformPong::quit() {
delete oscBuf;
}
DivPlatformPong::~DivPlatformPong() {
}

View file

@ -0,0 +1,89 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _PONG_H
#define _PONG_H
#include "../dispatch.h"
#include "../macroInt.h"
class DivPlatformPong: public DivDispatch {
struct Channel {
int freq, baseFreq, pitch, pitch2, note, ins;
unsigned char duty, sweep;
bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
signed char vol, outVol, wave;
DivMacroInt std;
void macroInit(DivInstrument* which) {
std.init(which);
pitch2=0;
}
Channel():
freq(0),
baseFreq(0),
pitch(0),
pitch2(0),
note(0),
ins(-1),
duty(0),
sweep(8),
active(false),
insChanged(true),
freqChanged(false),
sweepChanged(false),
keyOn(false),
keyOff(false),
inPorta(false),
furnaceDac(false),
vol(1),
outVol(1),
wave(-1) {}
};
Channel chan[1];
DivDispatchOscBuffer* oscBuf;
bool isMuted[1];
bool on, flip, lastOn;
int pos;
bool freq;
unsigned char regPool[2];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
public:
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void setFlags(const DivConfig& flags);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void quit();
~DivPlatformPong();
};
#endif

View file

@ -117,6 +117,7 @@ enum DivSystem {
DIV_SYSTEM_MSM5232, DIV_SYSTEM_MSM5232,
DIV_SYSTEM_T6W28, DIV_SYSTEM_T6W28,
DIV_SYSTEM_PCM_DAC, DIV_SYSTEM_PCM_DAC,
DIV_SYSTEM_PONG,
DIV_SYSTEM_DUMMY DIV_SYSTEM_DUMMY
}; };

View file

@ -1102,6 +1102,15 @@ void DivEngine::registerSystems() {
{DIV_INS_BEEPER} {DIV_INS_BEEPER}
); );
sysDefs[DIV_SYSTEM_PONG]=new DivSysDef(
"Pong", NULL, 0xfc, 0, 1, false, true, 0, false, 0,
"LOL",
{"Square"},
{"SQ"},
{DIV_CH_PULSE},
{DIV_INS_BEEPER}
);
sysDefs[DIV_SYSTEM_POKEY]=new DivSysDef( sysDefs[DIV_SYSTEM_POKEY]=new DivSysDef(
"POKEY", NULL, 0x94, 0, 4, false, true, 0, false, 0, "POKEY", NULL, 0x94, 0, 4, false, true, 0, false, 0,
"TIA, but better and more flexible.\nused in the Atari 8-bit family of computers (400/800/XL/XE).", "TIA, but better and more flexible.\nused in the Atari 8-bit family of computers (400/800/XL/XE).",

View file

@ -960,6 +960,7 @@ const int availableSystems[]={
DIV_SYSTEM_SNES, DIV_SYSTEM_SNES,
DIV_SYSTEM_MSM5232, DIV_SYSTEM_MSM5232,
DIV_SYSTEM_PCM_DAC, DIV_SYSTEM_PCM_DAC,
DIV_SYSTEM_PONG,
0 // don't remove this last one! 0 // don't remove this last one!
}; };