/// <summary> /// Set output sound format /// </summary> /// <param name="ay">pointer to ayemu_t structure</param> /// <param name="freq">sound freq (44100 for example)</param> /// <param name="chans">number of channels (1-mono, 2-stereo)</param> /// <param name="bits"> now supported only 16 and 8.</param> /// <returns> /// 1 on success, \b 0 if error occure /// </returns> public static int ayemu_set_sound_format(ayemu_ay_t ay, int freq, int chans, int bits) { if (!check_magic(ay)) { return(0); } if (!(bits == 16 || bits == 8)) { ayemu_err = "Incorrect bits value"; return(0); } else if (!(chans == 1 || chans == 2)) { ayemu_err = "Incorrect number of channels"; return(0); } else if (freq < 50) { ayemu_err = "Incorrect output sound freq"; return(0); } else { ay.sndfmt.freq = freq; ay.sndfmt.channels = chans; ay.sndfmt.bpc = bits; } ay.default_sound_format_flag = 0; ay.dirty = true; return(1); }
public static bool check_magic(ayemu_ay_t ay) { if (ay.magic == ayemu_ay_t.MAGIC1) { return(true); } return(false); }
// Set chip frequency. public static void ayemu_set_chip_freq(ayemu_ay_t ay, int chipfreq) { if (!check_magic(ay)) { return; } ay.ChipFreq = chipfreq; ay.dirty = true; }
public static void set_table_ym(ayemu_ay_t ay, int[] tbl) //[32] { int n; for (n = 0; n < 32; n++) { ay.table[n] = tbl[n]; } ay.type = ayemu_chip_t.AYEMU_YM; }
public static void set_table_ay(ayemu_ay_t ay, int[] tbl) //[16] { int n; for (n = 0; n < 32; n++) { ay.table[n] = tbl[n / 2]; } ay.type = ayemu_chip_t.AYEMU_AY; }
public static void prepare_generation(ayemu_ay_t ay) { int vol, max_l, max_r; if (!ay.dirty) { return; } if (!bEnvGenInit) { gen_env(); } if ((ay.default_chip_flag) != 0) { ayemu_set_chip_type(ay, ayemu_chip_t.AYEMU_AY, null); } if ((ay.default_stereo_flag) != 0) { ayemu_set_stereo(ay, ayemu_stereo_t.AYEMU_ABC, null); } if ((ay.default_sound_format_flag) != 0) { ayemu_set_sound_format(ay, 44100, 2, 16); } ay.ChipTacts_per_outcount = ay.ChipFreq / ay.sndfmt.freq / 8; { // GenVols int n, m; int vol2; for (n = 0; n < 32; n++) { vol2 = ay.table[n]; for (m = 0; m < 6; m++) { ay.vols[m][n] = (int)(((double)vol2 * ay.eq[m]) / 100); } } } /* ???????????? ????????? ??????????? ???????????? ???????? * ???????????????, ??? ? vols [x][31] ????? ????? ??????? ????????? * TODO: ??????? ???????? ?? ??? ;-) */ max_l = ay.vols[0][31] + ay.vols[2][31] + ay.vols[4][31]; max_r = ay.vols[1][31] + ay.vols[3][31] + ay.vols[5][31]; vol = (max_l > max_r) ? max_l : max_r; // =157283 on all defaults ay.Amp_Global = ay.ChipTacts_per_outcount * vol / AYEMU_MAX_AMP; ay.dirty = false; }
/// <summary> /// retval ayemu_init none. /// </summary> /// <param name="ay"></param> public static void ayemu_init(ayemu_ay_t ay) { ay.default_chip_flag = 1; ay.ChipFreq = AYEMU_DEFAULT_CHIP_FREQ; ay.default_stereo_flag = 1; ay.default_sound_format_flag = 1; ay.dirty = true; ay.magic = ayemu_ay_t.MAGIC1; ayemu_reset(ay); }
/// <summary> /// Set amplitude factor for each of channels (A,B anc C, tone and noise). /// Factor's value must be from (-100) to 100. /// </summary> /// <param name="ay">pointer to ayemu_t structure</param> /// <param name="stereo_type">type of stereo</param> /// <param name="custom_eq">null or array with custom table of mixer layout.</param> /// <returns> /// 1 if OK, 0 if error occures. /// </returns> public static int ayemu_set_stereo(ayemu_ay_t ay, ayemu_stereo_t stereo_type, int[] custom_eq) { int i; int chip; if (!check_magic(ay)) { return(0); } if (stereo_type != ayemu_stereo_t.AYEMU_STEREO_CUSTOM && custom_eq != null) { ayemu_err = "Stereo type not custom, 'custom_eq' parametr must be NULL"; return(0); } chip = (ay.type == ayemu_chip_t.AYEMU_AY) ? 0 : 1; switch (stereo_type) { case ayemu_stereo_t.AYEMU_MONO: case ayemu_stereo_t.AYEMU_ABC: case ayemu_stereo_t.AYEMU_ACB: case ayemu_stereo_t.AYEMU_BAC: case ayemu_stereo_t.AYEMU_BCA: case ayemu_stereo_t.AYEMU_CAB: case ayemu_stereo_t.AYEMU_CBA: for (i = 0; i < 6; i++) { ay.eq[i] = default_layout[chip][(int)stereo_type][i]; } break; case ayemu_stereo_t.AYEMU_STEREO_CUSTOM: for (i = 0; i < 6; i++) { ay.eq[i] = custom_eq[i]; } break; default: ayemu_err = "Incorrect stereo type"; return(0); } ay.default_stereo_flag = 0; ay.dirty = true; return(1); }
public void InitAY(byte[] _pAYBuffer) { ay8912.init_ay8912(); // remember buffer pAYBuffer = _pAYBuffer; // init AY structure and reset virtual chip AY = new ayemu_ay_t(); ay8912.ayemu_init(AY); ay8912.ayemu_reset(AY); // will create a 1248 buffer per frame (624 samples at 16bit) int ret = ay8912.ayemu_set_sound_format(AY, 312 * 2 * 50, 2, 8); }
/** Reset AY/YM chip. * * \arg \c ay - pointer to ayemu_ay_t structure. * \return none. */ public static void ayemu_reset(ayemu_ay_t ay) { if (!check_magic(ay)) { return; } ay.cnt_a = ay.cnt_b = ay.cnt_c = ay.cnt_n = ay.cnt_e = 0; ay.bit_a = ay.bit_b = ay.bit_c = ay.bit_n = false; ay.env_pos = ay.EnvNum = 0; ay.Cur_Seed = 0xffff; ay.regs.tone_a = ay.regs.tone_b = ay.regs.tone_c = 0; ay.regs.noise = 0; ay.regs.R7_tone_a = ay.regs.R7_tone_b = ay.regs.R7_tone_c = false; ay.regs.R7_noise_a = ay.regs.R7_noise_b = ay.regs.R7_noise_c = false; ay.regs.vol_a = ay.regs.vol_b = ay.regs.vol_c = 0; ay.regs.env_a = ay.regs.env_b = ay.regs.env_c = false; ay.regs.env_freq = ay.regs.env_style = 0; }
/** Set chip type. */ public static int ayemu_set_chip_type(ayemu_ay_t ay, ayemu_chip_t type, int[] custom_table) { if (!check_magic(ay)) { return(0); } if (!(type == ayemu_chip_t.AYEMU_AY_CUSTOM || type == ayemu_chip_t.AYEMU_YM_CUSTOM) && custom_table != null) { ayemu_err = "For non-custom chip type 'custom_table' param must be NULL"; return(0); } switch (type) { case ayemu_chip_t.AYEMU_AY: case ayemu_chip_t.AYEMU_AY_LION17: set_table_ay(ay, Lion17_AY_table); break; case ayemu_chip_t.AYEMU_YM: case ayemu_chip_t.AYEMU_YM_LION17: set_table_ym(ay, Lion17_YM_table); break; case ayemu_chip_t.AYEMU_AY_KAY: set_table_ay(ay, KAY_AY_table); break; case ayemu_chip_t.AYEMU_YM_KAY: set_table_ym(ay, KAY_YM_table); break; case ayemu_chip_t.AYEMU_AY_CUSTOM: set_table_ay(ay, custom_table); break; case ayemu_chip_t.AYEMU_YM_CUSTOM: set_table_ym(ay, custom_table); break; default: ayemu_err = "Incorrect chip type"; return(0); } ay.default_chip_flag = 0; ay.dirty = true; return(1); }
void ayemu_free(ayemu_ay_t ay) { // return; }
/// <summary> /// Generate sound. Fill sound buffer with current register data /// </summary> /// <param name="ay">ay chip</param> /// <param name="buff">8 bit buffer to fill - or null</param> /// <param name="buff16">16 bit buffer to fill - or null</param> /// <param name="frame_count">size of buffer</param> public static int ayemu_gen_sound(ayemu_ay_t ay, byte[] buff, UInt16[] buff16, int frame_count, int _index) { int mix_l, mix_r; int tmpvol; int m; byte[] char_buf = buff; UInt16[] short_buf = buff16; int buff_index = _index; if (!check_magic(ay)) { return(0); } prepare_generation(ay); while (frame_count-- > 0) { mix_l = mix_r = 0; for (m = 0; m < ay.ChipTacts_per_outcount; m++) { if (++ay.cnt_a >= ay.regs.tone_a) { ay.cnt_a = 0; ay.bit_a = !ay.bit_a; } if (++ay.cnt_b >= ay.regs.tone_b) { ay.cnt_b = 0; ay.bit_b = !ay.bit_b; } if (++ay.cnt_c >= ay.regs.tone_c) { ay.cnt_c = 0; ay.bit_c = !ay.bit_c; } /* GenNoise (c) Hacker KAY & Sergey Bulba */ if (++ay.cnt_n >= (ay.regs.noise * 2)) { ay.cnt_n = 0; ay.Cur_Seed = (ay.Cur_Seed * 2 + 1) ^ (((ay.Cur_Seed >> 16) ^ (ay.Cur_Seed >> 13)) & 1); ay.bit_n = false; if (((ay.Cur_Seed >> 16) & 1) != 0) { ay.bit_n = true; } } if (++ay.cnt_e >= ay.regs.env_freq) { ay.cnt_e = 0; if (++ay.env_pos > 127) { ay.env_pos = 64; } } //#define ENVVOL Envelope[ay.regs.env_style][ay.env_pos] if ((ay.bit_a | !ay.regs.R7_tone_a) & (ay.bit_n | !ay.regs.R7_noise_a)) { tmpvol = (ay.regs.env_a) ? Envelope[ay.regs.env_style][ay.env_pos] : ay.regs.vol_a * 2 + 1; mix_l += ay.vols[0][tmpvol]; mix_r += ay.vols[1][tmpvol]; } if ((ay.bit_b | !ay.regs.R7_tone_b) & (ay.bit_n | !ay.regs.R7_noise_b)) { tmpvol = (ay.regs.env_b) ? Envelope[ay.regs.env_style][ay.env_pos] : ay.regs.vol_b * 2 + 1; mix_l += ay.vols[2][tmpvol]; mix_r += ay.vols[3][tmpvol]; } if ((ay.bit_c | !ay.regs.R7_tone_c) & (ay.bit_n | !ay.regs.R7_noise_c)) { tmpvol = (ay.regs.env_c) ? Envelope[ay.regs.env_style][ay.env_pos] : ay.regs.vol_c * 2 + 1; mix_l += ay.vols[4][tmpvol]; mix_r += ay.vols[5][tmpvol]; } } /* end for (m=0; ...) */ mix_l /= ay.Amp_Global; mix_r /= ay.Amp_Global; if (ay.sndfmt.bpc == 8) { mix_l = (mix_l >> 8); // | 128; /* 8 bit sound */ mix_r = (mix_r >> 8); // | 128; char_buf[_index++] = (byte)mix_l; if (ay.sndfmt.channels != 1) { char_buf[_index++] = (byte)mix_r; } } else { short_buf[_index++] = (UInt16)mix_l; /* 16 bit sound */ if (ay.sndfmt.channels != 1) { short_buf[_index++] = (UInt16)mix_r; } } } return(buff_index); }
/** Assign values for AY registers. * * You must pass array of char [14] to this function */ /* * void ayemu_set_regs(ayemu_ay_t ay, unsigned char* regs) * { * if (!check_magic(ay)) return; * * // WARN_IF_REGISTER_GREAT_THAN(1, 15); * // WARN_IF_REGISTER_GREAT_THAN(3, 15); * // WARN_IF_REGISTER_GREAT_THAN(5, 15); * // WARN_IF_REGISTER_GREAT_THAN(8, 31); * // WARN_IF_REGISTER_GREAT_THAN(9, 31); * // WARN_IF_REGISTER_GREAT_THAN(10, 31); * * ay.regs.tone_a = regs[0] + ((regs[1] & 0x0f) << 8); * ay.regs.tone_b = regs[2] + ((regs[3] & 0x0f) << 8); * ay.regs.tone_c = regs[4] + ((regs[5] & 0x0f) << 8); * * ay.regs.noise = regs[6] & 0x1f; * * ay.regs.R7_tone_a = !(regs[7] & 0x01); * ay.regs.R7_tone_b = !(regs[7] & 0x02); * ay.regs.R7_tone_c = !(regs[7] & 0x04); * * ay.regs.R7_noise_a = !(regs[7] & 0x08); * ay.regs.R7_noise_b = !(regs[7] & 0x10); * ay.regs.R7_noise_c = !(regs[7] & 0x20); * * ay.regs.vol_a = regs[8] & 0x0f; * ay.regs.vol_b = regs[9] & 0x0f; * ay.regs.vol_c = regs[10] & 0x0f; * ay.regs.env_a = regs[8] & 0x10; * ay.regs.env_b = regs[9] & 0x10; * ay.regs.env_c = regs[10] & 0x10; * ay.regs.env_freq = regs[11] + (regs[12] << 8); * * if (regs[13] != 0xff) * { // R13 = 255 means continue curent envelop * ay.regs.env_style = regs[13] & 0x0f; * ay.env_pos = ay.cnt_e = 0; * } * } */ /** Assign value for a single AY register. */ public static void ayemu_set_reg(ayemu_ay_t ay, int reg, byte value) { if (!check_magic(ay)) { return; } switch (reg) { case 0: ay.regs.tone_a = (ay.regs.tone_a & 0x0f00) | value; break; case 1: ay.regs.tone_a = (ay.regs.tone_a & 0x00ff) | ((value & 0x0f) << 8); break; case 2: ay.regs.tone_b = (ay.regs.tone_b & 0x0f00) | value; break; case 3: ay.regs.tone_b = (ay.regs.tone_b & 0x00ff) | ((value & 0x0f) << 8); break; case 4: ay.regs.tone_c = (ay.regs.tone_c & 0x0f00) | value; break; case 5: ay.regs.tone_c = (ay.regs.tone_c & 0x00ff) | ((value & 0x0f) << 8); break; case 6: ay.regs.noise = value & 0x1f; break; case 7: ay.regs.R7_tone_a = !((value & 0x01) != 0); ay.regs.R7_tone_b = !((value & 0x02) != 0); ay.regs.R7_tone_c = !((value & 0x04) != 0); ay.regs.R7_noise_a = !((value & 0x08) != 0); ay.regs.R7_noise_b = !((value & 0x10) != 0); ay.regs.R7_noise_c = !((value & 0x20) != 0); break; case 8: ay.regs.vol_a = value & 0x0f; ay.regs.env_a = false; if ((value & 0x10) != 0) { ay.regs.env_a = true; } break; case 9: ay.regs.vol_b = value & 0x0f; ay.regs.env_b = false; if ((value & 0x10) != 0) { ay.regs.env_b = true; } break; case 10: ay.regs.vol_c = value & 0x0f; ay.regs.env_c = false; if ((value & 0x10) != 0) { ay.regs.env_c = true; } break; case 11: ay.regs.env_freq = (ay.regs.env_freq & 0xff00) | value; break; case 12: ay.regs.env_freq = (ay.regs.env_freq & 0x00ff) | (value << 8); break; case 13: ay.regs.env_style = value & 0x0f; ay.env_pos = ay.cnt_e = 0; break; } }