#include "midiplayer.h" #include "tone.h" #include "audio.h" #include "pcmdma.h" #include "pwmconfig.h" /** * @file * @brief Jednoduchý přehrávač midi souborů. * * Kompletní midi obsahuje zvukové fonty, které jsou obrovské. Tohle je velice zjednodušené, * takže docela dobře přehrává skladby typu ragtime, orchestrální midi jsou skoro nepoužitelné. * Přesto se to pro jednoduché zvuky může hodit, protože je to poměrně nenáročné na systémové * prostředky. Může to fungovat dokonce i na 8-bitovém uP. * */ // static Filtr iir; /// Generátory tónů static Tone gens[maxGens]; /// Generuj vzorek pro všechny tóny @return Vzorek static inline short genSample (void) { int res = 0; for (unsigned int i=0; i maxValue) res = maxValue; if (res < minValue) res = minValue; return (res); } /// Počítá další vzorek short MidiPlayer::nextSample (void) { if (pause) pause -= 1; // Časování tónu else ToneChange(); // Nový tón - MidiPlayer::ToneChange return genSample (); } static constexpr unsigned AudioMidiDelay = 24; static constexpr int INPUT_BIT_RANGE = 16; static constexpr unsigned SIGMA_MASK = (1u << (INPUT_BIT_RANGE + 0)) - 1u; static constexpr unsigned SIGNED_OFFEST = (1u << (INPUT_BIT_RANGE - 1)); // Předpokládá se na vstupu signed int o šířce INPUT_BIT_RANGE // přičemž 0 na vstupu odpovídá MAXPWM / 2 na výstupu. Vypadá to divně, ale funguje. static unsigned pwm_sd (const int input) { static unsigned sigma = 0; // podstatné je, že proměnná je statická const unsigned sample = (input + SIGNED_OFFEST) * MAXPWM; sigma &= SIGMA_MASK; // v podstatě se odečte hodnota PWM sigma += sample; // integrace prostým součtem return sigma >> INPUT_BIT_RANGE; } /******************************************************************/ /// Konstruktor MidiPlayer::MidiPlayer() noexcept : OneWay() { index = 0; pause = 0; melody = scores[index++]; running = true; } unsigned MidiPlayer::Send (uint16_t * const ptr, const unsigned len) { //if (!but.get()) running = true; // případně spouštět tlačítkem, není implementováno if (!running) { for (unsigned n=0; n> 1; return len; } for (unsigned n=0; n>= 4; switch (cmd) { case 0x8: // off gens[geno].setMidiOff(); break; case 0x9: // on midt = * melody++; gens[geno].setMidiOn (midt); break; default: stop(); return; // melodie končí eventem 0xf0 } } else { // pause midt = * melody++; // Když to trochu uteče, zase se z toho nestřílí, tak to nechme být. pause = ((unsigned int) cmd << 8) + midt; // v ms pause *= AudioMidiDelay; // ale máme vzorkování cca 24 kHz return; } } }