]> Shamusworld >> Repos - thunder/blobdiff - src/psg.cpp
Thunder now works with NO samples! \o/
[thunder] / src / psg.cpp
diff --git a/src/psg.cpp b/src/psg.cpp
new file mode 100644 (file)
index 0000000..b4f3f47
--- /dev/null
@@ -0,0 +1,209 @@
+//
+// PSG handler
+//
+// This emulates the Rolling Thunder PSG (Namco CUS30)
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who  When        What
+// ---  ----------  -----------------------------------------------------------
+// JLH  04/21/2014  Created this file.
+//
+
+#include "psg.h"
+#include <stdio.h>
+#include <string.h>
+
+
+struct Voice
+{
+       uint8_t leftVolume;
+       uint8_t rightVolume;
+       uint8_t waveform;
+       uint32_t frequency;
+       uint32_t counter;
+       bool noise;
+       uint32_t noiseSeed;
+};
+
+static Voice voice[8];
+static uint8_t memory[0x200];
+//static 
+static uint32_t sampleRate = 44100;
+
+extern FILE * psg1;
+extern FILE * psg2;
+
+
+void InitPSG(uint32_t s/*=44100*/)
+{
+       sampleRate = s;
+
+       for(int i=0; i<8; i++)
+               voice[i].noiseSeed = 1;
+}
+
+
+void UpdatePSG(uint8_t * buffer, int count)
+{
+/*
+if F == 44100, then counter++ for each sample.
+if F == 88200, then counter += 2 for each sample.
+if F == 22050, then counter += 0.5 for each sample.
+*/
+//     memset(buffer, 0, count * 2);
+
+       // Recast buffer as int16, we're doing 16-bit sound here
+       int16_t * p = (int16_t *)buffer;
+
+       for(int i=0; i<8; i++)
+       {
+               if (!voice[i].noise)
+               {
+                       if ((voice[i].leftVolume == 0) || (voice[i].frequency == 0))
+                               continue;
+
+                       for(int j=0; j<count; j++)
+                       {
+//                             uint8_t pos = (voice[i].counter / (sampleRate * 2)) & 0x1F;
+// Where does 60000 come from? IDK. This would probably change depending on
+// the playback rate (currently, 44100). N.B.: 58800 is a hair too high in pitch!
+// 44100 / 60000 = 0.735
+// 192000 / 60000 = 3.2
+//                             uint8_t pos = (voice[i].counter / (60000)) & 0x1F;
+                               uint8_t pos = (voice[i].counter / (65536)) & 0x1F;
+                               uint8_t sample = ((pos & 0x01) == 0
+                                       ? memory[(voice[i].waveform * 16) + (pos / 2)] >> 4
+                                       : memory[(voice[i].waveform * 16) + (pos / 2)]) & 0x0F;
+//                             p[j] += (((memory[(voice[i].waveform * 32) + pos] & 0x0F) - 8)
+//                                     * voice[i].leftVolume) << 5;
+                               p[j] += ((sample - 8) * voice[i].leftVolume) << 5;
+                               voice[i].counter += voice[i].frequency;
+                       }
+               }
+               else
+               {
+                       if ((voice[i].leftVolume == 0) || ((voice[i].frequency & 0xFF) == 0))
+                               continue;
+
+                       int16_t sample = (7 * voice[i].leftVolume) << 4;
+                       int16_t noiseSign = 1;
+                       int16_t hold = 1 << 1;
+
+                       for(int j=0; j<count; j++)
+                       {
+                               p[j] += sample * noiseSign;
+#if 0
+if (i == 1)
+{
+       fputc(sample & 0xFF, psg1);
+       fputc((sample >> 8) & 0xFF , psg1);
+}
+else if (i == 3)
+{
+       fputc(sample & 0xFF, psg2);
+       fputc((sample >> 8) & 0xFF , psg2);
+}
+#endif
+
+                               if (hold)
+                               {
+                                       hold--;
+                                       continue;
+                               }
+
+                               hold = 1 << 1;
+
+                               voice[i].counter += (voice[i].frequency & 0xFF) << 4;
+                               int c = voice[i].counter >> 12;
+                               voice[i].counter &= 0xFFF;
+
+                               for(; c>0; c--)
+                               {
+                                       if ((voice[i].noiseSeed + 1) & 0x02)
+                                               noiseSign *= -1;
+
+                                       if (voice[i].noiseSeed & 0x01)
+                                               voice[i].noiseSeed ^= 0x28000;
+
+                                       voice[i].noiseSeed >>= 1;
+                               }
+                       }
+               }
+       }
+}
+
+
+void WritePSG(uint16_t address, uint8_t data)
+{
+       if ((address >= 0x100) && (address <= 0x13F))
+       {
+               uint8_t channel = (address - 0x100) / 8;
+               uint8_t knob = (address - 0x100) - (channel * 8);
+
+               if (channel < 8)
+               {
+                       switch (knob)
+                       {
+                       case 0:
+                               voice[channel].leftVolume = data & 0x0F;
+                               break;
+                       case 1:
+                               voice[channel].waveform = data >> 4;
+                               voice[channel].frequency = ((data & 0x0F) << 16) 
+                                       | (voice[channel].frequency & 0x0FFFF);
+#if 0
+printf("PSG: Setting waveform on channel %i to %i...\n", channel, voice[channel].waveform);
+#endif
+                               break;
+                       case 2:
+                               voice[channel].frequency = (data << 8)
+                                       | (voice[channel].frequency & 0xF00FF);
+                               break;
+                       case 3:
+                               voice[channel].frequency = data
+                                       | (voice[channel].frequency & 0xFFF00);
+                               break;
+                       case 4:
+                               voice[channel].rightVolume = data & 0x0F;
+                               // Noise switch is channel # + 1 (wraps to zero)
+                               voice[(channel + 1) & 0x07].noise = (data & 0x80 ? true : false);
+#if 0
+if (voice[(channel + 1) & 0x07].noise)
+{
+       uint8_t ch = (channel + 1) & 0x07;
+       printf("PSG: Setting noise on channel %i, vol=%i, freq=%i...\n", ch, voice[ch].leftVolume, voice[ch].frequency);
+}
+#endif
+#if 0
+if (data & 0x0F)
+{
+       printf("PSG: Setting right volume on channel %i: vol=%i...\n", channel, voice[channel].rightVolume);
+}
+#endif
+                               break;
+                       }
+               }
+
+//             return;
+       }
+#if 0
+       else
+               printf("PSG: Write to $%03X of $%02X...\n", address, data);
+#endif
+
+//if (address < 0x100)
+//     printf("PSG: Waveform byte[$%02X] = $%02X...\n", address, data);
+
+       memory[address & 0x01FF] = data;
+}
+
+
+uint8_t ReadPSG(uint16_t address)
+{
+       return memory[address & 0x01FF];
+}
+