// license:GPL-2.0+ // copyright-holders:Juergen Buchmueller, Frank Palazzolo, Sean Riddle #include "emu.h" #include "audio/channelf.h" #define MAX_AMPLITUDE 0x7fff DEFINE_DEVICE_TYPE(CHANNELF_SOUND, channelf_sound_device, "channelf_sound", "Channel F Sound") channelf_sound_device::channelf_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, CHANNELF_SOUND, tag, owner, clock), device_sound_interface(mconfig, *this), m_channel(nullptr), m_sound_mode(0), m_incr(0), m_decay_mult(0), m_envelope(0), m_sample_counter(0), m_forced_ontime(0), m_min_ontime(0) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void channelf_sound_device::device_start() { int rate; m_channel = stream_alloc(0, 1, machine().sample_rate()); rate = machine().sample_rate(); /* * 2V = 1000Hz ~= 3579535/224/16 * Note 2V on the schematic is not the 2V scanline counter - * it is the 2V vertical pixel counter * 1 pixel = 4 scanlines high * * * This is a convenient way to generate the relevant frequencies, * using a DDS (Direct Digital Synthesizer) * * Essentially, you want a counter to overflow some bit position * at a fixed rate. So, you figure out a number which you can add * to the counter at every sample, so that you will achieve this * * In this case, we want to overflow bit 16 and the 2V rate, 1000Hz. * This means we also get bit 17 = 4V, bit 18 = 8V, etc. */ /* This is the proper value to add per sample */ m_incr = 65536.0/(rate/1000.0/2.0); // added for improved sound /* This is the minimum forced ontime, in samples */ m_min_ontime = rate/1000*2; /* approx 2ms - estimated, not verified on HW */ /* This was measured, decay envelope with half life of ~9ms */ /* (this is decay multiplier per sample) */ m_decay_mult = exp((-0.693/9e-3)/rate); /* initial conditions */ m_envelope = 0; } //------------------------------------------------- // sound_stream_update - handle a stream update //------------------------------------------------- void channelf_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { uint32_t mask = 0, target = 0; stream_sample_t *buffer = outputs[0]; stream_sample_t *sample = buffer; switch( m_sound_mode ) { case 0: /* sound off */ memset(buffer,0,sizeof(*buffer)*samples); return; case 1: /* high tone (2V) - 1000Hz */ mask = 0x00010000; target = 0x00010000; break; case 2: /* medium tone (4V) - 500Hz */ mask = 0x00020000; target = 0x00020000; break; case 3: /* low (weird) tone (32V & 8V) */ mask = 0x00140000; target = 0x00140000; break; } while (samples-- > 0) { if ((m_forced_ontime > 0) || ((m_sample_counter & mask) == target)) // change made for improved sound *sample++ = m_envelope; else *sample++ = 0; m_sample_counter += m_incr; m_envelope *= m_decay_mult; if (m_forced_ontime > 0) // added for improved sound m_forced_ontime -= 1; // added for improved sound } } void channelf_sound_device::sound_w(int mode) { if (mode == m_sound_mode) return; m_channel->update(); m_sound_mode = mode; switch(mode) { case 0: m_envelope = 0; m_forced_ontime = 0; // added for improved sound break; case 1: case 2: case 3: m_envelope = MAX_AMPLITUDE; m_forced_ontime = m_min_ontime; // added for improved sound break; } }