#include #include #include #include #include #include #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; }