use crate::config::Config;
use crate::{strict, verbose};
use crate::vgm2mid::CHN_DAC;
use crate::vgm2mid::PITCHWHEEL_SENSITIVITY_DEFAULT;
use anyhow::{anyhow, Result};
use midly::num::{u14, u4, u7};
use midly::MetaMessage::Tempo;
use midly::MidiMessage::{Controller, NoteOff, NoteOn, PitchBend, ProgramChange};
use midly::TrackEventKind::{Meta, Midi};
use midly::{Smf, TrackEvent, TrackEventKind};
use std::path::Path;
#[allow(dead_code)]
pub(crate) const MIDI_BANK_SELECT: u7 = u7::new(0x00);
pub(crate) const MIDI_MODULATOR_WHEEL: u7 = u7::new(0x01);
pub(crate) const MIDI_DATA_ENTRY_MSB: u7 = u7::new(0x06);
pub(crate) const MIDI_VOLUME: u7 = u7::new(0x07);
pub(crate) const MIDI_PAN: u7 = u7::new(0x0A);
#[allow(dead_code)]
pub(crate) const MIDI_SUSTAIN: u7 = u7::new(0x40);
#[allow(dead_code)]
pub(crate) const MIDI_SOFT: u7 = u7::new(0x43);
#[allow(dead_code)]
pub(crate) const MIDI_LEGATO_PEDAL: u7 = u7::new(0x44);
#[allow(dead_code)]
pub(crate) const MIDI_HOLD2_PEDAL: u7 = u7::new(0x45);
#[allow(dead_code)]
pub(crate) const MIDI_SOUND_TIMBRE: u7 = u7::new(0x47);
#[allow(dead_code)]
pub(crate) const MIDI_SOUND_RELEASE_TIME: u7 = u7::new(0x48);
#[allow(dead_code)]
pub(crate) const MIDI_SOUND_ATTACK_TIME: u7 = u7::new(0x49);
#[allow(dead_code)]
pub(crate) const MIDI_SOUND_BRIGHTNESS: u7 = u7::new(0x4A);
pub(crate) const MIDI_NRPN_LSB: u7 = u7::new(0x62);
pub(crate) const MIDI_NRPN_MSB: u7 = u7::new(0x63);
pub(crate) const MIDI_RPN_LSB: u7 = u7::new(0x64);
pub(crate) const MIDI_RPN_MSB: u7 = u7::new(0x65);
#[allow(dead_code)]
pub(crate) const MIDI_ALL_SOUNDS_OFF: u7 = u7::new(0x78);
#[allow(dead_code)]
pub(crate) const MIDI_RESET_ALL_CONTROLLERS: u7 = u7::new(0x79);
#[allow(dead_code)]
pub(crate) const MIDI_ALL_NOTES_OFF: u7 = u7::new(0x7B);
pub(crate) const TEXT_LOOP_START: &[u8] = "loopStart".as_bytes();
pub(crate) const TEXT_LOOP_END: &[u8] = "loopEnd".as_bytes();
pub(crate) const RPN_PITCH_BEND_RANGE_M: u7 = u7::new(0x0);
pub(crate) const RPN_PITCH_BEND_RANGE_L: u7 = u7::new(0x0);
pub(crate) const NRPN_DRUM_PITCH_COARSE: u7 = u7::new(0x18);
#[allow(dead_code)]
pub(crate) const NRPN_DRUM_PITCH_FINE: u7 = u7::new(0x19);
#[allow(dead_code)]
pub(crate) const NRPN_DRUM_VOLUME: u7 = u7::new(0x1A);
pub(crate) const NRPN_DRUM_PAN: u7 = u7::new(0x1C);
#[allow(dead_code)]
pub(crate) const MIDI_VOLUME_MIN: u7 = u7::new(0x00);
pub(crate) const MIDI_VOLUME_MAX: u7 = u7::new(0x7F);
#[allow(dead_code)]
pub(crate) const MIDI_VELOCITY_MIN: u7 = u7::new(0x00);
#[allow(dead_code)]
pub(crate) const MIDI_VELOCITY_MAX: u7 = u7::new(0x7F);
pub(crate) const MIDI_PAN_LEFT: u7 = u7::new(0x00);
pub(crate) const MIDI_PAN_RIGHT: u7 = u7::new(0x7F);
pub(crate) const MIDI_PAN_CENTER: u7 = u7::new(0x40);
#[allow(dead_code)]
pub(crate) const MIDI_PITCHWHEEL_DOWN_ONE_SEMITONE: u14 = u14::new(0x0);
#[allow(dead_code)]
pub(crate) const MIDI_PITCHWHEEL_DOWN_TWO_SEMITONES: u14 = u14::new(0x1000);
#[allow(dead_code)]
pub(crate) const MIDI_PITCHWHEEL_DOWN_HALF_SEMITIONE: u14 = u14::new(0x1800);
#[allow(dead_code)]
pub(crate) const MIDI_PITCHWHEEL_MIN: u14 = u14::new(0x0);
pub(crate) const MIDI_PITCHWHEEL_CENTER: u14 = u14::new(0x2000);
pub(crate) const MIDI_PITCHWHEEL_MAX: u14 = u14::new(0x3FFF);
#[allow(dead_code)]
pub(crate) const MIDI_PITCHWHEEL_UP_HALF_SEMITIONE: u14 = u14::new(0x2800);
#[allow(dead_code)]
pub(crate) const MIDI_PITCHWHEEL_UP_ONE_SEMITONE: u14 = u14::new(0x3000);
#[allow(dead_code)]
pub(crate) const MIDI_PITCHWHEEL_UP_TWO_SEMITONES: u14 = u14::new(0x3FFF);
pub(crate) const MIDI_PATCH_ACOUSTIC_GRAND_PIANO: u7 = u7::new(0);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BRIGHT_ACOUSTIC_PIANO: u7 = u7::new(1);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ELECTRIC_GRAND_PIANO: u7 = u7::new(2);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_HONKY_TONK_PIANO: u7 = u7::new(3);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_RHODES_PIANO: u7 = u7::new(4);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_CHORUSED_PIANO: u7 = u7::new(5);
pub(crate) const MIDI_PATCH_HARPSICHORD: u7 = u7::new(6);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_CLAVINET: u7 = u7::new(7);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_CELESTA: u7 = u7::new(8);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_GLOCKENSPIEL: u7 = u7::new(9);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_MUSIC_BOX: u7 = u7::new(10);
pub(crate) const MIDI_PATCH_VIBRAPHONE: u7 = u7::new(11);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_MARIMBA: u7 = u7::new(12);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_XYLOPHONE: u7 = u7::new(13);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TUBULAR_BELLS: u7 = u7::new(14);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_DULCIMER: u7 = u7::new(15);
pub(crate) const MIDI_PATCH_HAMMOND_ORGAN: u7 = u7::new(16);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PERCUSSIVE_ORGAN: u7 = u7::new(17);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ROCK_ORGAN: u7 = u7::new(18);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_CHURCH_ORGAN: u7 = u7::new(19);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_REED_ORGAN: u7 = u7::new(20);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ACCORDION: u7 = u7::new(21);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_HARMONICA: u7 = u7::new(22);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TANGO_ACCORDION: u7 = u7::new(23);
pub(crate) const MIDI_PATCH_ACOUSTIC_GUITAR_NYLON: u7 = u7::new(24);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ACOUSTIC_GUITAR_STEEL: u7 = u7::new(25);
pub(crate) const MIDI_PATCH_ELECTRIC_GUITAR_JAZZ: u7 = u7::new(26);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ELECTRIC_GUITAR_CLEAN: u7 = u7::new(27);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ELECTRIC_GUITAR_MUTED: u7 = u7::new(28);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_OVERDRIVEN_GUITAR: u7 = u7::new(29);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_DISTORTION_GUITAR: u7 = u7::new(30);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_GUITAR_HARMONICS: u7 = u7::new(31);
pub(crate) const MIDI_PATCH_ACOUSTIC_BASS: u7 = u7::new(32);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ELECTRIC_BASS_FINGER: u7 = u7::new(33);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ELECTRIC_BASS_PICK: u7 = u7::new(34);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FRETLESS_BASS: u7 = u7::new(35);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SLAP_BASS_1: u7 = u7::new(36);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SLAP_BASS_2: u7 = u7::new(37);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SYNTH_BASS_1: u7 = u7::new(38);
pub(crate) const MIDI_PATCH_SYNTH_BASS_2: u7 = u7::new(39);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_VIOLIN: u7 = u7::new(40);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_VIOLA: u7 = u7::new(41);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_CELLO: u7 = u7::new(42);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_CONTRABASS: u7 = u7::new(43);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TREMOLO_STRINGS: u7 = u7::new(44);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PIZZICATO_STRINGS: u7 = u7::new(45);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ORCHESTRAL_HARP: u7 = u7::new(46);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TIMPANI: u7 = u7::new(47);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_STRING_ENSEMBLE_1: u7 = u7::new(48);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_STRING_ENSEMBLE_2: u7 = u7::new(49);
pub(crate) const MIDI_PATCH_SYNTH_STRINGS_1: u7 = u7::new(50);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SYNTH_STRINGS_2: u7 = u7::new(51);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_CHOIR_AHHS: u7 = u7::new(52);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_VOICE_OOHS: u7 = u7::new(53);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SYNTH_VOICE: u7 = u7::new(54);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ORCHESTRA_HIT: u7 = u7::new(55);
pub(crate) const MIDI_PATCH_TRUMPET: u7 = u7::new(56);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TROMBONE: u7 = u7::new(57);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TUBA: u7 = u7::new(58);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_MUTED_TRUMPET: u7 = u7::new(59);
pub(crate) const MIDI_PATCH_FRENCH_HORN: u7 = u7::new(60);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BRASS_SECTION: u7 = u7::new(61);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SYNTH_BRASS_1: u7 = u7::new(62);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SYNTH_BRASS_2: u7 = u7::new(63);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SOPRANO_SAX: u7 = u7::new(64);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ALTO_SAX: u7 = u7::new(65);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TENOR_SAX: u7 = u7::new(66);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BARITONE_SAX: u7 = u7::new(67);
pub(crate) const MIDI_PATCH_OBOE: u7 = u7::new(68);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_ENGLISH_HORN: u7 = u7::new(69);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BASSOON: u7 = u7::new(70);
pub(crate) const MIDI_PATCH_CLARINET: u7 = u7::new(71);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PICCOLO: u7 = u7::new(72);
pub(crate) const MIDI_PATCH_FLUTE: u7 = u7::new(73);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_RECORDER: u7 = u7::new(74);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAN_FLUTE: u7 = u7::new(75);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BOTTLE_BLOW: u7 = u7::new(76);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SHAKUHACHI: u7 = u7::new(77);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_WHISTLE: u7 = u7::new(78);
pub(crate) const MIDI_PATCH_OCARINA: u7 = u7::new(79);
pub(crate) const MIDI_PATCH_LEAD_1_SQUARE: u7 = u7::new(80);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_LEAD_2_SAWTOOTH: u7 = u7::new(81);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_LEAD_3_CALLIOPE: u7 = u7::new(82);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_LEAD_4_CHIFF: u7 = u7::new(83);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_LEAD_5_CHANGARANG: u7 = u7::new(84);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_LEAD_6_VOICE: u7 = u7::new(85);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_LEAD_7_FIFTHS: u7 = u7::new(86);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_LEAD_8_BASS_LEAD: u7 = u7::new(87);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAD_1_NEW_AGE: u7 = u7::new(88);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAD_2_WARM: u7 = u7::new(89);
pub(crate) const MIDI_PATCH_PAD_3_POLYSYNTH: u7 = u7::new(90);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAD_4_CHOIR: u7 = u7::new(91);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAD_5_BOWED: u7 = u7::new(92);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAD_6_METALLIC: u7 = u7::new(93);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAD_7_HALO: u7 = u7::new(94);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_PAD_8_SWEEP: u7 = u7::new(95);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_1_RAIN: u7 = u7::new(96);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_2_SOUNDTRACK: u7 = u7::new(97);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_3_CRYSTAL: u7 = u7::new(98);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_4_ATMOSPHERE: u7 = u7::new(99);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_5_BRIGHTNESS: u7 = u7::new(100);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_6_GOBLINS: u7 = u7::new(101);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_7_ECHOES: u7 = u7::new(102);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FX_8_SCI_FI: u7 = u7::new(103);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SITAR: u7 = u7::new(104);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BANJO: u7 = u7::new(105);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SHAMISEN: u7 = u7::new(106);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_KOTO: u7 = u7::new(107);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_KALIMBA: u7 = u7::new(108);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BAGPIPE: u7 = u7::new(109);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_FIDDLE: u7 = u7::new(110);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SHANAI: u7 = u7::new(111);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TINKLE_BELL: u7 = u7::new(112);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_AGOGO: u7 = u7::new(113);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_STEEL_DRUMS: u7 = u7::new(114);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_WOODBLOCK: u7 = u7::new(115);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TAIKO_DRUM: u7 = u7::new(116);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_MELODIC_TOM: u7 = u7::new(117);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SYNTH_DRUM: u7 = u7::new(118);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_REVERSE_CYMBAL: u7 = u7::new(119);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_GUITAR_FRET_NOISE: u7 = u7::new(120);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BREATH_NOISE: u7 = u7::new(121);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_SEASHORE: u7 = u7::new(122);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_BIRD_TWEET: u7 = u7::new(123);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_TELEPHONE_RING: u7 = u7::new(124);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_HELICOPTER: u7 = u7::new(125);
#[allow(dead_code)]
pub(crate) const MIDI_PATCH_APPLAUSE: u7 = u7::new(126);
pub(crate) const MIDI_PATCH_GUNSHOT: u7 = u7::new(127);
pub(crate) struct MIDIShim<'smf, 'config> {
delta_factor: f64,
pub delta_time: u32,
written_delay_position: u32, current_sample_position: u32,
midi_file: Smf<'smf>,
config: &'config Config,
}
impl<'smf, 'config> MIDIShim<'smf, 'config> {
pub(crate) fn new<'c: 'config>(config: &'c Config) -> Result<MIDIShim> {
let delta_fact =
22050.0 / f64::from(config.cnv_accuracy) * config.get_tempo_modifier();
let mut midi = Smf::new(midly::Header {
format: midly::Format::SingleTrack,
timing: midly::Timing::Metrical(config.cnv_accuracy.into()),
});
midi.tracks.push(Vec::new());
Ok(MIDIShim {
delta_factor: delta_fact,
delta_time: 0,
written_delay_position: 0,
current_sample_position: 0,
midi_file: midi,
config,
})
}
pub(crate) fn controller_write(&mut self, channel: u4, controller: u7, value: u7) {
self.event_write(Midi {
channel,
message: Controller { controller, value },
})
}
pub(crate) fn note_on_write(&mut self, channel: u4, note: u7, velocity: u7) {
self.event_write(Midi {
channel,
message: NoteOn {
key: note,
vel: velocity,
},
});
}
pub(crate) fn note_off_write(&mut self, channel: u4, note: u7, velocity: u7) {
self.event_write(Midi {
channel,
message: NoteOff {
key: note,
vel: velocity,
},
});
}
pub(crate) fn program_change_write(&mut self, channel: u4, program: u7) {
self.event_write(Midi {
channel,
message: ProgramChange { program },
});
}
pub(crate) fn pitch_bend_write(&mut self, channel: u4, pitchbend: u14) {
self.event_write(Midi {
channel,
message: PitchBend {
bend: midly::PitchBend(pitchbend),
},
});
}
pub(crate) fn event_write<'event: 'smf>(&mut self, event_kind: TrackEventKind<'event>) {
self.current_sample_position += self.delta_time;
self.delta_time = 0;
let temp_long = (self.current_sample_position as f64 / self.delta_factor + 0.5)
.round() as u32;
let delta_delay = temp_long - self.written_delay_position;
self.written_delay_position += delta_delay;
let event = TrackEvent {
delta: delta_delay.into(),
kind: event_kind,
};
self.midi_file.tracks[0].push(event);
}
pub(crate) fn write_smf(&mut self, out_path: &Path) -> Result<()> {
verbose!("Writing smf to {}", out_path.display());
self.event_write(midly::TrackEventKind::Meta(midly::MetaMessage::EndOfTrack));
self.midi_file.save(out_path).map_err(|err| anyhow!(err))
}
pub(crate) fn data_init(&mut self, psg_on: bool, t6w28_sn76489: bool) {
let tempo_val = 500000.0 * self.config.get_tempo_modifier();
self.event_write(Meta(Tempo((tempo_val.round() as u32).into())));
for channel in 0..=8 {
self.controller_write(channel.into(), MIDI_PAN, MIDI_PAN_CENTER);
}
if self.config.pitchwheel_sensitivity != PITCHWHEEL_SENSITIVITY_DEFAULT {
for channel in 0x0..=0xF {
if channel == 9 {
continue;
}
self.controller_write(
channel.into(),
MIDI_RPN_MSB,
RPN_PITCH_BEND_RANGE_M,
);
self.controller_write(
channel.into(),
MIDI_RPN_LSB,
RPN_PITCH_BEND_RANGE_L,
);
self.controller_write(
channel.into(),
MIDI_RPN_MSB,
self.config.pitchwheel_sensitivity.into(),
);
}
}
self.controller_write(CHN_DAC, MIDI_PAN, MIDI_PAN_CENTER);
self.program_change_write(CHN_DAC, 0x00.into());
self.controller_write(CHN_DAC, MIDI_VOLUME, MIDI_VOLUME_MAX);
if psg_on {
for channel in 10..=13 {
if !t6w28_sn76489 {
self.controller_write(
channel.into(),
MIDI_PAN,
MIDI_PAN_CENTER,
);
} else {
self.controller_write(
(channel - 10).into(),
MIDI_PAN,
MIDI_PAN_RIGHT,
);
self.controller_write(
channel.into(),
MIDI_PAN,
MIDI_PAN_LEFT,
);
}
}
for channel in 10..=12 {
if t6w28_sn76489 {
self.program_change_write(
(channel - 10).into(),
MIDI_PATCH_LEAD_1_SQUARE,
);
}
self.program_change_write(channel.into(), MIDI_PATCH_LEAD_1_SQUARE);
}
if t6w28_sn76489 {
self.program_change_write(0x03.into(), MIDI_PATCH_GUNSHOT);
}
self.program_change_write(0x0D.into(), MIDI_PATCH_GUNSHOT);
for channel in 10..=13 {
if t6w28_sn76489 {
self.controller_write(
channel.into(),
MIDI_VOLUME,
0x7F.into(),
);
}
self.controller_write(channel.into(), MIDI_VOLUME, 0x7F.into());
}
}
}
pub(crate) fn do_note_on(
&mut self,
note_1: f64,
note_2: f64,
midi_channel: u4,
midi_note: &mut u7,
midi_wheel: &mut u14,
opt_note_type: Option<u8>,
opt_note_velocity: Option<u7>,
) -> Result<bool> {
if note_1 < 0.0 || note_2 < 0.0 {
strict!("Notes below 0") }
let note_velocity = opt_note_velocity.unwrap_or(u7::new(0x7F));
let note_type = opt_note_type.unwrap_or(0);
if note_type == 0xFF || note_1 == 0xFF as f64 || note_2 == 0xFF as f64 {
return self.do_note_internal(
note_2,
midi_channel,
midi_note,
midi_wheel,
note_velocity,
);
}
let fuzzy_wheel = f64::from(midi_wheel.as_int())
+ ((note_2 - note_1) * self.config.pitchwheel_steps as f64);
if fuzzy_wheel >= MIDI_PITCHWHEEL_MIN.as_int() as f64
&& fuzzy_wheel <= (MIDI_PITCHWHEEL_MAX.as_int() + 1) as f64
{
*midi_wheel = (fuzzy_wheel.round() as u16)
.clamp(MIDI_PITCHWHEEL_MIN.as_int(), MIDI_PITCHWHEEL_MAX.as_int())
.into(); self.pitch_bend_write(midi_channel, *midi_wheel);
} else {
return self.do_note_internal(
note_2,
midi_channel,
midi_note,
midi_wheel,
note_velocity,
);
}
Ok(false) }
fn do_note_internal(
&mut self,
mut note_2: f64,
midi_channel: u4,
midi_note: &mut u7,
midi_wheel: &mut u14,
note_velocity: u7,
) -> Result<bool> {
if note_2 >= f64::from(0xFF) {
if *midi_note < 0xFF {
self.note_off_write(midi_channel, *midi_note, 0x00.into());
*midi_note = (note_2.clamp(0.0, 0xFF.into()).round() as u8).into();
}
return Ok(true);
}
let mut dbl_pitch_wheel: f64 = note_2 - note_2.trunc();
note_2 = note_2.trunc().abs();
if dbl_pitch_wheel >= 0.5 {
note_2 += 1.0;
dbl_pitch_wheel -= -1.0;
}
if *midi_note < 0xFF {
self.note_off_write(midi_channel, *midi_note, 0x00.into());
}
let new_wheel = (MIDI_PITCHWHEEL_CENTER.as_int() as f64
+ dbl_pitch_wheel * f64::from(self.config.pitchwheel_steps))
.round() as u16;
if new_wheel != *midi_wheel {
*midi_wheel = new_wheel.into();
if !(midi_channel == CHN_DAC && dbl_pitch_wheel.abs() < 0.1) {
self.pitch_bend_write(midi_channel, *midi_wheel);
}
}
*midi_note = (note_2.round() as u8).into();
self.note_on_write(midi_channel, *midi_note, note_velocity);
Ok(true) }
}
pub(crate) fn db_to_midi_vol(db: f64) -> u7 {
((f64::powf(10.0, db / 40.0) * (0x7F as f64)) as u8).into()
}
pub(crate) fn lin_to_db(linear_val: f64) -> f64 {
if linear_val > 0.0 {
f64::log2(linear_val) * 6.0
} else {
-400.0 }
}