#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#define PI 3.1415926535897932384626433832795
#define OPK_NbRegs 256
#define OPK_NbCanaux 8
#define OPK_DureeAttaque 0.005
#define OPK_DureeRelach 0.005
#define Entree_FreqEvts 184594
#define Entree_FreqHorl 55958
#define Sortie_FreqEch 48000
struct
{
double Alpha;
double Amplitude;
}
OPK_Canal[OPK_NbCanaux];
uint8_t OPK_Reg[OPK_NbRegs];
const uint8_t OPK_FlagsMod[OPK_NbRegs] = {0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D};
const uint8_t OPK_FlagsCar[OPK_NbRegs] = {0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F};
const uint8_t OPK_FreqMSB[OPK_NbRegs] = {0x52, 0x53, 0x56, 0x57, 0x5A, 0x5B, 0x5E, 0x5F};
const uint8_t OPK_FreqLSB[OPK_NbRegs] = {0x62, 0x63, 0x66, 0x67, 0x6A, 0x6B, 0x6E, 0x6F};
FILE *Entree_Fichier;
FILE *Sortie_Fichier;
void OPK_Init(void)
{
for (uint32_t i = 0; i < OPK_NbRegs; i++)
{
OPK_Reg[i] = 0;
}
for (uint32_t i = 0; i < OPK_NbCanaux; i++)
{
OPK_Canal[i].Alpha = 0.0;
OPK_Canal[i].Amplitude = 0.0;
}
}
void OPK_EcritureReg(uint8_t NumReg, uint8_t Valeur)
{
switch (NumReg >> 4)
{
case 0x5:
case 0x6:
NumReg &= ~2;
OPK_Reg[NumReg] = Valeur;
OPK_Reg[NumReg | 2] = Valeur;
break;
default:
OPK_Reg[NumReg] = Valeur;
break;
}
}
void Entree_Init(const char *NomFichier)
{
Entree_Fichier = fopen(NomFichier, "rb");
assert(Entree_Fichier != NULL);
assert(fseek(Entree_Fichier, 2, SEEK_CUR) == 0);
}
void Entree_Deinit(void)
{
assert(fclose(Entree_Fichier) == 0);
}
bool Entree_LectureEvt(uint32_t *Duree)
{
uint8_t buf[4];
if (fread(buf, sizeof(buf), 1, Entree_Fichier) != 1) return false;
OPK_EcritureReg(buf[0], buf[1]);
*Duree = buf[2];
*Duree <<= 8;
*Duree |= buf[3];
return true;
}
void Sortie_Init(const char *NomFichier)
{
Sortie_Fichier = fopen(NomFichier, "wb");
assert(Sortie_Fichier != NULL);
}
void Sortie_Deinit(void)
{
assert(fclose(Sortie_Fichier) == 0);
}
void Sortie_Synthese(uint32_t NbEchs)
{
while (NbEchs--)
{
double EchSortie = 0.0;
for (uint32_t i = 0; i <= OPK_NbCanaux; i++)
{
double Alpha = OPK_Canal[i].Alpha;
double Amplitude = OPK_Canal[i].Amplitude;
EchSortie += sin(2.0 * PI * Alpha) * Amplitude;
{
double FreqNote;
{
uint16_t Tmp;
Tmp = OPK_Reg[OPK_FreqMSB[i]];
Tmp <<= 8;
Tmp |= OPK_Reg[OPK_FreqLSB[i]];
FreqNote = ((Tmp >> 4) & 0x1FF) << (Tmp >> 13);
FreqNote *= Entree_FreqHorl / pow(2.0, 19);
}
Alpha += FreqNote / Sortie_FreqEch;
Alpha -= floor(Alpha);
}
if (OPK_Reg[OPK_FlagsCar[i]] & 0x80)
{
Amplitude += 1.0 / (OPK_DureeAttaque * ((double)Sortie_FreqEch));
if (Amplitude > 1.0) Amplitude = 1.0;
}
else
{
Amplitude -= 1.0 / (OPK_DureeRelach * ((double)Sortie_FreqEch));
if (Amplitude < 0.0) Amplitude = 0.0;
}
OPK_Canal[i].Alpha = Alpha;
OPK_Canal[i].Amplitude = Amplitude;
}
EchSortie /= OPK_NbCanaux;
{
int16_t Tmp = EchSortie * 32767.0;
assert(fwrite(&Tmp, sizeof(Tmp), 1, Sortie_Fichier) == 1);
}
}
}
int main(void)
{
OPK_Init();
Entree_Init("pss26_demo_song_full_length.bin");
Sortie_Init("pss26_demo_song_full_length.raw");
{
uint32_t Duree;
while (Entree_LectureEvt(&Duree))
{
double NbEchs;
NbEchs = Duree;
NbEchs /= Entree_FreqEvts;
NbEchs *= Sortie_FreqEch;
Sortie_Synthese(floor(NbEchs + 0.5));
}
}
Sortie_Deinit();
Entree_Deinit();
return 0;
}