The 24 MB wave ROM embedded in SCCore.dll — the literal Sound Canvas hardware mask ROM, two banks addressed in 1 MB regions.
More...
#include <tabulasonora/wave_rom.hpp>
|
| struct | SplitRegion |
| | Splits a descriptor's region byte into a bank and a bank-relative region index. More...
|
|
| | WaveRom (const RomImage &rom) |
| | Creates a wave-ROM view over an open image, which must outlive it.
|
| std::int64_t | bank_base (int bank) const noexcept |
| | File offset of the first byte of a bank.
|
| std::int64_t | region_base (int region) const noexcept |
| | File offset of the base of a region, from a descriptor's region byte.
|
| std::optional< WaveStreams > | read_streams (int region, int loop, int start) const |
| | Reads the delta and scale streams for one wave.
|
|
| static constexpr int | region_count (int bank) noexcept |
| | Number of regions of real ROM data in a bank: 0 for bank A, 1 for bank B.
|
| static constexpr SplitRegion | split_region (int region) noexcept |
|
| static constexpr std::int32_t | region_size = 0x100000 |
| | Size of one addressable ROM region, 1 MB.
|
| static constexpr std::int32_t | max_sample_count = 2'000'000 |
| | Largest wave this class will attempt to read, as a sanity bound.
|
| static constexpr int | bank_a_region_count = 16 |
| | Regions bank A spans: sixteen, the full width of the region nibble.
|
| static constexpr int | bank_b_region_count = 8 |
| | Regions of real ROM data in bank B — eight, not twelve.
|
The 24 MB wave ROM embedded in SCCore.dll — the literal Sound Canvas hardware mask ROM, two banks addressed in 1 MB regions.
Bank A is the stacked SC-88/SC-88Pro ROM, bank B the SC-8820 ROM. Within a region the shift exponents live at the bottom (one byte per 32 samples, so 32 KB covers the whole 1 MB) while the deltas are addressed directly by sample index.
◆ WaveRom()
| ts::WaveRom::WaveRom |
( |
const RomImage & | rom | ) |
|
|
explicit |
Creates a wave-ROM view over an open image, which must outlive it.
◆ region_count()
| constexpr int ts::WaveRom::region_count |
( |
int | bank | ) |
|
|
inlinestaticnodiscardconstexprnoexcept |
Number of regions of real ROM data in a bank: 0 for bank A, 1 for bank B.
◆ split_region()
| constexpr SplitRegion ts::WaveRom::split_region |
( |
int | region | ) |
|
|
inlinestaticnodiscardconstexprnoexcept |
◆ bank_base()
| std::int64_t ts::WaveRom::bank_base |
( |
int | bank | ) |
const |
|
inlinenodiscardnoexcept |
File offset of the first byte of a bank.
◆ region_base()
| std::int64_t ts::WaveRom::region_base |
( |
int | region | ) |
const |
|
nodiscardnoexcept |
File offset of the base of a region, from a descriptor's region byte.
◆ read_streams()
| std::optional< WaveStreams > ts::WaveRom::read_streams |
( |
int | region, |
|
|
int | loop, |
|
|
int | start ) const |
|
nodiscard |
Reads the delta and scale streams for one wave.
Returns nothing when the descriptor describes no usable data — a non-positive or implausibly large length.
The descriptor's field names are as recovered, and they are confusing: loop is the data start, end is the loop point, and start is the physical end.
Decoding starts at loop exactly. An unaligned loop is not a malformed descriptor: the codec stores no absolute value per block, only differences, so a wave can begin partway into an exponent block and end partway through another, and the decoder simply has to index the exponents absolutely. This used to round the start down with loop & ~0x1F, which began the integration up to 31 samples early — and because the predictor has no leak and nothing downstream blocks DC, those extra deltas displaced the whole wave for its entire length rather than adding a moment of lead-in.
◆ region_size
| std::int32_t ts::WaveRom::region_size = 0x100000 |
|
staticconstexpr |
Size of one addressable ROM region, 1 MB.
◆ max_sample_count
| std::int32_t ts::WaveRom::max_sample_count = 2'000'000 |
|
staticconstexpr |
Largest wave this class will attempt to read, as a sanity bound.
◆ bank_a_region_count
| int ts::WaveRom::bank_a_region_count = 16 |
|
staticconstexpr |
Regions bank A spans: sixteen, the full width of the region nibble.
This read twelve for a long time, and descriptors reach past that — wave 4010 (TR-808 open hat) is region 12, wave 2092 (Bim Hit) region 14. That looked like a bug and is not: the two bank bases sit 0x1000030 apart, exactly 16 MB plus bank B's own 0x30 header, so regions 12–15 land at 0xc92700–0xf92700, well inside bank A and nowhere near bank B. The mapping bank_a_base + region * 1 MB is right for every region a descriptor can name, and nothing here bounds or clamps it.
Bank B is the one that genuinely stops early, at eight — see below.
◆ bank_b_region_count
| int ts::WaveRom::bank_b_region_count = 8 |
|
staticconstexpr |
Regions of real ROM data in bank B — eight, not twelve.
The manifest records both banks as 12 MB, but bank B's data ends at file offset 0x1892730: regions 0–3 are the tail of the 1996 rom_make image and regions 4–7 are the 1999 8820_wv0 image. The declared 12 MB span runs past the end of the file altogether, so the nominal size cannot be used as a bound.
The documentation for this class was generated from the following file: