|
Tabula Sonora 0.1.0
A native C++20 implementation of the Roland Sound Canvas VA synth voice
|
A dependency-free Standard MIDI File reader. More...
Classes | |
| struct | SongLoop |
| Loop points a file declared, in samples on the render-block grid. More... | |
| struct | Song |
| A parsed file: the event list plus what the container knew beyond the events. More... | |
Functions | |
| Song | load (const std::filesystem::path &path, int sample_rate=32000) |
| Reads a music file, with its loop points. | |
| Song | load (std::span< const std::uint8_t > data, int sample_rate=32000, std::string_view name={}) |
| Parses a music file held in memory, with its loop points. | |
| std::vector< MidiEvent > | read (const std::filesystem::path &path, int sample_rate=32000) |
| Reads a music file, ordered by position — load without the loop points. | |
| std::vector< MidiEvent > | parse (std::span< const std::uint8_t > data, int sample_rate=32000) |
| Parses a music file held in memory, ordered by position — load without the loop points. | |
| std::int64_t | quantise (double samples) noexcept |
| Rounds a sample position onto the render-block grid. | |
Variables | |
| constexpr int | block_grid = 32 |
| Samples per render block — the grid events are applied on. | |
| constexpr int | default_tempo = 500'000 |
| Default tempo when a file sets none: 120 bpm, in microseconds per quarter note. | |
A dependency-free Standard MIDI File reader.
Handles formats 0, 1 and 2, running status, system-exclusive messages, and the tempo map. Track ticks are converted to seconds through that map and then to samples, and finally quantised to the render-block grid — the granularity at which the engine actually applies events. Quantising here is what lets an offline render line up sample-for-sample with the real engine's own output.
Meta events other than tempo are consumed here or dropped: port tags pick the port scheme, markers feed the loop scanners, and none of them reach the event list.
|
nodiscard |
Reads a music file, with its loop points.
Not only Standard MIDI Files: the formats formats::to_smf recognises — RMID, MIDS, MUS, XMI, GMF, HMP, HMI, XMF, and (by file name) LDS — are converted first, so every caller understands them. Files carrying EMIDI track designations (CC 110) are filtered for a General MIDI receiver: tracks authored exclusively for some other synthesizer are dropped, as playing them doubles every voice.
|
nodiscard |
Parses a music file held in memory, with its loop points.
name is the file name the data came from, when the caller knows it; only LDS detection uses it. Throws std::runtime_error if the file is malformed or uses SMPTE timing.
|
nodiscard |
Reads a music file, ordered by position — load without the loop points.
|
nodiscard |
Parses a music file held in memory, ordered by position — load without the loop points.
Throws std::runtime_error if the file is malformed or uses SMPTE timing.
|
nodiscardnoexcept |
Rounds a sample position onto the render-block grid.
The rounding is to nearest with ties to even, matching .NET's Math.Round, because that is what the reference build uses. C's round and llround go half-away-from-zero instead.
Measured: for this expression the choice does not matter. Over 400,000 half-sample positions the two modes disagree at every one of the 100,000 ties and the resulting block is the same every time — the two candidates differ by one, and the floor onto a 32-sample grid absorbs that unless they straddle a multiple of 32, which a tie can never do. nearbyint is kept anyway so the expression matches the original exactly rather than by an argument that could stop holding.
The same is not true of Math.Round where no grid follows it — the delay's tap lengths are the case to watch.
|
inlineconstexpr |
Samples per render block — the grid events are applied on.
|
inlineconstexpr |
Default tempo when a file sets none: 120 bpm, in microseconds per quarter note.