paulo@0: #include <stdlib.h>
paulo@0: #include <stdio.h>
paulo@0: #include <math.h>
paulo@0: 
paulo@0: /*
paulo@0: Pin Eight standard tuning defines middle C as 2093/8 Hz.
paulo@0: It uses equal temperament: a semitone difference between two pitches
paulo@0: is a factor of 2^(1/12) between their frequencies.
paulo@0: Thus, MIDI 0 = 60, or 2093/256.
paulo@0: */
paulo@0: #define C_IN_OCTAVE(octave) \
paulo@0:   ((double)((long int)2093 << octave) / 256.0)
paulo@0: #define TWELFTH_ROOT_OF_TWO 1.0594630943592952645618252949463
paulo@0: 
paulo@0: /*
paulo@0: DS note frequencies for the tone generator at 8 samples per period
paulo@0: are ((-0x1000000 / (n * 8)))
paulo@0: */
paulo@0: #define FREQ_TO_PSG_PERIOD(freq) \
paulo@0:   ((unsigned short)(-0x1000000 / (freq * 8)))
paulo@0: 
paulo@0:   
paulo@0: int writePSG(FILE *fp) {
paulo@0: 
paulo@0:   // write header  
paulo@0:   fputs(".section .rodata\n"
paulo@0:         ".balign 4\n"
paulo@0:         ".global midi2psgFreq\n"
paulo@0:         "midi2psgFreq:", fp);
paulo@0:   
paulo@0:   int octave = 0;
paulo@0:   
paulo@0:   for (; octave < 2; ++octave) {
paulo@0:     fprintf(fp, "\n@ unsupported octave %d\n.byte ", octave);
paulo@0:     for (int semitone = 0; semitone < 12; ++semitone) {
paulo@0:       if (semitone) {
paulo@0:         fputs(", ", fp);
paulo@0:       }
paulo@0:       fputs("  0,  0", fp);
paulo@0:     }
paulo@0:   }
paulo@0:   for (; octave < 10; ++octave) {
paulo@0:     double freq = C_IN_OCTAVE(octave);
paulo@0:     fprintf(fp, "\n@ octave %d\n.byte ", octave);
paulo@0:     for (int semitone = 0; semitone < 12; ++semitone) {
paulo@0:       if (semitone) {
paulo@0:         fputs(", ", fp);
paulo@0:         freq *= TWELFTH_ROOT_OF_TWO;
paulo@0:       }
paulo@0:       unsigned int psgFreq = FREQ_TO_PSG_PERIOD(freq);
paulo@0:       printf("midi %2d = %.2f = psg %5d\n",
paulo@0:              octave * 12 + semitone,
paulo@0:              freq,
paulo@0:              psgFreq);
paulo@0:       fprintf(fp, "%3u,%3u",
paulo@0:               psgFreq & 0xFF,
paulo@0:               (psgFreq >> 8) & 0xFF);
paulo@0:     }    
paulo@0:   }
paulo@0:   
paulo@0:   fputs("\n", fp);
paulo@0:   return 0;
paulo@0: }
paulo@0: 
paulo@0: /**
paulo@0:  * Writes lookup tables used by the ARM7 code.
paulo@0:  * Currently, these include the PSG pitch values.
paulo@0:  */
paulo@0: int writeARM7(const char *filename) {
paulo@0:   FILE *fp = fopen(filename, "wt");
paulo@0:   if (!fp) {
paulo@0:     return -1;
paulo@0:   }
paulo@0:   if (writePSG(fp) < 0) {
paulo@0:     fclose(fp);
paulo@0:     return -1;
paulo@0:   }
paulo@0:   fclose(fp);
paulo@0:   return 0;
paulo@0: }
paulo@0: 
paulo@0: 
paulo@0: int main(void) {
paulo@0:   if (writeARM7("obj/ds/lookup_tables7.s") < 0) {
paulo@0:     return EXIT_FAILURE;
paulo@0:   }
paulo@0:   return EXIT_SUCCESS;
paulo@0: }