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 is ndspy.WaveType.ADPCM, every block must begin with its own ADPCM header. More information about ADPCM headers can be found on GBATEK.

Type:

list of list of bytes

Default:

[]

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:

int

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:

bool

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 to True.

Type:

int

Default:

0

playerID

The ID of the stream player that will be used to play this stream.

Type:

int

Default:

0

priority

The stream’s “priority.” The exact meaning of this is unclear.

Type:

int

Default:

64

sampleRate

The sample rate the STRM should be played at.

Type:

int

Default:

8000

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:

int

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:

int

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:

int

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:

int

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:

int

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:

int

Default:

0

unk28

A value of unknown purpose at offset 0x40 (relative to the beginning of the file) in the STRM file header.

Type:

int

Default:

0

unk2C

A value of unknown purpose at offset 0x44 (relative to the beginning of the file) in the STRM file header.

Type:

int

Default:

0

unk30

A value of unknown purpose at offset 0x48 (relative to the beginning of the file) in the STRM file header.

Type:

int

Default:

0

unk34

A value of unknown purpose at offset 0x4C (relative to the beginning of the file) in the STRM file header.

Type:

int

Default:

0

unk38

A value of unknown purpose at offset 0x50 (relative to the beginning of the file) in the STRM file header.

Type:

int

Default:

0

unk3C

A value of unknown purpose at offset 0x54 (relative to the beginning of the file) in the STRM file header.

Type:

int

Default:

0

unk40

A value of unknown purpose at offset 0x58 (relative to the beginning of the file) in the STRM file header.

Type:

int

Default:

0

unk44

A value of unknown purpose at offset 0x5C (relative to the beginning of the file) in the STRM file header.

Type:

int

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:

int

Default:

127

waveType

The format that this STRM’s waveform data (channels) is in.

Type:

ndspy.WaveType (or int)

Default:

ndspy.WaveType.PCM8

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:

STRM

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:

STRM

save(*[, updateTime=False])

Generate file data representing this STRM, and then return that data, unk02, volume, priority, playerID, and unk07, 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 the time attribute.

default:

False

Returns:

The STRM file data, unk02, volume, priority, playerID, and unk07.

Return type:

(data, unk02, volume, priority, playerID, unk07), where data is of type bytes and all of the other elements are of type int

saveToFile(filePath, *[, updateTime=False])

Generate file data representing this STRM, and save it to a filesystem file. This is a convenience function.

Parameters:
  • filePath (str or other path-like object) – The path to the STRM file to save to.

  • updateTime (bool) –

    If this is True, time will be updated based on the sample rate, using the formula found in the documentation for the time attribute.

    default:

    False