Advertisement
joric

ay_render.c

Sep 5th, 2018
254
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.59 KB | None | 0 0
  1. // minimal libayemu-based AY sound renderer
  2. // data converted with psg_to_text.py from ayumi
  3.  
  4. #include "frame_data.h"
  5.  
  6. #define AYEMU_MAX_AMP 24575
  7. #define AYEMU_DEFAULT_CHIP_FREQ 1773400
  8.  
  9. #include <stdio.h>
  10. #include <malloc.h>
  11. typedef unsigned char ayemu_ay_reg_frame_t[14];
  12.  
  13. typedef struct {
  14.     int tone_a;     /**< R0, R1 */
  15.     int tone_b;     /**< R2, R3 */
  16.     int tone_c;     /**< R4, R5 */
  17.     int noise;      /**< R6 */
  18.     int R7_tone_a;  /**< R7 bit 0 */
  19.     int R7_tone_b;  /**< R7 bit 1 */
  20.     int R7_tone_c;  /**< R7 bit 2 */
  21.     int R7_noise_a; /**< R7 bit 3 */
  22.     int R7_noise_b; /**< R7 bit 4 */
  23.     int R7_noise_c; /**< R7 bit 5 */
  24.     int vol_a;      /**< R8 bits 3-0 */
  25.     int vol_b;      /**< R9 bits 3-0 */
  26.     int vol_c;      /**< R10 bits 3-0 */
  27.     int env_a;      /**< R8 bit 4 */
  28.     int env_b;      /**< R9 bit 4 */
  29.     int env_c;      /**< R10 bit 4 */
  30.     int env_freq;   /**< R11, R12 */
  31.     int env_style;  /**< R13 */
  32. } ayemu_regdata_t;
  33.  
  34.  
  35. typedef struct {
  36.     int freq;           /**< sound freq */
  37.     int channels;       /**< channels (1-mono, 2-stereo) */
  38.     int bpc;            /**< bits (8 or 16) */
  39. } ayemu_sndfmt_t;
  40.  
  41. typedef struct {
  42.     int table[32];          /**< table of volumes for chip */
  43.     int ChipFreq;           /**< chip emulator frequency */
  44.     int eq[6];              /**< volumes for channels, range -100..100 **/
  45.     int bit_a;              /**< state of channel A generator */
  46.     int bit_b;              /**< state of channel B generator */
  47.     int bit_c;              /**< state of channel C generator */
  48.     int bit_n;              /**< current generator state */
  49.     int cnt_a;              /**< back counter of A */
  50.     int cnt_b;              /**< back counter of B */
  51.     int cnt_c;              /**< back counter of C */
  52.     int cnt_n;              /**< back counter of noise generator */
  53.     int cnt_e;              /**< back counter of envelop generator */
  54.     int EnvNum;             /**< number of current envilopment (0...15) */
  55.     int env_pos;            /**< current position in envelop (0...127) */
  56.     int Cur_Seed;           /**< random numbers counter */
  57.     ayemu_regdata_t regs;   /**< parsed registers data */
  58.     ayemu_sndfmt_t sndfmt;  /**< output sound format */
  59.     int ChipTacts_per_outcount;  /**< chip's counts per one sound signal count */
  60.     int Amp_Global;         /**< scale factor for amplitude */
  61.     int vols[6][32];        /**< stereo type (channel volumes) and chip table. This cache calculated by #table and #eq  */
  62. } ayemu_ay_t;
  63.  
  64. #if 0
  65. static int AY_table [16] = {0,513,828,1239,1923,3238,4926,9110,10344,17876,24682,30442,38844,47270,56402,65535};
  66. static const int AY_eq[] = {100,33,70,70,33,100};
  67. #else //YM
  68. static int AY_table [32] = { 0, 0, 190, 286, 375, 470, 560, 664, 866, 1130, 1515, 1803, 2253, 2848, 3351, 3862, 4844, 6058, 7290, 8559, 10474, 12878, 15297, 17787, 21500, 26172, 30866, 35676, 42664, 50986, 58842, 65535};
  69. static const int AY_eq[] = {100, 5, 70, 70, 5, 100};
  70. #endif
  71.  
  72. #define ENVVOL envelope(ay->regs.env_style, ay->env_pos)
  73.  
  74.  
  75. int envelope(int e, int x) {
  76.     int loop = e > 7 && (e % 2)==0;
  77.     int q = (x / 32) & (loop ? 1 : 3);
  78.     int ofs = (q==0 ? (e & 4)==0 : (e == 8 || e==11 || e==13 || e==14)) ? 31 : 0;
  79.     return (q==0 || loop) ? ( ofs + (ofs!=0 ? -1 : 1) * (x % 32) ) : ofs;
  80. }
  81.  
  82.  
  83. void ayemu_init(ayemu_ay_t *ay, int freq, int channels, int bits) {
  84.     ay->ChipFreq = AYEMU_DEFAULT_CHIP_FREQ;
  85.  
  86.     ay->cnt_a = ay->cnt_b = ay->cnt_c = ay->cnt_n = ay->cnt_e = 0;
  87.     ay->bit_a = ay->bit_b = ay->bit_c = ay->bit_n = 0;
  88.     ay->env_pos = ay->EnvNum = 0;
  89.     ay->Cur_Seed = 0xffff;
  90.  
  91.     for (int n = 0; n < 32; n++)
  92.         ay->table[n] = AY_table[ n * (sizeof(AY_table) / sizeof(AY_table[0])) / 32 ];
  93.  
  94.     for (int i = 0 ; i < 6 ; i++)
  95.         ay->eq[i] = AY_eq[i];
  96.  
  97.     ay->sndfmt.freq = freq;
  98.     ay->sndfmt.channels = channels;
  99.     ay->sndfmt.bpc = bits;
  100. }
  101.  
  102.  
  103. void ayemu_set_regs(ayemu_ay_t *ay, ayemu_ay_reg_frame_t regs) {
  104.     ay->regs.tone_a = regs[0] + ((regs[1]&0x0f) << 8);
  105.     ay->regs.tone_b = regs[2] + ((regs[3]&0x0f) << 8);
  106.     ay->regs.tone_c = regs[4] + ((regs[5]&0x0f) << 8);
  107.     ay->regs.noise = regs[6] & 0x1f;
  108.     ay->regs.R7_tone_a = ! (regs[7] & 0x01);
  109.     ay->regs.R7_tone_b = ! (regs[7] & 0x02);
  110.     ay->regs.R7_tone_c = ! (regs[7] & 0x04);
  111.     ay->regs.R7_noise_a = ! (regs[7] & 0x08);
  112.     ay->regs.R7_noise_b = ! (regs[7] & 0x10);
  113.     ay->regs.R7_noise_c = ! (regs[7] & 0x20);
  114.     ay->regs.vol_a = regs[8] & 0x0f;
  115.     ay->regs.vol_b = regs[9] & 0x0f;
  116.     ay->regs.vol_c = regs[10] & 0x0f;
  117.     ay->regs.env_a = regs[8] & 0x10;
  118.     ay->regs.env_b = regs[9] & 0x10;
  119.     ay->regs.env_c = regs[10] & 0x10;
  120.     ay->regs.env_freq = regs[11] + (regs[12] << 8);
  121.     if (regs[13] != 0xff) {
  122.         ay->regs.env_style = regs[13] & 0x0f;
  123.         ay->env_pos = ay->cnt_e = 0;
  124.     }
  125. }
  126.  
  127.  
  128. void *ayemu_gen_sound(ayemu_ay_t *ay, unsigned char * sound_buf, size_t sound_bufsize)
  129. {
  130.     int mix_l, mix_r;
  131.     int tmpvol;
  132.     int m;
  133.     int snd_numcount;
  134.  
  135.     int vol, max_l, max_r;
  136.  
  137.     ay->ChipTacts_per_outcount = ay->ChipFreq / ay->sndfmt.freq / 8;
  138.  
  139.     for (int n = 0; n < 32; n++) {
  140.         vol = ay->table[n];
  141.         for (int m=0; m < 6; m++)
  142.             ay->vols[m][n] = (int) (((double) vol * ay->eq[m]) / 100);
  143.     }
  144.  
  145.     max_l = ay->vols[0][31] + ay->vols[2][31] + ay->vols[3][31];
  146.     max_r = ay->vols[1][31] + ay->vols[3][31] + ay->vols[5][31];
  147.  
  148.     vol = (max_l > max_r) ? max_l : max_r;
  149.     ay->Amp_Global = ay->ChipTacts_per_outcount *vol / AYEMU_MAX_AMP;
  150.  
  151.     snd_numcount = sound_bufsize / (ay->sndfmt.channels * (ay->sndfmt.bpc >> 3));
  152.  
  153.     while (snd_numcount-- > 0) {
  154.  
  155.         mix_l = mix_r = 0;
  156.  
  157.         for (m = 0 ; m < ay->ChipTacts_per_outcount ; m++) {
  158.  
  159.             if (++ay->cnt_a >= ay->regs.tone_a) {
  160.                 ay->cnt_a = 0;
  161.                 ay->bit_a = ! ay->bit_a;
  162.             }
  163.  
  164.             if (++ay->cnt_b >= ay->regs.tone_b) {
  165.                 ay->cnt_b = 0;
  166.                 ay->bit_b = ! ay->bit_b;
  167.             }
  168.  
  169.             if (++ay->cnt_c >= ay->regs.tone_c) {
  170.                 ay->cnt_c = 0;
  171.                 ay->bit_c = ! ay->bit_c;
  172.             }
  173.  
  174.             if (++ay->cnt_n >= (ay->regs.noise * 2)) {
  175.                 ay->cnt_n = 0;
  176.                 ay->Cur_Seed = (ay->Cur_Seed * 2 + 1) ^ (((ay->Cur_Seed >> 16) ^ (ay->Cur_Seed >> 13)) & 1);
  177.                 ay->bit_n = ((ay->Cur_Seed >> 16) & 1);
  178.             }
  179.            
  180.             if (++ay->cnt_e >= ay->regs.env_freq) {
  181.                 ay->cnt_e = 0;
  182.                 if (++ay->env_pos > 127) ay->env_pos = 64;
  183.             }
  184.  
  185.             if ((ay->bit_a | !ay->regs.R7_tone_a) & (ay->bit_n | !ay->regs.R7_noise_a)) {
  186.                 tmpvol = (ay->regs.env_a)? ENVVOL : ay->regs.vol_a * 2 + 1;
  187.                 mix_l += ay->vols[0][tmpvol];
  188.                 mix_r += ay->vols[1][tmpvol];
  189.             }
  190.            
  191.             if ((ay->bit_b | !ay->regs.R7_tone_b) & (ay->bit_n | !ay->regs.R7_noise_b)) {
  192.                 tmpvol =(ay->regs.env_b)? ENVVOL :  ay->regs.vol_b * 2 + 1;
  193.                 mix_l += ay->vols[2][tmpvol];
  194.                 mix_r += ay->vols[3][tmpvol];
  195.             }
  196.            
  197.             if ((ay->bit_c | !ay->regs.R7_tone_c) & (ay->bit_n | !ay->regs.R7_noise_c)) {
  198.                 tmpvol = (ay->regs.env_c)? ENVVOL : ay->regs.vol_c * 2 + 1;
  199.                 mix_l += ay->vols[4][tmpvol];
  200.                 mix_r += ay->vols[5][tmpvol];
  201.             }
  202.         }
  203.  
  204.         mix_l /= ay->Amp_Global;
  205.         mix_r /= ay->Amp_Global;
  206.  
  207.         *sound_buf++ = mix_l & 0x00FF;
  208.         *sound_buf++ = (mix_l >> 8);
  209.         *sound_buf++ = mix_r & 0x00FF;
  210.         *sound_buf++ = (mix_r >> 8);
  211.     }
  212.     return sound_buf;
  213. }
  214.  
  215.  
  216. int main() {
  217.     ayemu_ay_t ay;
  218.     ayemu_ay_reg_frame_t regs;
  219.  
  220.     int freq = 44100;
  221.     int channels = 2;
  222.     int bits = 16;
  223.     int playerFreq = 50;
  224.     int frames = sizeof(frame_data)/sizeof(frame_data[0]);
  225.  
  226.     ayemu_init(&ay, freq, channels, bits);
  227.     int audio_bufsize = freq * channels * (bits / 8) / playerFreq;
  228.     unsigned char * audio_buf = (unsigned char*)malloc(audio_bufsize);
  229.  
  230.     printf("frames: %d, writing wav...\n", frames);
  231.  
  232.     FILE *fp = fopen("out.wav", "wb");
  233.     int hdr[] = {1179011410, 36, 1163280727, 544501094, 16, 131073, 44100, 176400, 1048580, 1635017060, 0};
  234.     hdr[1] = audio_bufsize * frames+15;
  235.     hdr[10] = audio_bufsize * frames;
  236.     fwrite(hdr, 1, sizeof(hdr), fp);
  237.  
  238.     size_t pos = 0;
  239.     while (pos++ < frames) {
  240.         ayemu_set_regs (&ay, frame_data[pos-1]);
  241.         ayemu_gen_sound (&ay, audio_buf, audio_bufsize);
  242.         fwrite(audio_buf, 1, audio_bufsize, fp);
  243.     }
  244.  
  245.     fclose(fp);
  246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement