static byte apu_noise(noise_t chan) {
        int freq, env_delay;
        /*uint8*/
        int outvol;
        /*uint8*/
        int output;

        /* reg0: 0-3=volume, 4=envelope, 5=hold
         ** reg2: 7=small(93 byte) sample,3-0=freq lookup
         ** reg3: 7-4=vbl length counter
         */
        if (false == chan.enabled) {
            return 0;
        }

        /* enveloping */
        env_delay = sync_times1[chan.regs[0] & 0x0F];

        /* decay is at a rate of (env_regs + 1) / 240 secs */
        chan.env_phase -= 4;
        while (chan.env_phase < 0) {
            chan.env_phase += env_delay;
            if ((chan.regs[0] & 0x20) != 0) {
                chan.env_vol = ((chan.env_vol + 1) & 15) & 0xFF;
            } else if (chan.env_vol < 15) {
                chan.env_vol++;
            }
        }

        /* length counter */
        if (0 == (chan.regs[0] & 0x20)) {
            if (chan.vbl_length > 0) {
                chan.vbl_length--;
            }
        }

        if (0 == chan.vbl_length) {
            return 0;
        }

        freq = noise_freq[chan.regs[2] & 0x0F];
        chan.phaseacc -= (float) apu_incsize; /* # of cycles per sample */

        while (chan.phaseacc < 0) {
            chan.phaseacc += freq;

            chan.cur_pos++;
            if (NOISE_SHORT == chan.cur_pos && (chan.regs[2] & 0x80) != 0) {
                chan.cur_pos = 0;
            } else if (NOISE_LONG == chan.cur_pos) {
                chan.cur_pos = 0;
            }
        }

        if ((chan.regs[0] & 0x10) != 0)/* fixed volume */ {
            outvol = chan.regs[0] & 0x0F;
        } else {
            outvol = (0x0F - chan.env_vol) & 0xFF;
        }

        output = noise_lut[chan.cur_pos];
        if (output > outvol) {
            output = outvol;
        }

        if ((noise_lut[chan.cur_pos] & 0x80) != 0) /* make it negative */ {
            output = -output;
        }

        return (byte) output;
    }