ndspy.soundStream
: Sound Streams¶
The ndspy.soundStream
module lets you edit and create STRM streamed audio
files. These are intended to be used for background music.
A STRM is conceptually similar to a standard WAV audio file. They define a waveform rather than sequence events. They support multiple channels, and longer loops than SWAVs do. These are less commonly used than SSEQ sequenced audio files due to their much larger file size.
Warning
All STRMs I’ve found in retail games which have multiple blocks per
channel use the ADPCM wave type (waveType
=
ndspy.WaveType.ADPCM
). This may be due to a hardware limitation
explained on GBATEK
(see the section about the “Hold Flag (appears useless/bugged)”). You may
run into issues playing STRMs with multiple blocks per channel and some
other wave data format.
See also
If you aren’t familiar with how SDAT files are structured, consider reading the appendix explaining this.
- class ndspy.soundStream.STRM([file[, unk02[, volume[, priority[, playerID[, unk07]]]]]])¶
A STRM streamed audio file. This is a piece of music, usually used for background music or jingles.
- Parameters:
file (bytes) – The data to be read as an STRM file. If this is not provided, the STRM object will initially be empty.
unk02 – The initial value for the
unk02
attribute.volume – The initial value for the
volume
attribute.priority – The initial value for the
priority
attribute.playerID – The initial value for the
playerID
attribute.unk07 – The initial value for the
unk07
attribute.
- channels¶
This attribute contains the STRM’s raw waveform data, organized by channel and block.
This attribute is a list where each element represents a channel. Each of these channels is itself a list of
bytes
objects representing blocks of wave data. Many STRMs have channels that are only one block long, but some have hundreds or even thousands of blocks per channel.Warning
There are some restrictions on what you’re allowed to put in here, and you’ll experience errors upon trying to save (
save()
) if you don’t follow them:All channels must have the same number of blocks:
for c in strm.channels: assert len(c) == len(strm.channels[0])
All of the blocks in a given channel must be of the same size, except for the last block, which can be a different size from the others (typically shorter, but this isn’t enforced):
for c in strm.channels: for b in c[:-1]: assert len(b) == len(c[0])
The lengths of the blocks in all channels must match:
for c in strm.channels: for i, b in enumerate(c): assert len(b) == len(strm.channels[0][i])
Note
If the
waveType
isndspy.WaveType.ADPCM
, every block must begin with its own ADPCM header. More information about ADPCM headers can be found on GBATEK.
- dataMergeOptimizationID¶
When saving a SDAT file containing multiple STRM files, ndspy will check if any of them save to identical data. If it finds any, it will only encode the data for them once and then reference it multiple times, to save some space. This attribute is an extra field that is also compared between STRM files, which you can use to exclude particular ones from this optimization.
Since this defaults to 0 for all STRMs created from scratch, this optimization will happen by default. It’s unlikely that you will need to use this attribute to disable the optimization, but you can.
Note
This value is not explicitly saved in the STRM file or in the SDAT file containing it.
- Type:
- Default:
0
- isLooped¶
Whether the STRM is looped or just plays through once.
See also
You can use
loopOffset
to control the beginning of the looped region.- Type:
- Default:
False
- loopOffset¶
The beginning of the looped portion of the STRM data, measured in samples.
See also
In order to loop a STRM, you also need to set
isLooped
toTrue
.- Type:
- Default:
0
- samplesInLastBlock¶
The length in samples of each channel’s last block of waveform data (
channels
).See also
samplesPerBlock
– the corresponding attribute that defines the number of samples in all blocks except for each channel’s last one.- Type:
- Default:
0
- samplesPerBlock¶
The length in samples of each individual block of waveform data (in
channels
), per channel, ignoring the final block of each channel.See also
samplesInLastBlock
– the corresponding attribute that defines the number of samples in each channel’s last block.- Type:
- Default:
0
- time¶
A value of unclear meaning. This is pretty much always set to the following:
strm.time = int(1.0 / strm.sampleRate * 16756991 / 32)
Note
This can optionally be recalculated for you automatically upon saving the STRM. For more information about this, see the documentation for the
save()
function.- Type:
- Default:
0
- unk02¶
The value following the STRM’s file ID in the “INFO” section of the SDAT file it is contained in. Its purpose is unknown.
Note
This value is not explicitly saved in the STRM file, but it is saved in the SDAT file if the STRM is within one.
- Type:
- Default:
0
- unk07¶
The value following the STRM’s player ID in the “INFO” section of the SDAT file it is contained in. Its purpose is unknown.
Note
This value is not explicitly saved in the STRM file, but it is saved in the SDAT file if the STRM is within one.
- Type:
- Default:
0
- unk03¶
A value of unknown purpose at offset 0x1B (relative to the beginning of the file) in the STRM file header.
Based on its location relative to surrounding values, this could be a meaningless padding byte for alignment.
- Type:
- Default:
0
- unk28¶
A value of unknown purpose at offset 0x40 (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- unk2C¶
A value of unknown purpose at offset 0x44 (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- unk30¶
A value of unknown purpose at offset 0x48 (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- unk34¶
A value of unknown purpose at offset 0x4C (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- unk38¶
A value of unknown purpose at offset 0x50 (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- unk3C¶
A value of unknown purpose at offset 0x54 (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- unk40¶
A value of unknown purpose at offset 0x58 (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- unk44¶
A value of unknown purpose at offset 0x5C (relative to the beginning of the file) in the STRM file header.
- Type:
- Default:
0
- volume¶
The overall volume of the stream. This is an integer between 0 and 127, inclusive. You should usually leave this as 127.
- Type:
- Default:
127
- waveType¶
The format that this STRM’s waveform data (
channels
) is in.- Type:
ndspy.WaveType
(orint
)- Default:
- classmethod fromChannels(channels[, unk02[, volume[, priority[, playerID[, unk07]]]]])¶
Create a STRM from a list of channels.
- Parameters:
channels – The initial value for the
channels
attribute.unk02 – The initial value for the
unk02
attribute.volume – The initial value for the
volume
attribute.priority – The initial value for the
priority
attribute.playerID – The initial value for the
playerID
attribute.unk07 – The initial value for the
unk07
attribute.
- Returns:
The STRM object.
- Return type:
- classmethod fromFile(filePath[, ...])¶
Load a STRM from a filesystem file. This is a convenience function.
- Parameters:
filePath (
str
or other path-like object) – The path to the STRM file to open.
Further parameters are the same as those of the default constructor.
- Returns:
The STRM object.
- Return type:
- save(*[, updateTime=False])¶
Generate file data representing this STRM, and then return that data,
unk02
,volume
,priority
,playerID
, andunk07
, as a 6-tuple. This matches the parameters of the default class constructor.- Parameters:
updateTime (bool) –
If this is
True
,time
will be updated based on the sample rate, using the formula found in the documentation for thetime
attribute.- default:
False
- Returns:
The STRM file data,
unk02
,volume
,priority
,playerID
, andunk07
.- Return type:
(data, unk02, volume, priority, playerID, unk07)
, wheredata
is of typebytes
and all of the other elements are of typeint
- saveToFile(filePath, *[, updateTime=False])¶
Generate file data representing this STRM, and save it to a filesystem file. This is a convenience function.