File: pss26_demo.c - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

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: }