void sound_beeper( int on ) { static int beeper_ampl[] = { 0, AMPL_TAPE, AMPL_BEEPER, AMPL_BEEPER+AMPL_TAPE }; int val; int ampl; if( !sound_enabled ) return; /* Timex machines have no loading noise */ if( tape_is_playing() && ( !settings_current.sound_load || machine_current->timex ) ) on = on & 0x02; ampl = beeper_ampl[on]; val = -beeper_ampl[3] + ampl*2; blip_synth_update( left_beeper_synth, tstates, val ); if( sound_stereo ) { blip_synth_update( right_beeper_synth, tstates, val ); } }
/* * sound_specdrum_write - very simple routine * as the output is already a digitized waveform */ void sound_specdrum_write( libspectrum_word port GCC_UNUSED, libspectrum_byte val ) { if( periph_is_active( PERIPH_TYPE_SPECDRUM ) ) { blip_synth_update( left_specdrum_synth, tstates, ( val - 128) * 128); if( right_specdrum_synth ) { blip_synth_update( right_specdrum_synth, tstates, ( val - 128) * 128); } machine_current->specdrum.specdrum_dac = val - 128; } }
void sound_beeper( int on ) { static int beeper_ampl[] = { 0, AMPL_TAPE, AMPL_BEEPER, AMPL_BEEPER+AMPL_TAPE }; int val; if( !sound_enabled ) return; if( tape_is_playing() ) { /* Timex machines have no loading noise */ if( !settings_current.sound_load || machine_current->timex ) on = on & 0x02; } else { /* ULA book says that MIC only isn't enough to drive the speaker as output voltage is below the 1.4v threshold */ if( on == 1 ) on = 0; } val = -beeper_ampl[3] + beeper_ampl[on]*2; blip_synth_update( left_beeper_synth, tstates, val ); if( sound_stereo_ay != SOUND_STEREO_AY_NONE ) blip_synth_update( right_beeper_synth, tstates, val ); }
static void sound_ay_overlay( void ) { static int rng = 1; static int noise_toggle = 0; static int env_first = 1, env_rev = 0, env_counter = 15; int tone_level[3]; int mixer, envshape; int g, level; libspectrum_dword f; struct ay_change_tag *change_ptr = ay_change; int changes_left = ay_change_count; int reg, r; int chan1, chan2, chan3; int last_chan1 = 0, last_chan2 = 0, last_chan3 = 0; unsigned int tone_count, noise_count; /* If no AY chip, don't produce any AY sound (!) */ if( !( periph_is_active( PERIPH_TYPE_FULLER) || periph_is_active( PERIPH_TYPE_MELODIK ) || machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) ) return; for( f = 0; f < machine_current->timings.tstates_per_frame; f+= AY_CLOCK_DIVISOR * AY_CLOCK_RATIO ) { /* update ay registers. */ while( changes_left && f >= change_ptr->tstates ) { sound_ay_registers[ reg = change_ptr->reg ] = change_ptr->val; change_ptr++; changes_left--; /* fix things as needed for some register changes */ switch ( reg ) { case 0: case 1: case 2: case 3: case 4: case 5: r = reg >> 1; /* a zero-len period is the same as 1 */ ay_tone_period[r] = ( sound_ay_registers[ reg & ~1 ] | ( sound_ay_registers[ reg | 1 ] & 15 ) << 8 ); if( !ay_tone_period[r] ) ay_tone_period[r]++; /* important to get this right, otherwise e.g. Ghouls 'n' Ghosts * has really scratchy, horrible-sounding vibrato. */ if( ay_tone_tick[r] >= ay_tone_period[r] * 2 ) ay_tone_tick[r] %= ay_tone_period[r] * 2; break; case 6: ay_noise_tick = 0; ay_noise_period = ( sound_ay_registers[ reg ] & 31 ); break; case 11: case 12: ay_env_period = sound_ay_registers[11] | ( sound_ay_registers[12] << 8 ); break; case 13: ay_env_internal_tick = ay_env_tick = ay_env_cycles = 0; env_first = 1; env_rev = 0; env_counter = ( sound_ay_registers[13] & AY_ENV_ATTACK ) ? 0 : 15; break; } } /* the tone level if no enveloping is being used */ for( g = 0; g < 3; g++ ) tone_level[g] = ay_tone_levels[ sound_ay_registers[ 8 + g ] & 15 ]; /* envelope */ envshape = sound_ay_registers[13]; level = ay_tone_levels[ env_counter ]; for( g = 0; g < 3; g++ ) if( sound_ay_registers[ 8 + g ] & 16 ) tone_level[g] = level; /* envelope output counter gets incr'd every 16 AY cycles. */ ay_env_cycles += AY_CLOCK_DIVISOR; noise_count = 0; while( ay_env_cycles >= 16 ) { ay_env_cycles -= 16; noise_count++; ay_env_tick++; while( ay_env_tick >= ay_env_period ) { ay_env_tick -= ay_env_period; /* do a 1/16th-of-period incr/decr if needed */ if( env_first || ( ( envshape & AY_ENV_CONT ) && !( envshape & AY_ENV_HOLD ) ) ) { if( env_rev ) env_counter -= ( envshape & AY_ENV_ATTACK ) ? 1 : -1; else env_counter += ( envshape & AY_ENV_ATTACK ) ? 1 : -1; if( env_counter < 0 ) env_counter = 0; if( env_counter > 15 ) env_counter = 15; } ay_env_internal_tick++; while( ay_env_internal_tick >= 16 ) { ay_env_internal_tick -= 16; /* end of cycle */ if( !( envshape & AY_ENV_CONT ) ) env_counter = 0; else { if( envshape & AY_ENV_HOLD ) { if( env_first && ( envshape & AY_ENV_ALT ) ) env_counter = ( env_counter ? 0 : 15 ); } else { /* non-hold */ if( envshape & AY_ENV_ALT ) env_rev = !env_rev; else env_counter = ( envshape & AY_ENV_ATTACK ) ? 0 : 15; } } env_first = 0; } /* don't keep trying if period is zero */ if( !ay_env_period ) break; } } /* generate tone+noise... or neither. * (if no tone/noise is selected, the chip just shoves the * level out unmodified. This is used by some sample-playing * stuff.) */ chan1 = tone_level[0]; chan2 = tone_level[1]; chan3 = tone_level[2]; mixer = sound_ay_registers[7]; ay_tone_cycles += AY_CLOCK_DIVISOR; tone_count = ay_tone_cycles >> 3; ay_tone_cycles &= 7; if( ( mixer & 1 ) == 0 ) { level = chan1; ay_do_tone( level, tone_count, &chan1, 0 ); } if( ( mixer & 0x08 ) == 0 && noise_toggle ) chan1 = 0; if( ( mixer & 2 ) == 0 ) { level = chan2; ay_do_tone( level, tone_count, &chan2, 1 ); } if( ( mixer & 0x10 ) == 0 && noise_toggle ) chan2 = 0; if( ( mixer & 4 ) == 0 ) { level = chan3; ay_do_tone( level, tone_count, &chan3, 2 ); } if( ( mixer & 0x20 ) == 0 && noise_toggle ) chan3 = 0; if( last_chan1 != chan1 ) { blip_synth_update( ay_a_synth, f, chan1 ); if( ay_a_synth_r ) blip_synth_update( ay_a_synth_r, f, chan1 ); last_chan1 = chan1; } if( last_chan2 != chan2 ) { blip_synth_update( ay_b_synth, f, chan2 ); if( ay_b_synth_r ) blip_synth_update( ay_b_synth_r, f, chan2 ); last_chan2 = chan2; } if( last_chan3 != chan3 ) { blip_synth_update( ay_c_synth, f, chan3 ); if( ay_c_synth_r ) blip_synth_update( ay_c_synth_r, f, chan3 ); last_chan3 = chan3; } /* update noise RNG/filter */ ay_noise_tick += noise_count; while( ay_noise_tick >= ay_noise_period ) { ay_noise_tick -= ay_noise_period; if( ( rng & 1 ) ^ ( ( rng & 2 ) ? 1 : 0 ) ) noise_toggle = !noise_toggle; /* rng is 17-bit shift reg, bit 0 is output. * input is bit 0 xor bit 3. */ if( rng & 1 ) { rng ^= 0x24000; } rng >>= 1; /* don't keep trying if period is zero */ if( !ay_noise_period ) break; } } }