001: #include <stdio.h>
002: #include <stdlib.h>
003: #include <inttypes.h>
004: #include <stdbool.h>
005: #include <assert.h>
006: #include <math.h>
007:
008: #define PI 3.1415926535897932384626433832795
009:
010: #define OPK_NbRegs 256
011: #define OPK_NbCanaux 8
012: #define OPK_DureeAttaque 0.005
013: #define OPK_DureeRelach 0.005
014:
015: #define Entree_FreqEvts 184594
016: #define Entree_FreqHorl 55958
017: #define Sortie_FreqEch 48000
018:
019:
020: struct
021: {
022: double Alpha;
023: double Amplitude;
024: }
025: OPK_Canal[OPK_NbCanaux];
026:
027: uint8_t OPK_Reg[OPK_NbRegs];
028: const uint8_t OPK_FlagsMod[OPK_NbRegs] = {0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D};
029: const uint8_t OPK_FlagsCar[OPK_NbRegs] = {0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F};
030: const uint8_t OPK_FreqMSB[OPK_NbRegs] = {0x52, 0x53, 0x56, 0x57, 0x5A, 0x5B, 0x5E, 0x5F};
031: const uint8_t OPK_FreqLSB[OPK_NbRegs] = {0x62, 0x63, 0x66, 0x67, 0x6A, 0x6B, 0x6E, 0x6F};
032:
033:
034: FILE *Entree_Fichier;
035: FILE *Sortie_Fichier;
036:
037:
038: void OPK_Init(void)
039: {
040: for (uint32_t i = 0; i < OPK_NbRegs; i++)
041: {
042: OPK_Reg[i] = 0;
043: }
044:
045: for (uint32_t i = 0; i < OPK_NbCanaux; i++)
046: {
047: OPK_Canal[i].Alpha = 0.0;
048: OPK_Canal[i].Amplitude = 0.0;
049: }
050: }
051:
052:
053: void OPK_EcritureReg(uint8_t NumReg, uint8_t Valeur)
054: {
055: switch (NumReg >> 4)
056: {
057: case 0x5:
058: case 0x6:
059: NumReg &= ~2;
060: OPK_Reg[NumReg] = Valeur;
061: OPK_Reg[NumReg | 2] = Valeur;
062: break;
063:
064: default:
065: OPK_Reg[NumReg] = Valeur;
066: break;
067: }
068: }
069:
070:
071: void Entree_Init(const char *NomFichier)
072: {
073: Entree_Fichier = fopen(NomFichier, "rb");
074: assert(Entree_Fichier != NULL);
075:
076: assert(fseek(Entree_Fichier, 2, SEEK_CUR) == 0);
077: }
078:
079:
080: void Entree_Deinit(void)
081: {
082: assert(fclose(Entree_Fichier) == 0);
083: }
084:
085:
086: bool Entree_LectureEvt(uint32_t *Duree)
087: {
088: uint8_t buf[4];
089:
090: if (fread(buf, sizeof(buf), 1, Entree_Fichier) != 1) return false;
091:
092: OPK_EcritureReg(buf[0], buf[1]);
093:
094: *Duree = buf[2];
095: *Duree <<= 8;
096: *Duree |= buf[3];
097:
098: return true;
099: }
100:
101:
102: void Sortie_Init(const char *NomFichier)
103: {
104: Sortie_Fichier = fopen(NomFichier, "wb");
105: assert(Sortie_Fichier != NULL);
106: }
107:
108:
109: void Sortie_Deinit(void)
110: {
111: assert(fclose(Sortie_Fichier) == 0);
112: }
113:
114:
115: void Sortie_Synthese(uint32_t NbEchs)
116: {
117: while (NbEchs--)
118: {
119: double EchSortie = 0.0;
120:
121: for (uint32_t i = 0; i <= OPK_NbCanaux; i++)
122: {
123: double Alpha = OPK_Canal[i].Alpha;
124: double Amplitude = OPK_Canal[i].Amplitude;
125:
126: EchSortie += sin(2.0 * PI * Alpha) * Amplitude;
127:
128: {
129: double FreqNote;
130:
131: {
132: uint16_t Tmp;
133:
134: Tmp = OPK_Reg[OPK_FreqMSB[i]];
135: Tmp <<= 8;
136: Tmp |= OPK_Reg[OPK_FreqLSB[i]];
137:
138: FreqNote = ((Tmp >> 4) & 0x1FF) << (Tmp >> 13);
139: FreqNote *= Entree_FreqHorl / pow(2.0, 19);
140: }
141:
142: Alpha += FreqNote / Sortie_FreqEch;
143: Alpha -= floor(Alpha);
144: }
145:
146: if (OPK_Reg[OPK_FlagsCar[i]] & 0x80)
147: {
148: Amplitude += 1.0 / (OPK_DureeAttaque * ((double)Sortie_FreqEch));
149: if (Amplitude > 1.0) Amplitude = 1.0;
150: }
151: else
152: {
153: Amplitude -= 1.0 / (OPK_DureeRelach * ((double)Sortie_FreqEch));
154: if (Amplitude < 0.0) Amplitude = 0.0;
155: }
156:
157: OPK_Canal[i].Alpha = Alpha;
158: OPK_Canal[i].Amplitude = Amplitude;
159: }
160:
161: EchSortie /= OPK_NbCanaux;
162:
163: {
164: int16_t Tmp = EchSortie * 32767.0;
165: assert(fwrite(&Tmp, sizeof(Tmp), 1, Sortie_Fichier) == 1);
166: }
167: }
168: }
169:
170:
171: int main(void)
172: {
173: OPK_Init();
174:
175: Entree_Init("pss26_demo_song_full_length.bin");
176:
177: Sortie_Init("pss26_demo_song_full_length.raw");
178:
179: {
180: uint32_t Duree;
181:
182: while (Entree_LectureEvt(&Duree))
183: {
184: double NbEchs;
185:
186: NbEchs = Duree;
187:
188: NbEchs /= Entree_FreqEvts;
189: NbEchs *= Sortie_FreqEch;
190:
191: Sortie_Synthese(floor(NbEchs + 0.5));
192: }
193: }
194:
195: Sortie_Deinit();
196: Entree_Deinit();
197:
198: return 0;
199: }