public override int start(Mame.MachineSound msound) { string snd_name = "K005289"; //k005289_sound_channel voice=channel_list; k005289_interface intf = (k005289_interface)msound.sound_interface; /* get stream channels */ stream = Mame.stream_init(snd_name, intf.volume, Mame.Machine.sample_rate, 0, K005289_update); mclock = intf.master_clock; rate = Mame.Machine.sample_rate; /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */ mixer_buffer = new _ShortPtr(2 * sizeof(short) * Mame.Machine.sample_rate); /* build the mixer table */ if (make_mixer_table(2) != 0) { mixer_buffer = null; return 1; } sound_prom = Mame.memory_region(intf.region); /* reset all the voices */ channel_list[0].frequency = 0; channel_list[0].volume = 0; channel_list[0].wave = new _BytePtr(sound_prom); channel_list[0].counter = 0; channel_list[1].frequency = 0; channel_list[1].volume = 0; channel_list[1].wave = new _BytePtr(sound_prom, 0x100); channel_list[1].counter = 0; return 0; }
public static int stream_init_multi(int channels, string[] names, int[] default_mixing_levels, int sample_rate, int param, _stream_callback_multi callback) { int channel = mixer_allocate_channels(channels, default_mixing_levels); stream_joined_channels[channel] = channels; for (int i = 0; i < channels; i++) { mixer_set_name(channel + i, names[i]); stream_buffer[channel + i] = new _ShortPtr(sizeof(short) * BUFFER_LEN); stream_sample_rate[channel + i] = sample_rate; stream_buffer_pos[channel + i] = 0; if (sample_rate!=0) stream_sample_length[channel + i] = 1000000 / sample_rate; else stream_sample_length[channel + i] = 0; } stream_param[channel] = param; stream_callback_multi[channel] = callback; set_RC_filter(channel, 0, 0, 0, 0); return channel; }
public static void overlay_draw(osd_bitmap dest, artwork overlay) { int i, j; int height, width; osd_bitmap o = null; int black; o = overlay._artwork; height = overlay._artwork.height; width = overlay._artwork.width; black = Machine.pens[0]; if (dest.depth == 8) { _BytePtr dst, ovr; for (j = 0; j < height; j++) { dst = new _BytePtr(dest.line[j]); ovr = new _BytePtr(o.line[j]); for (i = 0; i < width; i++) { if (dst[0] != black) dst[0] = ovr[0]; dst.offset++; ovr.offset++; } } } else { _ShortPtr dst, ovr; for (j = 0; j < height; j++) { dst = new _ShortPtr(dest.line[j]); ovr = new _ShortPtr(o.line[j]); for (i = 0; i < width; i++) { if (dst.read16(0) != black) dst.write16(0, ovr.read16(0)); dst.offset += 2; ovr.offset += 2; } } } }
public static int stream_init(string name, int default_mixing_level, int sample_rate, int param, _stream_callback callback) { int channel = mixer_allocate_channel(default_mixing_level); stream_joined_channels[channel] = 1; mixer_set_name(channel, name); stream_buffer[channel] = new _ShortPtr(sizeof(short) * BUFFER_LEN); stream_sample_rate[channel] = sample_rate; stream_buffer_pos[channel] = 0; if (sample_rate != 0) stream_sample_length[channel] = 1000000 / sample_rate; else stream_sample_length[channel] = 0; stream_param[channel] = param; stream_callback[channel] = callback; set_RC_filter(channel, 0, 0, 0, 0); return channel; }
static int make_mixer_table(int voices) { int count = voices * 128; int i; int gain = 16; /* allocate memory */ mixer_table = new _ShortPtr(256 * voices * sizeof(short)); /* find the middle of the table */ mixer_lookup = new _ShortPtr(mixer_table, (128 * voices) * 2); /* fill in the table - 16 bit case */ for (i = 0; i < count; i++) { int val = i * gain * 16 / voices; if (val > 32767) val = 32767; mixer_lookup.write16(i, (ushort)val); mixer_lookup.write16(-i, (ushort)-val); } return 0; }
static void generate_adpcm(ADPCMVoice voice, _ShortPtr buffer, int samples) { /* if this voice is active */ if (voice.playing != 0) { _BytePtr _base = voice._base; int sample = (int)voice.sample; int signal = (int)voice.signal; int count = (int)voice.count; int step = (int)voice.step; int val; /* loop while we still have samples to generate */ while (samples != 0) { /* compute the new amplitude and update the current step */ val = _base[sample / 2] >> (((sample & 1) << 2) ^ 4); signal += diff_lookup[step * 16 + (val & 15)]; /* clamp to the maximum */ if (signal > 2047) signal = 2047; else if (signal < -2048) signal = -2048; /* adjust the step size and clamp */ step += index_shift[val & 7]; if (step > 48) step = 48; else if (step < 0) step = 0; /* output to the buffer, scaling by the volume */ buffer.write16(0, (ushort)(signal * voice.volume / 16)); buffer.offset += 2; samples--; /* next! */ if (++sample > count) { voice.playing = 0; break; } } /* update the parameters */ voice.sample = (uint)sample; voice.signal = (uint)signal; voice.step = (uint)step; } /* fill the rest with silence */ while (samples-- != 0) { buffer.write16(0, 0); buffer.offset += 2; } }
public static void adpcm_update(int num, _ShortPtr buffer, int length) { ADPCMVoice voice = _adpcm[num]; _ShortPtr sample_data = new _ShortPtr(MAX_SAMPLE_CHUNK * 2), curr_data = new _ShortPtr(sample_data); short prev = voice.last_sample, curr = voice.curr_sample; uint final_pos; uint new_samples; /* finish off the current sample */ if (voice.source_pos > 0) { /* interpolate */ while (length > 0 && voice.source_pos < FRAC_ONE) { buffer.write16(0, (ushort)((((int)prev * (FRAC_ONE - voice.source_pos)) + ((int)curr * voice.source_pos)) >> FRAC_BITS)); buffer.offset += 2; voice.source_pos += voice.source_step; length--; } /* if we're over, continue; otherwise, we're done */ if (voice.source_pos >= FRAC_ONE) voice.source_pos -= FRAC_ONE; else return; } /* compute how many new samples we need */ final_pos = (uint)(voice.source_pos + length * voice.source_step); new_samples = (final_pos + FRAC_ONE - 1) >> FRAC_BITS; if (new_samples > MAX_SAMPLE_CHUNK) new_samples = MAX_SAMPLE_CHUNK; /* generate them into our buffer */ generate_adpcm(voice, sample_data, (int)new_samples); prev = curr; curr = (short)curr_data.read16(0); curr_data.offset += 2; /* then sample-rate convert with linear interpolation */ while (length > 0) { /* interpolate */ while (length > 0 && voice.source_pos < FRAC_ONE) { buffer.write16(0, (ushort)((((int)prev * (FRAC_ONE - voice.source_pos)) + ((int)curr * voice.source_pos)) >> FRAC_BITS)); buffer.offset += 2; voice.source_pos += voice.source_step; length--; } /* if we're over, grab the next samples */ if (voice.source_pos >= FRAC_ONE) { voice.source_pos -= FRAC_ONE; prev = curr; curr = (short)curr_data.read16(0); curr_data.offset += 2; } } /* remember the last samples */ voice.last_sample = prev; voice.curr_sample = curr; }
void namco_update_stereo(int ch, _ShortPtr[] buffer, int length) { throw new Exception(); }
public static void stream_update(int channel, int min_interval) { if (Machine.sample_rate == 0 || stream_buffer[channel] == null) return; /* get current position based on the timer */ int newpos = sound_scalebufferpos(mixer_need_samples_this_frame(channel, stream_sample_rate[channel]));//SAMPLES_THIS_FRAME(channel)); int buflen = newpos - stream_buffer_pos[channel]; if (buflen * stream_sample_length[channel] > min_interval) { if (stream_joined_channels[channel] > 1) { _ShortPtr[] buf = new _ShortPtr[MIXER_MAX_CHANNELS]; for (int i = 0; i < stream_joined_channels[channel]; i++) buf[i] = new _ShortPtr(stream_buffer[channel + i], stream_buffer_pos[channel + i] * sizeof(short)); stream_callback_multi[channel](stream_param[channel], buf, buflen); for (int i = 0; i < stream_joined_channels[channel]; i++) stream_buffer_pos[channel + i] += buflen; } else { _ShortPtr buf = new _ShortPtr(stream_buffer[channel], stream_buffer_pos[channel] * sizeof(short)); stream_callback[channel](stream_param[channel], buf, buflen); stream_buffer_pos[channel] += buflen; } } }
static void blockmove_opaque16(_BytePtr srcdata, int srcwidth, int srcheight, int srcmodulo, _ShortPtr dstdata, int dstmodulo, UShortSubArray paldata) { //blockmove_opaque8(srcdata, srcwidth, srcheight, srcmodulo, (_BytePtr)dstdata, dstmodulo, paldata); //return; int end; srcmodulo -= srcwidth; dstmodulo -= srcwidth; while (srcheight != 0) { end = dstdata.offset + srcwidth; while (dstdata.offset <= end - 8) { dstdata.write16(0, paldata[srcdata[0]]); dstdata.write16(1, paldata[srcdata[1]]); dstdata.write16(2, paldata[srcdata[2]]); dstdata.write16(3, paldata[srcdata[3]]); dstdata.write16(4, paldata[srcdata[4]]); dstdata.write16(5, paldata[srcdata[5]]); dstdata.write16(6, paldata[srcdata[6]]); dstdata.write16(7, paldata[srcdata[7]]); dstdata.offset += 8 * 2; srcdata.offset++; } while (dstdata.offset < end) { dstdata.write16(0, paldata[srcdata[0]]); srcdata.offset++; dstdata.offset += 2; } srcdata.inc(srcmodulo); dstdata.inc(dstmodulo); srcheight--; } }
static void blockmove_transmask16(_BytePtr srcdata, int srcwidth, int srcheight, int srcmodulo, _ShortPtr dstdata, int dstmodulo, UShortSubArray paldata, int transmask) { throw new Exception(); }
public static void tms5220_update(int ch, _ShortPtr buffer, int length) { short[] sample_data = new short[MAX_SAMPLE_CHUNK]; ShortSubArray curr_data = new ShortSubArray(sample_data); short prev = last_sample, curr = curr_sample; uint final_pos; uint new_samples; /* finish off the current sample */ if (source_pos > 0) { /* interpolate */ while (length > 0 && source_pos < FRAC_ONE) { buffer.write16(0, (ushort)((((int)prev * (FRAC_ONE - source_pos)) + ((int)curr * source_pos)) >> FRAC_BITS)); buffer.offset += 2; source_pos += source_step; length--; } /* if we're over, continue; otherwise, we're done */ if (source_pos >= FRAC_ONE) source_pos -= FRAC_ONE; else return; } /* compute how many new samples we need */ final_pos = (uint)(source_pos + length * source_step); new_samples = (final_pos + FRAC_ONE - 1) >> FRAC_BITS; if (new_samples > MAX_SAMPLE_CHUNK) new_samples = MAX_SAMPLE_CHUNK; /* generate them into our buffer */ tms5220_process(sample_data, new_samples); prev = curr; curr = curr_data[0]; curr_data.offset++; /* then sample-rate convert with linear interpolation */ while (length > 0) { /* interpolate */ while (length > 0 && source_pos < FRAC_ONE) { buffer.write16(0, (ushort)((((int)prev * (FRAC_ONE - source_pos)) + ((int)curr * source_pos)) >> FRAC_BITS)); source_pos += source_step; length--; } /* if we're over, grab the next samples */ if (source_pos >= FRAC_ONE) { source_pos -= FRAC_ONE; prev = curr; curr = curr_data[0]; curr_data.offset++; } } /* remember the last samples */ last_sample = prev; curr_sample = curr; }
public static void drawgfxzoom(osd_bitmap dest_bmp, GfxElement gfx, uint code, uint color, bool flipx, bool flipy, int sx, int sy, rectangle clip, int transparency, int transparent_color, int scalex, int scaley) { FuncDict["drawgfxzoom"] = "drawgfxzoom"; rectangle myclip = new rectangle(); /* only support TRANSPARENCY_PEN and TRANSPARENCY_COLOR */ if (transparency != TRANSPARENCY_PEN && transparency != TRANSPARENCY_COLOR) return; if (transparency == TRANSPARENCY_COLOR) transparent_color = Machine.pens[transparent_color]; /* scalex and scaley are 16.16 fixed point numbers 1<<15 : shrink to 50% 1<<16 : uniform scale 1<<17 : double to 200% */ if ((Machine.orientation & ORIENTATION_SWAP_XY) != 0) { int temp; temp = sx; sx = sy; sy = temp; var tempb = flipx; flipx = flipy; flipy = tempb; temp = scalex; scalex = scaley; scaley = temp; if (clip != null) { /* clip and myclip might be the same, so we need a temporary storage */ temp = clip.min_x; myclip.min_x = clip.min_y; myclip.min_y = temp; temp = clip.max_x; myclip.max_x = clip.max_y; myclip.max_y = temp; clip = myclip; } } if ((Machine.orientation & ORIENTATION_FLIP_X) != 0) { sx = dest_bmp.width - ((gfx.width * scalex + 0x7fff) >> 16) - sx; if (clip != null) { int temp; /* clip and myclip might be the same, so we need a temporary storage */ temp = clip.min_x; myclip.min_x = dest_bmp.width - 1 - clip.max_x; myclip.max_x = dest_bmp.width - 1 - temp; myclip.min_y = clip.min_y; myclip.max_y = clip.max_y; clip = myclip; } #if !PREROTATE_GFX flipx = !flipx; #endif } if ((Machine.orientation & ORIENTATION_FLIP_Y) != 0) { sy = dest_bmp.height - ((gfx.height * scaley + 0x7fff) >> 16) - sy; if (clip != null) { int temp; myclip.min_x = clip.min_x; myclip.max_x = clip.max_x; /* clip and myclip might be the same, so we need a temporary storage */ temp = clip.min_y; myclip.min_y = dest_bmp.height - 1 - clip.max_y; myclip.max_y = dest_bmp.height - 1 - temp; clip = myclip; } #if !PREROTATE_GFX flipy = !flipy; #endif } /* KW 991012 -- Added code to force clip to bitmap boundary */ if (clip != null) { myclip.min_x = clip.min_x; myclip.max_x = clip.max_x; myclip.min_y = clip.min_y; myclip.max_y = clip.max_y; if (myclip.min_x < 0) myclip.min_x = 0; if (myclip.max_x >= dest_bmp.width) myclip.max_x = dest_bmp.width - 1; if (myclip.min_y < 0) myclip.min_y = 0; if (myclip.max_y >= dest_bmp.height) myclip.max_y = dest_bmp.height - 1; clip = myclip; } /* ASG 980209 -- added 16-bit version */ if (dest_bmp.depth != 16) { if (gfx != null && gfx.colortable != null) { UShortSubArray pal = new UShortSubArray(gfx.colortable, (int)(gfx.color_granularity * (color % gfx.total_colors))); /* ASG 980209 */ int source_base = (int)((code % gfx.total_elements) * gfx.height); int sprite_screen_height = (scaley * gfx.height + 0x8000) >> 16; int sprite_screen_width = (scalex * gfx.width + 0x8000) >> 16; /* compute sprite increment per screen pixel */ int dx = (gfx.width << 16) / sprite_screen_width; int dy = (gfx.height << 16) / sprite_screen_height; int ex = sx + sprite_screen_width; int ey = sy + sprite_screen_height; int x_index_base; int y_index; if (flipx) { x_index_base = (sprite_screen_width - 1) * dx; dx = -dx; } else { x_index_base = 0; } if (flipy) { y_index = (sprite_screen_height - 1) * dy; dy = -dy; } else { y_index = 0; } if (clip != null) { if (sx < clip.min_x) { /* clip left */ int pixels = clip.min_x - sx; sx += pixels; x_index_base += pixels * dx; } if (sy < clip.min_y) { /* clip top */ int pixels = clip.min_y - sy; sy += pixels; y_index += pixels * dy; } /* NS 980211 - fixed incorrect clipping */ if (ex > clip.max_x + 1) { /* clip right */ int pixels = ex - clip.max_x - 1; ex -= pixels; } if (ey > clip.max_y + 1) { /* clip bottom */ int pixels = ey - clip.max_y - 1; ey -= pixels; } } if (ex > sx) { /* skip if inner loop doesn't draw anything */ int y; /* case 1: TRANSPARENCY_PEN */ if (transparency == TRANSPARENCY_PEN) { for (y = sy; y < ey; y++) { _BytePtr source = new _BytePtr(gfx.gfxdata, (source_base + (y_index >> 16)) * gfx.line_modulo); _BytePtr dest = dest_bmp.line[y]; int x, x_index = x_index_base; for (x = sx; x < ex; x++) { int c = source[x_index >> 16]; if (c != transparent_color) dest[x] = (byte)pal[c]; x_index += dx; } y_index += dy; } } /* case 2: TRANSPARENCY_COLOR */ else if (transparency == TRANSPARENCY_COLOR) { for (y = sy; y < ey; y++) { _BytePtr source = new _BytePtr(gfx.gfxdata, (source_base + (y_index >> 16)) * gfx.line_modulo); _BytePtr dest = dest_bmp.line[y]; int x, x_index = x_index_base; for (x = sx; x < ex; x++) { int c = pal[source[x_index >> 16]]; if (c != transparent_color) dest[x] = (byte)c; x_index += dx; } y_index += dy; } } } } } /* ASG 980209 -- new 16-bit part */ else { if (gfx != null && gfx.colortable != null) { UShortSubArray pal = new UShortSubArray(gfx.colortable, (int)(gfx.color_granularity * (color % gfx.total_colors))); /* ASG 980209 */ int source_base = (int)((code % gfx.total_elements) * gfx.height); int sprite_screen_height = (scaley * gfx.height + 0x8000) >> 16; int sprite_screen_width = (scalex * gfx.width + 0x8000) >> 16; /* compute sprite increment per screen pixel */ int dx = (gfx.width << 16) / sprite_screen_width; int dy = (gfx.height << 16) / sprite_screen_height; int ex = sx + sprite_screen_width; int ey = sy + sprite_screen_height; int x_index_base; int y_index; if (flipx) { x_index_base = (sprite_screen_width - 1) * dx; dx = -dx; } else { x_index_base = 0; } if (flipy) { y_index = (sprite_screen_height - 1) * dy; dy = -dy; } else { y_index = 0; } if (clip != null) { if (sx < clip.min_x) { /* clip left */ int pixels = clip.min_x - sx; sx += pixels; x_index_base += pixels * dx; } if (sy < clip.min_y) { /* clip top */ int pixels = clip.min_y - sy; sy += pixels; y_index += pixels * dy; } /* NS 980211 - fixed incorrect clipping */ if (ex > clip.max_x + 1) { /* clip right */ int pixels = ex - clip.max_x - 1; ex -= pixels; } if (ey > clip.max_y + 1) { /* clip bottom */ int pixels = ey - clip.max_y - 1; ey -= pixels; } } if (ex > sx) { /* skip if inner loop doesn't draw anything */ int y; /* case 1: TRANSPARENCY_PEN */ if (transparency == TRANSPARENCY_PEN) { for (y = sy; y < ey; y++) { _BytePtr source = new _BytePtr(gfx.gfxdata, (source_base + (y_index >> 16)) * gfx.line_modulo); _ShortPtr dest = new _ShortPtr(dest_bmp.line[y]); int x, x_index = x_index_base; for (x = sx; x < ex; x++) { int c = source[x_index >> 16]; if (c != transparent_color) dest[x] = (byte)pal[c]; x_index += dx; } y_index += dy; } } /* case 2: TRANSPARENCY_COLOR */ else if (transparency == TRANSPARENCY_COLOR) { for (y = sy; y < ey; y++) { _BytePtr source = new _BytePtr(gfx.gfxdata, (source_base + (y_index >> 16)) * gfx.line_modulo); _ShortPtr dest = new _ShortPtr(dest_bmp.line[y]); int x, x_index = x_index_base; for (x = sx; x < ex; x++) { int c = pal[source[x_index >> 16]]; if (c != transparent_color) dest.write16(x, (ushort)c); x_index += dx; } y_index += dy; } } } } } }
static void SEGAPCMUpdate(int num, _ShortPtr[] buffer, int length) { throw new Exception(); }
static void draw_tile(osd_bitmap pixmap, int col, int row, int tile_width, int tile_height, _BytePtr pendata, UShortSubArray paldata, byte flags) { int x, sx = tile_width * col; int sy, y1, y2, dy; int pi = 0; if (Machine.scrbitmap.depth == 16) { if ((flags & TILE_FLIPY) != 0) { y1 = tile_height * row + tile_height - 1; y2 = y1 - tile_height; dy = -1; } else { y1 = tile_height * row; y2 = y1 + tile_height; dy = 1; } if ((flags & TILE_FLIPX) != 0) { tile_width--; for (sy = y1; sy != y2; sy += dy) { _ShortPtr dest = new _ShortPtr(pixmap.line[sy], sx); for (x = tile_width; x >= 0; x--) { dest.write16(x, paldata[pendata[pi++]]); } } } else { for (sy = y1; sy != y2; sy += dy) { _ShortPtr dest = new _ShortPtr(pixmap.line[sy], sx); for (x = 0; x < tile_width; x++) { dest.write16(x, paldata[pendata[pi++]]); } } } } else { if ((flags & TILE_FLIPY) != 0) { y1 = tile_height * row + tile_height - 1; y2 = y1 - tile_height; dy = -1; } else { y1 = tile_height * row; y2 = y1 + tile_height; dy = 1; } if ((flags & TILE_FLIPX) != 0) { tile_width--; for (sy = y1; sy != y2; sy += dy) { _BytePtr dest = new _BytePtr(pixmap.line[sy], sx); for (x = tile_width; x >= 0; x--) { dest[x] = (byte)paldata[pendata[pi++]]; } } } else { for (sy = y1; sy != y2; sy += dy) { _BytePtr dest = new _BytePtr(pixmap.line[sy], sx); for (x = 0; x < tile_width; x++) { dest[x] = (byte)paldata[pendata[pi++]]; } } } } }
public static void YM3812UpdateOne(FM_OPL OPL, _ShortPtr buffer, int length) { int i; int data; _ShortPtr buf = buffer; uint amsCnt = (uint)OPL.amsCnt; uint vibCnt = (uint)OPL.vibCnt; byte rythm = (byte)(OPL.rythm & 0x20); OPL_CH CH; int R_CH; if ((object)OPL != cur_chip) { cur_chip = OPL; /* channel pointers */ S_CH = OPL.P_CH; E_CH = 9;// S_CH[9]; /* rythm slot */ SLOT7_1 = S_CH[7].SLOT[SLOT1]; SLOT7_2 = S_CH[7].SLOT[SLOT2]; SLOT8_1 = S_CH[8].SLOT[SLOT1]; SLOT8_2 = S_CH[8].SLOT[SLOT2]; /* LFO state */ amsIncr = OPL.amsIncr; vibIncr = OPL.vibIncr; ams_table = OPL.ams_table; vib_table = OPL.vib_table; } R_CH = rythm != 0 ? 6 : E_CH; for (i = 0; i < length; i++) { /* channel A channel B channel C */ /* LFO */ ams = ams_table[(int)((amsCnt += (uint)amsIncr) >> AMS_SHIFT)]; vib = vib_table[(int)((vibCnt += (uint)vibIncr) >> VIB_SHIFT)]; outd[0] = 0; /* FM part */ for (int k = 0; k != R_CH; k++) { CH = S_CH[k]; //for(CH=S_CH ; CH < R_CH ; CH++) OPL_CALC_CH(CH); } /* Rythn part */ if (rythm != 0) OPL_CALC_RH(S_CH); /* limit check */ data = Limit(outd[0], OPL_MAXOUT, OPL_MINOUT); /* store to sound buffer */ buf.write16(i, (ushort)(data >> OPL_OUTSB)); } OPL.amsCnt = (int)amsCnt; OPL.vibCnt = (int)vibCnt; }
public static void YM2203UpdateOne(int num, _ShortPtr buffer, int length) { YM2203 F2203 = (FM2203[num]); FM_OPN OPN = (FM2203[num].OPN); int i; FM_CH ch; _ShortPtr buf = new _ShortPtr(buffer); cur_chip = F2203; State = F2203.OPN.ST; cch[0] = F2203.CH[0]; cch[1] = F2203.CH[1]; cch[2] = F2203.CH[2]; #if FM_LFO_SUPPORT /* LFO */ lfo_amd = 0; lfo_pmd = 0; #endif /* frequency counter channel A */ CALC_FCOUNT(cch[0]); /* frequency counter channel B */ CALC_FCOUNT(cch[1]); /* frequency counter channel C */ if ((State.mode & 0xc0) != 0) { /* 3SLOT MODE */ if (cch[2].SLOT[SLOT1].Incr == unchecked((uint)-1)) { /* 3 slot mode */ CALC_FCSLOT(cch[2].SLOT[SLOT1], (int)OPN.SL3.fc[1], OPN.SL3.kcode[1]); CALC_FCSLOT(cch[2].SLOT[SLOT2], (int)OPN.SL3.fc[2], OPN.SL3.kcode[2]); CALC_FCSLOT(cch[2].SLOT[SLOT3], (int)OPN.SL3.fc[0], OPN.SL3.kcode[0]); CALC_FCSLOT(cch[2].SLOT[SLOT4], (int)cch[2].fc, cch[2].kcode); } } else CALC_FCOUNT(cch[2]); for (i = 0; i < length; i++) { /* channel A channel B channel C */ out_ch[OUTD_CENTER] = 0; /* calcrate FM */ //for( ch=cch[0] ; ch <= cch[2] ; ch++) for (int kk = 0; kk < 2; kk++) FM_CALC_CH(cch[kk]); /* limit check */ Limit(ref out_ch[OUTD_CENTER], FM_MAXOUT, FM_MINOUT); /* store to sound buffer */ buf.write16(i, (ushort)(out_ch[OUTD_CENTER] >> FM_OUTSB)); /* timer controll */ INTERNAL_TIMER_A(State, cch[2]); } INTERNAL_TIMER_B(State, length); }
public static void OPMUpdateOne(int num, _ShortPtr[] buffer, int length) { YM2151 OPM = (FMOPM[num]); int i; int amd, pmd; FM_CH ch; _ShortPtr bufL, bufR; /* set bufer */ bufL = buffer[0]; bufR = buffer[1]; if ((object)OPM != cur_chip) { cur_chip = OPM; State = OPM.ST; /* channel pointer */ cch[0] = OPM.CH[0]; cch[1] = OPM.CH[1]; cch[2] = OPM.CH[2]; cch[3] = OPM.CH[3]; cch[4] = OPM.CH[4]; cch[5] = OPM.CH[5]; cch[6] = OPM.CH[6]; cch[7] = OPM.CH[7]; /* ch7.op4 noise mode / step */ NoiseIncr = OPM.NoiseIncr; NoiseCnt = OPM.NoiseCnt; #if FM_LFO_SUPPORT /* LFO */ LFOCnt = OPM.LFOCnt; //LFOIncr = OPM.LFOIncr; if (LFOIncr == 0) { lfo_amd = 0; lfo_pmd = 0; } LFO_wave = OPM.wavetype; #endif } amd = OPM.amd; pmd = OPM.pmd; if (amd == 0 && pmd == 0) LFOIncr = 0; else LFOIncr = OPM.LFOIncr; OPM_CALC_FCOUNT(OPM, cch[0]); OPM_CALC_FCOUNT(OPM, cch[1]); OPM_CALC_FCOUNT(OPM, cch[2]); OPM_CALC_FCOUNT(OPM, cch[3]); OPM_CALC_FCOUNT(OPM, cch[4]); OPM_CALC_FCOUNT(OPM, cch[5]); OPM_CALC_FCOUNT(OPM, cch[6]); /* CSM check */ OPM_CALC_FCOUNT(OPM, cch[7]); for (i = 0; i < length; i++) { #if FM_LFO_SUPPORT /* LFO */ if (LFOIncr != 0) { int depth = LFO_wave[(int)((LFOCnt += LFOIncr) >> LFO_SHIFT)]; lfo_amd = (uint)(depth * amd); lfo_pmd = (depth - (LFO_RATE / 127 / 2)) * pmd; } #endif /* clear output acc. */ out_ch[OUTD_LEFT] = out_ch[OUTD_RIGHT] = out_ch[OUTD_CENTER] = 0; /* calcrate channel output */ //for(ch = cch[0] ; ch <= cch[6] ; ch++) for (int k = 0; k < 6; k++) { ch = cch[k]; FM_CALC_CH(ch); OPM_CALC_CH7(cch[7]); /* buffering */ //FM_BUFFERING_STEREO; #if FM_STEREO_MIX /* stereo mixing */ { /* get left & right output with clipping */ out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; Limit( out_ch[OUTD_LEFT] , FM_MAXOUT, FM_MINOUT ); out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; Limit( out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT ); /* buffering */ ((FMSAMPLE_MIX *)bufL)[i] = ((out_ch[OUTD_LEFT]>>FM_OUTSB)<<FM_OUTPUT_BIT)|(out_ch[OUTD_RIGHT]>>FM_OUTSB); } #else /* stereo separate */ { /* get left & right output with clipping */ out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; Limit(ref out_ch[OUTD_LEFT], FM_MAXOUT, FM_MINOUT); out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; Limit(ref out_ch[OUTD_RIGHT], FM_MAXOUT, FM_MINOUT); /* buffering */ bufL.write16(i, (ushort)(out_ch[OUTD_LEFT] >> FM_OUTSB)); bufR.write16(i, (ushort)(out_ch[OUTD_RIGHT] >> FM_OUTSB)); } #endif /* timer A controll */ INTERNAL_TIMER_A(State, cch[7]); } INTERNAL_TIMER_B(State, length); OPM.NoiseCnt = NoiseCnt; #if FM_LFO_SUPPORT OPM.LFOCnt = LFOCnt; #endif } }
public void streams_sh_update() { if (Machine.sample_rate == 0) return; /* update all the output buffers */ for (int channel = 0; channel < MIXER_MAX_CHANNELS; channel += stream_joined_channels[channel]) { if (stream_buffer[channel] != null) { int newpos = mixer_need_samples_this_frame(channel, stream_sample_rate[(channel)]); int buflen = newpos - stream_buffer_pos[channel]; if (stream_joined_channels[channel] > 1) { _ShortPtr[] buf = new _ShortPtr[MIXER_MAX_CHANNELS]; if (buflen > 0) { for (int i = 0; i < stream_joined_channels[channel]; i++) buf[i] = new _ShortPtr(stream_buffer[channel + i], stream_buffer_pos[channel + i]*sizeof(short)); stream_callback_multi[channel](stream_param[channel], buf, buflen); } for (int i = 0; i < stream_joined_channels[channel]; i++) stream_buffer_pos[channel + i] = 0; for (int i = 0; i < stream_joined_channels[channel]; i++) apply_RC_filter(channel + i, stream_buffer[channel + i], buflen, stream_sample_rate[channel + i]); } else { if (buflen > 0) { _ShortPtr buf= new _ShortPtr(stream_buffer[channel], stream_buffer_pos[channel]*sizeof(short)); stream_callback[channel](stream_param[channel], buf, buflen); } stream_buffer_pos[channel] = 0; apply_RC_filter(channel, stream_buffer[channel], buflen, stream_sample_rate[channel]); } } } for (int channel = 0; channel < MIXER_MAX_CHANNELS; channel += stream_joined_channels[channel]) { if (stream_buffer[channel] != null) { for (int i = 0; i < stream_joined_channels[channel]; i++) mixer_play_streamed_sample_16(channel + i, stream_buffer[channel + i], sizeof(short) * mixer_need_samples_this_frame((channel + i), stream_sample_rate[(channel + i)]), stream_sample_rate[channel]); } } }
static void YM3812UpdateHandler(int n, _ShortPtr buf, int length) { FMOPL.YM3812UpdateOne(F3812[n], buf, length); }
public static void fillbitmap(osd_bitmap dest, int pen, rectangle clip) { FuncDict["fillbitmap"] = "fillbitmap"; rectangle myclip = new rectangle(); if ((Machine.orientation & ORIENTATION_SWAP_XY) != 0) { if (clip != null) { myclip.min_x = clip.min_y; myclip.max_x = clip.max_y; myclip.min_y = clip.min_x; myclip.max_y = clip.max_x; clip = myclip; } } if ((Machine.orientation & ORIENTATION_FLIP_X) != 0) { if (clip != null) { int temp = clip.min_x; myclip.min_x = dest.width - 1 - clip.max_x; myclip.max_x = dest.width - 1 - temp; myclip.min_y = clip.min_y; myclip.max_y = clip.max_y; clip = myclip; } } if ((Machine.orientation & ORIENTATION_FLIP_Y) != 0) { if (clip != null) { myclip.min_x = clip.min_x; myclip.max_x = clip.max_x; int temp = clip.min_y; myclip.min_y = dest.height - 1 - clip.max_y; myclip.max_y = dest.height - 1 - temp; clip = myclip; } } int sx = 0; int ex = dest.width - 1; int sy = 0; int ey = dest.height - 1; if (clip != null && sx < clip.min_x) sx = clip.min_x; if (clip != null && ex > clip.max_x) ex = clip.max_x; if (sx > ex) return; if (clip != null && sy < clip.min_y) sy = clip.min_y; if (clip != null && ey > clip.max_y) ey = clip.max_y; if (sy > ey) return; osd_mark_dirty(sx, sy, ex, ey, 0); /* ASG 971011 */ /* ASG 980211 */ if (dest.depth == 16) { if ((pen >> 8) == (pen & 0xff)) { for (int y = sy; y <= ey; y++) { for (int k = 0; k < (ex - sx + 1) * 2; k++) dest.line[y][sx * 2 + k] = (byte)(pen & 0xff); } //memset(&dest.line[y][sx*2],pen&0xff,(ex-sx+1)*2); } else { _ShortPtr sp = new _ShortPtr(dest.line[sy]); int x; for (x = sx; x <= ex; x++) sp.write16(x, (ushort)pen); sp.offset += sx * 2; for (int y = sy + 1; y <= ey; y++) { Buffer.BlockCopy(sp.buffer, sp.offset, dest.line[y].buffer, sx * 2, (ex - sx + 1) * 2); } //memcpy(&dest.line[y][sx*2],sp,(ex-sx+1)*2); } } else { for (int y = sy; y <= ey; y++) { for (int k = 0; k < ex - sx + 1; k++) dest.line[y][sx + k] = (byte)pen; } } }
static void blockmove_opaque_noremap_flipx16(_ShortPtr srcdata, int srcwidth, int srcheight, int srcmodulo, _ShortPtr dstdata, int dstmodulo) { throw new Exception(); }
static void drawgfx_core16(osd_bitmap dest, GfxElement gfx, uint code, uint color, bool flipx, bool flipy, int sx, int sy, rectangle clip, int transparency, int transparent_color) { int ox; int oy; int ex; int ey; /* check bounds */ ox = sx; oy = sy; ex = sx + gfx.width - 1; if (sx < 0) sx = 0; if (clip != null && sx < clip.min_x) sx = clip.min_x; if (ex >= dest.width) ex = dest.width - 1; if (clip != null && ex > clip.max_x) ex = clip.max_x; if (sx > ex) return; ey = sy + gfx.height - 1; if (sy < 0) sy = 0; if (clip != null && sy < clip.min_y) sy = clip.min_y; if (ey >= dest.height) ey = dest.height - 1; if (clip != null && ey > clip.max_y) ey = clip.max_y; if (sy > ey) return; osd_mark_dirty(sx, sy, ex, ey, 0); /* ASG 971011 */ { _BytePtr sd = new _BytePtr(gfx.gfxdata, (int)(code * gfx.char_modulo)); /* source data */ int sw = ex - sx + 1; /* source width */ int sh = ey - sy + 1; /* source height */ int sm = gfx.line_modulo; /* source modulo */ _ShortPtr dd = new _ShortPtr(dest.line[sy], sx); /* dest data */ int dm = dest.line[1].offset - dest.line[0].offset; /* dest modulo */ UShortSubArray paldata = new UShortSubArray(gfx.colortable, (int)((gfx.color_granularity * color))); if (flipx) { sd.offset += gfx.width - 1 - (sx - ox); } else sd.offset += (sx - ox); if (flipy) { sd.offset += sm * (gfx.height - 1 - (sy - oy)); sm = -sm; } else sd.offset += sm * (sy - oy); switch (transparency) { case TRANSPARENCY_NONE: if (flipx) blockmove_opaque_flipx16(sd, sw, sh, sm, dd, dm, paldata); else blockmove_opaque16(sd, sw, sh, sm, dd, dm, paldata); break; case TRANSPARENCY_PEN: if (flipx) blockmove_transpen_flipx16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); else blockmove_transpen16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); break; case TRANSPARENCY_PENS: if (flipx) blockmove_transmask_flipx16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); else blockmove_transmask16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); break; case TRANSPARENCY_COLOR: if (flipx) blockmove_transcolor_flipx16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); else blockmove_transcolor16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); break; case TRANSPARENCY_THROUGH: if (flipx) blockmove_transthrough_flipx16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); else blockmove_transthrough16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); break; case TRANSPARENCY_PEN_TABLE: if (flipx) blockmove_pen_table_flipx16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); else blockmove_pen_table16(sd, sw, sh, sm, dd, dm, paldata, transparent_color); break; } } }
public override int start(xnamame036.mame.Mame.MachineSound msound) { string mono_name = "NAMCO sound"; string[] stereo_names = { "NAMCO sound left", "NAMCO sound right" }; Namco_interface intf = (Namco_interface)msound.sound_interface; namco_clock = intf.samplerate; sample_rate = Mame.Machine.sample_rate; /* get stream channels */ if (intf.stereo) { int[] vol = new int[2]; vol[1] = Mame.MIXER(intf.volume, Mame.MIXER_PAN_RIGHT); vol[0] = Mame.MIXER(intf.volume, Mame.MIXER_PAN_LEFT); stream = Mame.stream_init_multi(2, stereo_names, vol, intf.samplerate, 0, namco_update_stereo); } else { stream = Mame.stream_init(mono_name, intf.volume, intf.samplerate, 0, namco_update_mono); } /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */ mixer_buffer = new _ShortPtr(2 * intf.samplerate * sizeof(short) ); mixer_buffer_2 = new _ShortPtr(mixer_buffer, intf.samplerate * sizeof(short)); /* build the mixer table */ make_mixer_table(intf.voices); /* extract globals from the interface */ num_voices = intf.voices; last_channel = num_voices; if (intf.region == -1) { sound_prom = namco_wavedata; samples_per_byte = 2; /* first 4 high bits, then low 4 bits */ } else { sound_prom = Mame.memory_region(intf.region); samples_per_byte = 1; /* use only low 4 bits */ } /* start with sound enabled, many games don't have a sound enable register */ sound_enable = true; /* reset all the voices */ for (int i = 0; i < last_channel; i++) //for (voice = channel_list; voice < last_channel; voice++) { channel_list[i] = new sound_channel(); channel_list[i].frequency = 0; channel_list[i].volume[0] = channel_list[i].volume[1] = 0; channel_list[i].wave = sound_prom; channel_list[i].counter = 0; channel_list[i].noise_sw = 0; channel_list[i].noise_state = 0; channel_list[i].noise_seed = 1; channel_list[i].noise_counter = 0; } return 0; }
static void blockmove_opaque_flipx16(_BytePtr srcdata, int srcwidth, int srcheight, int srcmodulo, _ShortPtr dstdata, int dstmodulo, UShortSubArray paldata) { throw new Exception(); }
void apply_RC_filter(int channel, _ShortPtr buf, int len, int sample_rate) { if (c[channel] == 0) return; /* filter disabled */ float R1 = r1[channel]; float R2 = r2[channel]; float R3 = r3[channel]; float C = (float)(c[channel] * 1E-12); /* convert pF to F */ /* Cut Frequency = 1/(2*Pi*Req*C) */ float Req = (R1 * (R2 + R3)) / (R1 + R2 + R3); int K = (int)(0x10000 * Math.Exp(-1 / (Req * C) / sample_rate)); buf.write16(0, (ushort)(buf.read16(0) + (memory[channel] - buf.read16(0)) * K / 0x10000)); for (int i = 1; i < len; i++) buf.write16(i, (ushort)(buf.read16(i) + (buf.read16(i - 1) - buf.read16(i)) * K / 0x10000)); memory[channel] = buf.read16(len - 1); }
static void blockmove_pen_table_flipx16(_BytePtr srcdata, int srcwidth, int srcheight, int srcmodulo, _ShortPtr dstdata, int dstmodulo, UShortSubArray paldata, int transcolor) { throw new Exception(); }
void namco_update_mono(int ch, _ShortPtr buffer, int length) { _ShortPtr mix; /* if no sound, we're done */ if (!sound_enable) { Array.Clear(buffer.buffer, buffer.offset, length*2); return; } /* zap the contents of the mixer buffer */ Array.Clear(mixer_buffer.buffer, mixer_buffer.offset, length * 2); /* loop over each voice and add its contribution */ for (int voice=0;voice<last_channel;voice++)//; voice < last_channel; voice++) { int f = channel_list[voice].frequency; int v = channel_list[voice].volume[0]; mix = new _ShortPtr(mixer_buffer); if (channel_list[voice].noise_sw != 0) { /* only update if we have non-zero volume and frequency */ if (v != 0 && (f & 0xff) != 0) { float fbase = (float)sample_rate / (float)namco_clock; int delta = (int)((float)((f & 0xff) << 4) * fbase); int c = channel_list[voice].noise_counter; /* add our contribution */ for (int i = 0; i < length; i++) { int noise_data; int cnt; if (channel_list[voice].noise_state != 0) noise_data = 0x07; else noise_data = -0x07; mix.write16(0, (ushort)((short)mix.read16(0) + noise_data * (v >> 1))); mix.offset += 2; c += delta; cnt = (c >> 12); c &= (1 << 12) - 1; for (; cnt > 0; cnt--) { if (((channel_list[voice].noise_seed + 1) & 2) != 0) channel_list[voice].noise_state ^= 1; if ((channel_list[voice].noise_seed & 1) != 0) channel_list[voice].noise_seed ^= 0x28000; channel_list[voice].noise_seed >>= 1; } } /* update the counter for this voice */ channel_list[voice].noise_counter = c; } } else { /* only update if we have non-zero volume and frequency */ if (v != 0 && f != 0) { int c = channel_list[voice].counter; /* add our contribution */ for (int i = 0; i < length; i++) { c += f; int offs = (c >> 15) & 0x1f; //ushort currentmix = mix.read16(0); if (samples_per_byte == 1) /* use only low 4 bits */ { mix.write16(0, (ushort)((short)mix.read16(0) + ((channel_list[voice].wave[offs] & 0x0f) - 8) * v)); mix.offset += 2; } else /* use full byte, first the high 4 bits, then the low 4 bits */ { if ((offs & 1) != 0) { mix.write16(0, (ushort)((short)mix.read16(0) + ((channel_list[voice].wave[offs >> 1] & 0x0f) - 8) * v)); mix.offset += 2; } else { mix.write16(0, (ushort)((short)mix.read16(0) + (((channel_list[voice].wave[offs >> 1] >> 4) & 0x0f) - 8) * v)); mix.offset += 2; } } } /* update the counter for this voice */ channel_list[voice].counter = c; } } } /* mix it down */ mix = new _ShortPtr(mixer_buffer); for (int i = 0; i < length; i++) { buffer.write16(0, (ushort)mixer_lookup[mixer_lookup_middle+(short)mix.read16(0)]); buffer.offset += 2; mix.offset += 2; } }
static void blockmove_transthrough_noremap_flipx16(_ShortPtr srcdata, int srcwidth, int srcheight, int srcmodulo, _ShortPtr dstdata, int dstmodulo, int transcolor) { throw new Exception(); }
void AY8910Update(int chip, _ShortPtr[] buffer, int length) { AY8910 PSG = AYPSG[chip]; _ShortPtr buf1, buf2, buf3; int outn; buf1 = buffer[0]; buf2 = buffer[1]; buf3 = buffer[2]; /* The 8910 has three outputs, each output is the mix of one of the three */ /* tone generators and of the (single) noise generator. The two are mixed */ /* BEFORE going into the DAC. The formula to mix each channel is: */ /* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */ /* Note that this means that if both tone and noise are disabled, the output */ /* is 1, not 0, and can be modulated changing the volume. */ /* If the channels are disabled, set their output to 1, and increase the */ /* counter, if necessary, so they will not be inverted during this update. */ /* Setting the output to 1 is necessary because a disabled channel is locked */ /* into the ON state (see above); and it has no effect if the volume is 0. */ /* If the volume is 0, increase the counter, but don't touch the output. */ if ((PSG.Regs[AY_ENABLE] & 0x01) != 0) { if (PSG.CountA <= length * STEP) PSG.CountA += length * STEP; PSG.OutputA = 1; } else if (PSG.Regs[AY_AVOL] == 0) { /* note that I do count += length, NOT count = length + 1. You might think */ /* it's the same since the volume is 0, but doing the latter could cause */ /* interferencies when the program is rapidly modulating the volume. */ if (PSG.CountA <= length * STEP) PSG.CountA += length * STEP; } if ((PSG.Regs[AY_ENABLE] & 0x02) != 0) { if (PSG.CountB <= length * STEP) PSG.CountB += length * STEP; PSG.OutputB = 1; } else if (PSG.Regs[AY_BVOL] == 0) { if (PSG.CountB <= length * STEP) PSG.CountB += length * STEP; } if ((PSG.Regs[AY_ENABLE] & 0x04) != 0) { if (PSG.CountC <= length * STEP) PSG.CountC += length * STEP; PSG.OutputC = 1; } else if (PSG.Regs[AY_CVOL] == 0) { if (PSG.CountC <= length * STEP) PSG.CountC += length * STEP; } /* for the noise channel we must not touch OutputN - it's also not necessary */ /* since we use outn. */ if ((PSG.Regs[AY_ENABLE] & 0x38) == 0x38) /* all off */ if (PSG.CountN <= length * STEP) PSG.CountN += length * STEP; outn = (PSG.OutputN | PSG.Regs[AY_ENABLE]); /* buffering loop */ while (length != 0) { int vola, volb, volc; int left; /* vola, volb and volc keep track of how long each square wave stays */ /* in the 1 position during the sample period. */ vola = volb = volc = 0; left = STEP; do { int nextevent; if (PSG.CountN < left) nextevent = PSG.CountN; else nextevent = left; if ((outn & 0x08) != 0) { if (PSG.OutputA != 0) vola += PSG.CountA; PSG.CountA -= nextevent; /* PeriodA is the half period of the square wave. Here, in each */ /* loop I add PeriodA twice, so that at the end of the loop the */ /* square wave is in the same status (0 or 1) it was at the start. */ /* vola is also incremented by PeriodA, since the wave has been 1 */ /* exactly half of the time, regardless of the initial position. */ /* If we exit the loop in the middle, OutputA has to be inverted */ /* and vola incremented only if the exit status of the square */ /* wave is 1. */ while (PSG.CountA <= 0) { PSG.CountA += PSG.PeriodA; if (PSG.CountA > 0) { PSG.OutputA ^= 1; if (PSG.OutputA != 0) vola += PSG.PeriodA; break; } PSG.CountA += PSG.PeriodA; vola += PSG.PeriodA; } if (PSG.OutputA != 0) vola -= PSG.CountA; } else { PSG.CountA -= nextevent; while (PSG.CountA <= 0) { PSG.CountA += PSG.PeriodA; if (PSG.CountA > 0) { PSG.OutputA ^= 1; break; } PSG.CountA += PSG.PeriodA; } } if ((outn & 0x10) != 0) { if (PSG.OutputB != 0) volb += PSG.CountB; PSG.CountB -= nextevent; while (PSG.CountB <= 0) { PSG.CountB += PSG.PeriodB; if (PSG.CountB > 0) { PSG.OutputB ^= 1; if (PSG.OutputB != 0) volb += PSG.PeriodB; break; } PSG.CountB += PSG.PeriodB; volb += PSG.PeriodB; } if (PSG.OutputB != 0) volb -= PSG.CountB; } else { PSG.CountB -= nextevent; while (PSG.CountB <= 0) { PSG.CountB += PSG.PeriodB; if (PSG.CountB > 0) { PSG.OutputB ^= 1; break; } PSG.CountB += PSG.PeriodB; } } if ((outn & 0x20) != 0) { if (PSG.OutputC != 0) volc += PSG.CountC; PSG.CountC -= nextevent; while (PSG.CountC <= 0) { PSG.CountC += PSG.PeriodC; if (PSG.CountC > 0) { PSG.OutputC ^= 1; if (PSG.OutputC != 0) volc += PSG.PeriodC; break; } PSG.CountC += PSG.PeriodC; volc += PSG.PeriodC; } if (PSG.OutputC != 0) volc -= PSG.CountC; } else { PSG.CountC -= nextevent; while (PSG.CountC <= 0) { PSG.CountC += PSG.PeriodC; if (PSG.CountC > 0) { PSG.OutputC ^= 1; break; } PSG.CountC += PSG.PeriodC; } } PSG.CountN -= nextevent; if (PSG.CountN <= 0) { /* Is noise output going to change? */ if (((PSG.RNG + 1) & 2) != 0) /* (bit0^bit1)? */ { PSG.OutputN = (byte)~PSG.OutputN; outn = (PSG.OutputN | PSG.Regs[AY_ENABLE]); } /* The Random Number Generator of the 8910 is a 17-bit shift */ /* register. The input to the shift register is bit0 XOR bit2 */ /* (bit0 is the output). */ /* The following is a fast way to compute bit 17 = bit0^bit2. */ /* Instead of doing all the logic operations, we only check */ /* bit 0, relying on the fact that after two shifts of the */ /* register, what now is bit 2 will become bit 0, and will */ /* invert, if necessary, bit 16, which previously was bit 18. */ if ((PSG.RNG & 1) != 0) PSG.RNG ^= 0x28000; PSG.RNG >>= 1; PSG.CountN += PSG.PeriodN; } left -= nextevent; } while (left > 0); /* update envelope */ if (PSG.Holding == 0) { PSG.CountE -= STEP; if (PSG.CountE <= 0) { do { PSG.CountEnv--; PSG.CountE += PSG.PeriodE; } while (PSG.CountE <= 0); /* check envelope current position */ if (PSG.CountEnv < 0) { if (PSG.Hold != 0) { if (PSG.Alternate != 0) PSG.Attack ^= 0x1f; PSG.Holding = 1; PSG.CountEnv = 0; } else { /* if CountEnv has looped an odd number of times (usually 1), */ /* invert the output. */ if (PSG.Alternate != 0 && (PSG.CountEnv & 0x20) != 0) PSG.Attack ^= 0x1f; PSG.CountEnv &= 0x1f; } } PSG.VolE = PSG.VolTable[PSG.CountEnv ^ PSG.Attack]; /* reload volume */ if (PSG.EnvelopeA != 0) PSG.VolA = PSG.VolE; if (PSG.EnvelopeB != 0) PSG.VolB = PSG.VolE; if (PSG.EnvelopeC != 0) PSG.VolC = PSG.VolE; } } buf1.write16(0, (ushort)((vola * PSG.VolA) / STEP)); buf2.write16(0, (ushort)((volb * PSG.VolB) / STEP)); buf3.write16(0, (ushort)((volc * PSG.VolC) / STEP)); buf1.offset += 2; buf2.offset += 2; buf3.offset += 2; length--; } }