public override int start(Mame.MachineSound msound)
            {
                int i, j, sweep, charge, countdown, generator, bit1, bit2;
                int[] lfovol = { LFO_VOLUME, LFO_VOLUME, LFO_VOLUME };

#if SAMPLES
                Mame.Machine.samples = Mame.readsamples(galaxian_sample_names, Mame.Machine.gamedrv.name);
#endif

                channelnoise = Mame.mixer_allocate_channel(NOISE_VOLUME);
                Mame.mixer_set_name(channelnoise, "Noise");
                channelshoot = Mame.mixer_allocate_channel(SHOOT_VOLUME);
                Mame.mixer_set_name(channelshoot, "Shoot");
                channellfo = Mame.mixer_allocate_channels(3, lfovol);
                Mame.mixer_set_name(channellfo + 0, "Background #0");
                Mame.mixer_set_name(channellfo + 1, "Background #1");
                Mame.mixer_set_name(channellfo + 2, "Background #2");

#if SAMPLES
                if (Mame.Machine.samples != null && Mame.Machine.samples.sample[0] != null)	/* We should check also that Samplename[0] = 0 */
                    shootsampleloaded = 1;
                else
                    shootsampleloaded = 0;

                if (Mame.Machine.samples != null && Mame.Machine.samples.sample[1] != null)	/* We should check also that Samplename[0] = 0 */
                    deathsampleloaded = 1;
                else
                    deathsampleloaded = 0;
#endif

                if ((noisewave = new _ShortPtr((int)(NOISE_LENGTH * sizeof(short)))) == null)
                {
                    return 1;
                }

#if NEW_SHOOT
                byte SHOOT_SEC = 2;
                shoot_rate = Mame.Machine.sample_rate;
                shoot_length = SHOOT_SEC * shoot_rate;
                if ((shootwave = new _ShortPtr(shoot_length * sizeof(short))) == null)
#else
	if( (shootwave = new _ShortPtr(SHOOT_LENGTH * sizeof(short))) == null )
#endif
                {
                    noisewave = null;
                    return 1;
                }

                /*
                 * The RNG shifter is clocked with RNG_RATE, bit 17 is
                 * latched every 2V cycles (every 2nd scanline).
                 * This signal is used as a noise source.
                 */
                generator = 0;
                countdown = (int)(NOISE_RATE / 2);
                for (i = 0; i < NOISE_LENGTH; i++)
                {
                    countdown -= (int)RNG_RATE;
                    while (countdown < 0)
                    {
                        generator <<= 1;
                        bit1 = (~generator >> 17) & 1;
                        bit2 = (generator >> 5) & 1;
                        if ((bit1 ^ bit2) != 0) generator |= 1;
                        countdown += (int)NOISE_RATE;
                    }
                    noisewave.write16(i, (ushort)(((generator >> 17) & 1) != 0 ? (ushort)NOISE_AMPLITUDE : -(ushort)NOISE_AMPLITUDE));
                }

#if NEW_SHOOT

                /* dummy */
                sweep = 100;
                charge = +2;
                j = 0;
                {
                    int R41__ = 100000;
                    int R44__ = 10000;
                    int R45__ = 22000;
                    int R46__ = 10000;
                    int R47__ = 2200;
                    int R48__ = 2200;
                    double C25__ = 0.000001;
                    double C27__ = 0.00000001;
                    double C28__ = 0.000047;
                    double C29__ = 0.00000001;
                    double IC8L3_L = 0.2;  /* 7400 L level */
                    double IC8L3_H = 4.5; /* 7400 H level */
                    double NOISE_L = 0.2;  /* 7474 L level */
                    double NOISE_H = 4.5;   /* 7474 H level */
                    /*
                        key on/off time is programmable
                        Therefore,  it is necessary to make separate sample with key on/off.
                        And,  calculate the playback point according to the voltage of c28.
                    */
                    double SHOOT_KEYON_TIME = 0.1;  /* second */
                    /*
                        NE555-FM input calculation is wrong.
                        The frequency is not proportional to the voltage of FM input.
                        And,  duty will be changed,too.
                    */
                    double NE555_FM_ADJUST_RATE = 0.80;
                    /* discharge : 100K * 1uF */
                    double v = 5.0;
                    double vK = (shoot_rate) != 0 ? Math.Exp(-1 / (R41__ * C25__) / shoot_rate) : 0;
                    /* -- SHOOT KEY port -- */
                    double IC8L3 = IC8L3_L; /* key on */
                    int IC8Lcnt = (int)(SHOOT_KEYON_TIME * shoot_rate); /* count for key off */
                    /* C28 : KEY port capacity */
                    /*       connection : 8L-3 - R47(2.2K) - C28(47u) - R48(2.2K) - C29 */
                    double c28v = IC8L3_H - (IC8L3_H - (NOISE_H + NOISE_L) / 2) / (R46__ + R47__ + R48__) * R47__;
                    double c28K = (shoot_rate) != 0 ? Math.Exp(-1 / (22000 * 0.000047) / shoot_rate) : 0;
                    /* C29 : NOISE capacity */
                    /*       connection : NOISE - R46(10K) - C29(0.1u) - R48(2.2K) - C28 */
                    double c29v = IC8L3_H - (IC8L3_H - (NOISE_H + NOISE_L) / 2) / (R46__ + R47__ + R48__) * (R47__ + R48__);
                    double c29K1 = (shoot_rate) != 0 ? Math.Exp(-1 / (22000 * 0.00000001) / shoot_rate) : 0; /* form C28   */
                    double c29K2 = (shoot_rate) != 0 ? Math.Exp(-1 / (100000 * 0.00000001) / shoot_rate) : 0; /* from noise */
                    /* NE555 timer */
                    /* RA = 10K , RB = 22K , C=.01u ,FM = C29 */
                    double ne555cnt = 0;
                    double ne555step = (shoot_rate) != 0 ? ((1.44 / ((R44__ + R45__ * 2) * C27__)) / shoot_rate) : 0;
                    double ne555duty = (double)(R44__ + R45__) / (R44__ + R45__ * 2); /* t1 duty */
                    double ne555sr;		/* threshold (FM) rate */
                    /* NOISE source */
                    double ncnt = 0.0;
                    double nstep = (shoot_rate) != 0 ? ((double)NOISE_RATE / shoot_rate) : 0;
                    double noise_sh2; /* voltage level */

                    for (i = 0; i < shoot_length; i++)
                    {
                        /* noise port */
                        noise_sh2 = noisewave.read16((int)(ncnt % NOISE_LENGTH)) == NOISE_AMPLITUDE ? NOISE_H : NOISE_L;
                        ncnt += nstep;
                        /* calculate NE555 threshold level by FM input */
                        ne555sr = c29v * NE555_FM_ADJUST_RATE / (5.0 * 2 / 3);
                        /* calc output */
                        ne555cnt += ne555step;
                        if (ne555cnt >= ne555sr) ne555cnt -= ne555sr;
                        if (ne555cnt < ne555sr * ne555duty)
                        {
                            /* t1 time */
                            shootwave.write16(i, (ushort)(v / 5 * 0x7fff));
                            /* discharge output level */
                            if (IC8L3 == IC8L3_H)
                                v *= vK;
                        }
                        else
                            shootwave.write16(i, 0);
                        /* C28 charge/discharge */
                        c28v += (IC8L3 - c28v) - (IC8L3 - c28v) * c28K;	/* from R47 */
                        c28v += (c29v - c28v) - (c29v - c28v) * c28K;		/* from R48 */
                        /* C29 charge/discharge */
                        c29v += (c28v - c29v) - (c28v - c29v) * c29K1;	/* from R48 */
                        c29v += (noise_sh2 - c29v) - (noise_sh2 - c29v) * c29K2;	/* from R46 */
                        /* key off */
                        if (IC8L3 == IC8L3_L && --IC8Lcnt == 0)
                            IC8L3 = IC8L3_H;
                    }
                }
#else
	/*
	 * Ra is 10k, Rb is 22k, C is 0.01uF
	 * charge time t1 = 0.693 * (Ra + Rb) * C . 221.76us
	 * discharge time t2 = 0.693 * (Rb) *  C . 152.46us
	 * average period 374.22us . 2672Hz
	 * I use an array of 10 values to define some points
	 * of the charge/discharge curve. The wave is modulated
	 * using the charge/discharge timing of C28, a 47uF capacitor,
	 * over a 2k2 resistor. This will change the frequency from
	 * approx. Favg-Favg/3 up to Favg+Favg/3 down to Favg-Favg/3 again.
	 */
	sweep = 100;
	charge = +2;
	countdown = sweep / 2;
	for( i = 0, j = 0; i < SHOOT_LENGTH; i++ )
	{
		
		shootwave[i] = charge_discharge[j];
		LOG((errorlog, "shoot[%5d] $%04x (sweep: %3d, j:%d)\n", i, shootwave[i] & 0xffff, sweep, j));
		/*
		 * The current sweep and a 2200/10000 fraction (R45 and R48)
		 * of the noise are frequency modulating the NE555 chip.
		 */
		countdown -= sweep + noisewave[i % NOISE_LENGTH] / (2200*NOISE_AMPLITUDE/10000);
		while( countdown < 0 )
		{
			countdown += 100;
			j = ++j % 10;
		}
		/* sweep from 100 to 133 and down to 66 over the time of SHOOT_LENGTH */
		if( i % (SHOOT_LENGTH / 33 / 3 ) == 0 )
		{
			sweep += charge;
			if( sweep >= 133 )
				charge = -1;
		}
	}
#endif

                //memset(tonewave, 0, sizeof(tonewave));

                for (i = 0; i < TOOTHSAW_LENGTH; i++)
                {
                    //#define V(r0,r1) 2*TOOTHSAW_AMPLITUDE*(r0)/(r0+r1)-TOOTHSAW_AMPLITUDE
                    double r0a = 1.0 / 1e12, r1a = 1.0 / 1e12;
                    double r0b = 1.0 / 1e12, r1b = 1.0 / 1e12;

                    /* #0: VOL1=0 and VOL2=0
                     * only the 33k and the 22k resistors R51 and R50
                     */
                    if ((i & 1) != 0)
                    {
                        r1a += 1.0 / 33000;
                        r1b += 1.0 / 33000;
                    }
                    else
                    {
                        r0a += 1.0 / 33000;
                        r0b += 1.0 / 33000;
                    }
                    if ((i & 4) != 0)
                    {
                        r1a += 1.0 / 22000;
                        r1b += 1.0 / 22000;
                    }
                    else
                    {
                        r0a += 1.0 / 22000;
                        r0b += 1.0 / 22000;
                    }
                    for (int k = 0; k < 4; k++) tonewave[k] = new _BytePtr(TOOTHSAW_LENGTH);
                    tonewave[0][i] = (byte)V(1.0 / r0a, 1.0 / r1a);
                    //#define V(r0,r1) 2*TOOTHSAW_AMPLITUDE*(r0)/(r0+r1)-TOOTHSAW_AMPLITUDE

                    /* #1: VOL1=1 and VOL2=0
                     * add the 10k resistor R49 for bit QC
                     */
                    if ((i & 4) != 0)
                        r1a += 1.0 / 10000;
                    else
                        r0a += 1.0 / 10000;
                    tonewave[1][i] = (byte)V(1.0 / r0a, 1.0 / r1a);

                    /* #2: VOL1=0 and VOL2=1
                     * add the 15k resistor R52 for bit QD
                     */
                    if ((i & 8) != 0)
                        r1b += 1.0 / 15000;
                    else
                        r0b += 1.0 / 15000;
                    tonewave[2][i] = (byte)V(1.0 / r0b, 1.0 / r1b);

                    /* #3: VOL1=1 and VOL2=1
                     * add the 10k resistor R49 for QC
                     */
                    if ((i & 4) != 0)
                        r0b += 1.0 / 10000;
                    else
                        r1b += 1.0 / 10000;
                    tonewave[3][i] = (byte)V(1.0 / r0b, 1.0 / r1b);
                    //LOG((errorlog, "tone[%2d]: $%02x $%02x $%02x $%02x\n", i, tonewave[0][i], tonewave[1][i], tonewave[2][i], tonewave[3][i]));
                }

                pitch = 0;
                vol = 0;

                tone_stream = Mame.stream_init("Tone", TOOTHSAW_VOLUME, (int)(SOUND_CLOCK / STEPS), 0, tone_update);

#if SAMPLES
                if (deathsampleloaded == 0)
#endif
                {
                    Mame.mixer_set_volume(channelnoise, 0);
                    Mame.mixer_play_sample_16(channelnoise, noisewave, (int)NOISE_LENGTH, (int)NOISE_RATE, true);
                }
#if SAMPLES
                if (shootsampleloaded == 0)
#endif
                {
                    Mame.mixer_set_volume(channelshoot, 0);
                    Mame.mixer_play_sample_16(channelshoot, shootwave, SHOOT_LENGTH, SHOOT_RATE, false);
                }

                Mame.mixer_set_volume(channellfo + 0, 0);
                Mame.mixer_play_sample_16(channellfo + 0, backgroundwave, backgroundwave.buffer.Length / 2, 1000, true);
                Mame.mixer_set_volume(channellfo + 1, 0);
                Mame.mixer_play_sample_16(channellfo + 1, backgroundwave, backgroundwave.buffer.Length / 2, 1000, true);
                Mame.mixer_set_volume(channellfo + 2, 0);
                Mame.mixer_play_sample_16(channellfo + 2, backgroundwave, backgroundwave.buffer.Length / 2, 1000, true);

                return 0;
            }
示例#2
0
        static void shuffle(_ShortPtr buf, int len)
        {
            if (len == 2) return;

            if ((len % 4) != 0) throw new Exception();   /* must not happen */

            len /= 2;

            for (int i = 0; i < len / 2; i++)
            {
                ushort t = buf.read16(len / 2 + i);
                buf.write16(len / 2 + i, buf.read16(len + i));
                buf.write16(len + i, t);
            }

            shuffle(buf, len);
            shuffle(new _ShortPtr(buf, len*2 ), len);
        }