138 static constexpr
word energytable[0x20] =
140 0, 2, 4, 6, 10, 12, 14, 18,
141 22, 26, 30, 34, 38, 44, 48, 54,
142 62, 68, 76, 84, 94,102,114,124,
143 136,150,164,178,196,214,232,254
151 23, 24, 25, 26, 27, 28, 29, 30,
152 32, 34, 36, 38, 40, 42, 44, 46,
153 50, 54, 58, 62, 66, 70, 74, 78,
154 86, 94, 102,110,118,126
158 -24898, -25672, -26446, -27091, -27736, -28252, -28768, -29155,
159 -29542, -29929, -30316, -30574, -30832, -30961, -31219, -31348,
160 -31606, -31735, -31864, -31864, -31993, -32122, -32122, -32251,
161 -32251, -32380, -32380, -32380, -32509, -32509, -32509, -32509,
162 24898, 23995, 22963, 21931, 20770, 19480, 18061, 16642,
163 15093, 13416, 11610, 9804, 7998, 6063, 3999, 1935,
164 0, -1935, -3999, -6063, -7998, -9804, -11610, -13416,
165 -15093, -16642, -18061, -19480, -20770, -21931, -22963, -23995
168 0, -3096, -6321, -9417, -12513, -15351, -18061, -20770,
169 -23092, -25285, -27220, -28897, -30187, -31348, -32122, -32638,
170 0, 32638, 32122, 31348, 30187, 28897, 27220, 25285,
171 23092, 20770, 18061, 15351, 12513, 9417, 6321, 3096
174 0, -3999, -8127, -12255, -16384, -20383, -24511, -28639,
175 32638, 28639, 24511, 20383, 16254, 12255, 8127, 3999
178 0, -8127, -16384, -24511, 32638, 24511, 16254, 8127
181 int VLM5030::getBits(
unsigned sBit,
unsigned bits)
183 unsigned offset = address + (sBit / 8);
184 unsigned data = rom[(offset + 0) & address_mask] +
185 rom[(offset + 1) & address_mask] * 256;
187 data &= (0xFF >> (8 - bits));
192 int VLM5030::parseFrame()
195 old_energy = new_energy;
196 old_pitch = new_pitch;
199 byte cmd = rom[address & address_mask];
202 new_energy = new_pitch = 0;
210 int nums = ((cmd >> 2) + 1) * 2;
215 new_pitch = (
pitchtable[getBits(1, 5)] + pitch_offset) & 0xff;
217 new_energy = energytable[getBits(6, 5)];
220 new_k[9] =
K5_table[getBits(11, 3)];
221 new_k[8] =
K5_table[getBits(14, 3)];
222 new_k[7] =
K5_table[getBits(17, 3)];
223 new_k[6] =
K5_table[getBits(20, 3)];
224 new_k[5] =
K5_table[getBits(23, 3)];
225 new_k[4] =
K5_table[getBits(26, 3)];
226 new_k[3] =
K3_table[getBits(29, 4)];
227 new_k[2] =
K3_table[getBits(33, 4)];
228 new_k[1] =
K2_table[getBits(37, 5)];
229 new_k[0] =
K1_table[getBits(42, 6)];
236 void VLM5030::generateChannels(
float** bufs,
unsigned num)
252 if (sample_count == 0) {
258 sample_count = frame_size;
260 if (interp_count == 0) {
262 interp_count = parseFrame();
263 if (interp_count == 0) {
266 sample_count = frame_size;
270 current_energy = old_energy;
271 current_pitch = old_pitch;
274 if (current_energy == 0) {
276 target_pitch = current_pitch;
280 target_energy = new_energy;
281 target_pitch = new_pitch;
287 interp_count -= interp_step;
290 current_energy = old_energy + (target_energy - old_energy) * interp_effect /
FR_SIZE;
292 current_pitch = old_pitch + (target_pitch - old_pitch) * interp_effect /
FR_SIZE;
295 current_k[i] = old_k[i] + (target_k[i] - old_k[i]) * interp_effect /
FR_SIZE;
298 if (old_energy == 0) {
301 }
else if (old_pitch <= 1) {
304 : -int(current_energy);
307 current_val = (pitch_count == 0) ? current_energy : 0;
313 for (
int i = 9; i >= 0; --i) {
314 u[i] = u[i + 1] - ((current_k[i] * x[i]) / 32768);
316 for (
int i = 9; i >= 1; --i) {
317 x[i] = x[i - 1] + ((current_k[i - 1] * u[i - 1]) / 32768);
322 bufs[0][buf_count] =
std::clamp(u[0], -511, 511);
326 if (pitch_count >= current_pitch) {
336 if (sample_count <= num) {
345 if (sample_count <= num) {
355 bufs[0][buf_count++] = 0;
360 float VLM5030::getAmplificationFactorImpl()
const
362 return 1.0f / (1 << 9);
366 void VLM5030::setupParameter(
byte param)
374 }
else if (param & 1) {
386 }
else if (param & 0x40) {
400 old_energy = old_pitch = 0;
401 new_energy = new_pitch = 0;
402 current_energy = current_pitch = 0;
403 target_energy = target_pitch = 0;
404 memset(old_k, 0,
sizeof(old_k));
405 memset(new_k, 0,
sizeof(new_k));
406 memset(current_k, 0,
sizeof(current_k));
407 memset(target_k, 0,
sizeof(target_k));
408 interp_count = sample_count = pitch_count = 0;
409 memset(x, 0,
sizeof(x));
411 setupParameter(0x00);
430 setRST((data & 0x01) != 0);
431 setVCU((data & 0x04) != 0);
432 setST ((data & 0x02) != 0);
436 void VLM5030::setRST(
bool pin)
441 setupParameter(latch_data);
454 void VLM5030::setVCU(
bool pin)
461 void VLM5030::setST(
bool pin)
472 vcu_addr_h = (int(latch_data) << 8) + 0x01;
477 address = (vcu_addr_h & 0xff00) + latch_data;
481 int table = (latch_data & 0xfe) + ((
int(latch_data) & 1) << 8);
482 address = ((rom[(
table + 0) & address_mask]) << 8) |
483 rom[(
table + 1) & address_mask];
486 sample_count = frame_size;
503 static XMLElement getRomConfig(
const std::string& name, std::string_view romFilename)
506 voiceROMconfig.addAttribute(
"id",
"name");
507 auto& romElement = voiceROMconfig.addChild(
"rom");
509 "sha1",
"4f36d139ee4baa7d5980f765de9895570ee05f40");
513 "filename",
"keyboardmaster/voice.rom");
514 return voiceROMconfig;
517 constexpr
auto INPUT_RATE = unsigned(
cstd::round(3579545 / 440.0));
520 std::string_view romFilename,
const DeviceConfig& config)
522 , rom(name_ +
" ROM",
"rom",
DeviceConfig(config, getRomConfig(name_, romFilename)))
525 pin_RST = pin_ST = pin_VCU =
false;
531 address_mask = rom.
getSize() - 1;
541 template<
typename Archive>
544 ar.serialize(
"address_mask", address_mask,
545 "frame_size", frame_size,
546 "pitch_offset", pitch_offset,
547 "current_energy", current_energy,
548 "current_pitch", current_pitch,
549 "current_k", current_k,
552 "vcu_addr_h", vcu_addr_h,
555 "target_k", target_k,
556 "old_energy", old_energy,
557 "new_energy", new_energy,
558 "target_energy", target_energy,
559 "old_pitch", old_pitch,
560 "new_pitch", new_pitch,
561 "target_pitch", target_pitch,
562 "interp_step", interp_step,
563 "interp_count", interp_count,
564 "sample_count", sample_count,
565 "pitch_count", pitch_count,
566 "latch_data", latch_data,
567 "parameter", parameter,
void updateStream(EmuTime::param time)
void unregisterSound()
Unregisters this sound device with the Mixer.
void registerSound(const DeviceConfig &config)
Registers this sound device with the Mixer.
void writeControl(byte data, EmuTime::param time)
set RST / VCU / ST pins
void writeData(byte data)
latch control data
bool getBSY(EmuTime::param time) const
get BSY pin level
VLM5030(const std::string &name, static_string_view desc, std::string_view romFilename, const DeviceConfig &config)
void serialize(Archive &ar, unsigned version)
constexpr double round(double x)
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
string_view stripExtension(string_view path)
Returns the path without extension.
This file implemented 3 utility functions:
constexpr int IP_SIZE_NORMAL
constexpr int16_t K3_table[]
constexpr int16_t K2_table[]
constexpr int IP_SIZE_FAST
constexpr int VLM5030_speed_table[8]
constexpr int IP_SIZE_SLOW
constexpr byte pitchtable[0x20]
uint16_t word
16 bit unsigned integer
constexpr int IP_SIZE_SLOWER
constexpr int16_t K5_table[]
constexpr int IP_SIZE_FASTER
constexpr int16_t K1_table[]
void fill(ForwardRange &&range, const T &value)
auto copy(InputRange &&range, OutputIter out)
bool random_bool()
Return a random boolean value.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
std::string strCat(Ts &&...ts)
constexpr auto xrange(T e)