ndspy.soundBank
: Instrument Banks¶
The ndspy.soundBank
module contains classes and functions related to the
SBNK instrument bank file included in SDAT sound archives.
See also
If you aren’t familiar with how SDAT files are structured, consider reading the appendix explaining this.
- ndspy.soundBank.NO_INSTRUMENT_TYPE¶
The type value of a nonexistent instrument: 0.
- ndspy.soundBank.SINGLE_NOTE_PCM_INSTRUMENT_TYPE¶
The type value of a
SingleNoteInstrument
that plays a SWAV from a SWAR: 1.
- ndspy.soundBank.SINGLE_NOTE_PSG_SQUARE_WAVE_INSTRUMENT_TYPE¶
The type value of a
SingleNoteInstrument
that plays a square wave using the Nintendo DS’s PSG hardware: 2.
- ndspy.soundBank.SINGLE_NOTE_PSG_WHITE_NOISE_INSTRUMENT_TYPE¶
The type value of a
SingleNoteInstrument
that plays white noise using the Nintendo DS’s PSG hardware: 3.
- ndspy.soundBank.RANGE_INSTRUMENT_TYPE¶
The type value of a
RangeInstrument
: 16.
- ndspy.soundBank.REGIONAL_INSTRUMENT_TYPE¶
The type value of a
RegionalInstrument
: 17.
- class ndspy.soundBank.NoteType¶
- Base class:
An enumeration that distinguishes between the three primary types of note definitions.
See also
NoteDefinition
– for more information about these type values.- PCM¶
The type value of a
NoteDefinition
that plays an SWAV from a SWAR: 1.
- PSG_SQUARE_WAVE¶
The type value of a
NoteDefinition
that plays a square wave using the Nintendo DS’s PSG hardware: 2.
- PSG_WHITE_NOISE¶
The type value of a
NoteDefinition
that plays white noise using the Nintendo DS’s PSG hardware: 3.
- class ndspy.soundBank.NoteDefinition([waveID_dutyCycle[, waveArchiveIDID[, pitch[, attack[, decay[, sustain[, release[, pan[, type]]]]]]]]])¶
A note definition within a SBNK instrument. This can be thought of as a template from which many notes of different pitches can be played.
There are three known meaningful type values (
type
) associated with this class, which affect which attributes are meaningful:NoteType.PCM
will produce a PCM note definition, which can play a SWAV wave file from a SWAR wave archive file.If the note definition is of this type, you can use the
waveID
andwaveArchiveIDID
attributes to set the SWAV and SWAR IDs, respectively.NoteType.PSG_SQUARE_WAVE
will produce a PSG square-wave note definition, which uses the Nintendo DS’s PSG hardware to play a square wave.If the instrument is of this type, you can use the
dutyCycle
attribute to set the square wave’s duty cycle.NoteType.PSG_WHITE_NOISE
will produce a PSG white noise note definition, which uses the Nintendo DS’s PSG hardware to play white noise.There are no attributes that are specific to this instrument type.
Attributes not mentioned above will work with all type values.
- Parameters:
waveID_dutyCycle – The initial value for the
waveID
anddutyCycle
attributes.waveArchiveIDID – The initial value for the
waveArchiveIDID
attribute.pitch – The initial value for the
pitch
attribute.attack – The initial value for the
attack
attribute.decay – The initial value for the
decay
attribute.sustain – The initial value for the
sustain
attribute.release – The initial value for the
release
attribute.pan – The initial value for the
pan
attribute.type – The initial value for the
type
attribute.
- attack¶
The speed at which the note will fade from 0 to 100% volume when it begins to play. 0 is the slowest speed possible, and 127 is instant.
See also
The Wikipedia page on envelope explains attack, decay, sustain, and release values.
Section 4.2 (Articulation Data) in the kiwi.ds Nitro Composer File (*.sdat) Specification explains this in more detail.
Note
The link in the sentence “See this file for more details on how to interpret the articulation data” may be broken; here is the correct link.
- Type:
- Default:
127
- decay¶
The speed at which the note will fade from 100% volume to the
sustain
level after theattack
phase is finished. 0 is the slowest speed possible, and 127 is instant.See also
The Wikipedia page on envelope explains attack, decay, sustain, and release values.
Section 4.2 (Articulation Data) in the kiwi.ds Nitro Composer File (*.sdat) Specification explains this in more detail.
Note
The link in the sentence “See this file for more details on how to interpret the articulation data” may be broken; here is the correct link.
- Type:
- Default:
127
- dutyCycle¶
The duty cycle of the PSG square wave defined by this note definition. Values are as follows:
Attribute value
Actual duty cycle
0
12.5%
1
25%
2
37.5%
3
50%
4
62.5%
5
75%
6
87.5%
7
0%
Higher values are bitwise-AND-ed with 7.
Note
This only has an effect if
type
isNoteType.PSG_SQUARE_WAVE
.Note
This is an alias for
waveID
. This does not cause conflicts, since this attribute only affects note definitions that define PSG square waves, which do not use SWAVs at all.- Type:
- Default:
0
- pan¶
The note’s stereo panning value. A value of 64 is centered. Smaller values pan to the left, and larger values pan to the right.
Note
SSEQ sequence events can also specify panning values, using
ndspy.soundSequence.PanSequenceEvent
s. The interplay between instrument and track panning may cause your track’s sounds to ultimately be panned differently from how yourpan
value dictates.- Type:
- Default:
64
- pitch¶
The pitch number that the instrument sample wave plays. This is used to calculate the adjusted sample rate that the wave needs to be played at to produce a desired actual pitch in the sequence.
This is measured in half-steps; 60 is middle C. Valid values are between 0 and 127, inclusive.
- Type:
- Default:
60
- release¶
The speed at which the note will fade from the
sustain
level to 0% volume when it is released. 0 is the slowest speed possible, and 127 is instant.See also
The Wikipedia page on envelope explains attack, decay, sustain, and release values.
Section 4.2 (Articulation Data) in the kiwi.ds Nitro Composer File (*.sdat) Specification explains this in more detail.
Note
The link in the sentence “See this file for more details on how to interpret the articulation data” may be broken; here is the correct link.
- Type:
- Default:
127
- sustain¶
The volume that the note will remain at after the
attack
anddecay
phases are finished. 0 is no volume, and 127 is 100% volume.See also
The Wikipedia page on envelope explains attack, decay, sustain, and release values.
Section 4.2 (Articulation Data) in the kiwi.ds Nitro Composer File (*.sdat) Specification explains this in more detail.
Note
The link in the sentence “See this file for more details on how to interpret the articulation data” may be broken; here is the correct link.
- Type:
- Default:
127
- type¶
The type of sound that will be produced when this note definition is played. The value of this attribute affects whether other attributes are meaningful or not, such as
dutyCycle
,waveID
, andwaveArchiveIDID
.Warning
If this note definition is within a
SingleNoteInstrument
, this attribute is an alias forSingleNoteInstrument.type
(automatically cast to and fromNoteType
for you). See the documentation forSingleNoteInstrument.type
for more information.See also
NoteDefinition
– for more information about valid values for this attribute.- Type:
- Default:
- waveArchiveIDID¶
An index into the SWAR IDs list of the SBNK this note definition is a part of (
SBNK.waveArchiveIDs
). This, in turn, indicates the ID number (index) of the SWAR where the SWAV for this note’s instrument sample can be found.Warning
This is not the index of the SWAR in
ndspy.soundArchive.SDAT.waveArchives
!For example, if this attribute has a value 3, you would look up
sbnk.waveArchiveIDs[3]
in the SBNK this note definition resides in. The value you find there is the actual SWAR ID, which you can use to get the actual SWAR from the SDAT:sdat.waveArchives[swarID]
.Note
This only has an effect if
type
isNoteType.PCM
.See also
waveID
– the ID number of the SWAV to use from the SWAR.- Type:
- Default:
0
- waveID¶
The ID number (index) of the SWAV to use as the instrument sample for this note.
Note
This only has an effect if
type
isNoteType.PCM
.Note
This is an alias for
dutyCycle
. This does not cause conflicts, since that attribute only affects note definitions that define PSG square waves, which do not use SWAVs at all.See also
waveArchiveIDID
– the ID number of the ID number of the SWAR where this SWAV can be found.- Type:
- Default:
0
- classmethod fromData(data[, type])¶
Create a note definition from raw file data that does not include the
type
value at the beginning.See also
fromDataWithType()
– use this function instead if the file data does includetype
.- Parameters:
- Returns:
The note definition object.
- Return type:
- classmethod fromDataWithType(data)¶
Create a note definition from raw file data that includes the
type
value at the beginning.See also
fromData()
– use this function instead if the file data does not includetype
.- Parameters:
data (bytes) – The data to be read. Only the first 12 bytes will be used.
- Returns:
The note definition object.
- Return type:
- save()¶
Generate data representing this note definition, without including the
type
value at the beginning.See also
saveWithType()
– use this function instead if you want the data to includetype
.- Returns:
The note definition data.
- Return type:
- class ndspy.soundBank.Instrument(type)¶
An instrument within a SBNK file.
This is an abstract base class, and should be subclassed in order to be used.
See also
SingleNoteInstrument
– the subclass that should be used fortype
values 1 through 15 (SINGLE_NOTE_PCM_INSTRUMENT_TYPE
,SINGLE_NOTE_PSG_SQUARE_WAVE_INSTRUMENT_TYPE
, andSINGLE_NOTE_PSG_WHITE_NOISE_INSTRUMENT_TYPE
).RangeInstrument
– the subclass that should be used fortype
value 16 (RANGE_INSTRUMENT_TYPE
).RegionalInstrument
– the subclass that should be used fortype
value 17 (REGIONAL_INSTRUMENT_TYPE
).- Parameters:
type – The initial value for the
type
attribute.
- bankOrderKey¶
This attribute has to do with the way instrument data structs are sorted within the SBNK. The data structs are always first sorted by instrument type (first types < 16, then type 16, then type 17). Within each of those three groups, though, the order is arbitrary. Thus, this key allows you to set up whatever arrangement you want.
It’s extremely unlikely that you’ll ever need to look at or change this, since the order of the structs doesn’t really affect anything.
Note
This value is not explicitly saved in the SBNK file.
- Type:
- Default:
0
- dataMergeOptimizationID¶
When saving a SBNK, ndspy will check if any instruments have 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 instruments, which you can use to exclude particular instruments from this optimization.
Since this defaults to 0 for all instruments 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 SBNK file.
- Type:
- Default:
0
- type¶
The type value of this instrument.
Warning
In the
SingleNoteInstrument
subclass, this is an alias forinstrument.noteDefinition.type
. SeeSingleNoteInstrument.type
for more information.See also
NO_INSTRUMENT_TYPE
,SINGLE_NOTE_PCM_INSTRUMENT_TYPE
,SINGLE_NOTE_PSG_SQUARE_WAVE_INSTRUMENT_TYPE
,SINGLE_NOTE_PSG_WHITE_NOISE_INSTRUMENT_TYPE
,RANGE_INSTRUMENT_TYPE
,REGIONAL_INSTRUMENT_TYPE
– type values for known instrument types.- Type:
- classmethod fromData(type, data, startOffset)¶
Create an instrument from raw file data.
This method must be implemented in subclasses; this abstract-base-class implementation simply raises
NotImplementedError
.- Parameters:
type – The initial value for the
type
attribute.data (bytes) – The data to be read. The instrument data need not be at the beginning of it.
startOffset (int) – The offset in the data where the instrument data begins. This is not the place in the SBNK where the instrument type value is; rather, it is the place pointed to by the offset that comes just after that.
- Returns:
The instrument object, and the number of bytes that were read to create it.
- Return type:
(instrument, bytesRead)
, whereinstrument
is of typeInstrument
andbytesRead
is of typeint
.
- class ndspy.soundBank.SingleNoteInstrument(noteDefinition)¶
- Base class:
An instrument that contains one note definition and nothing else. This is usually used for sound effects, which often contain one sound each anyway. This class encompasses instrument type (
Instrument.type
) values 1 through 15.See the base class documentation (
Instrument
) for information about inherited functions and attributes.- Parameters:
noteDefinition – The initial value for the
noteDefinition
attribute.
- noteDefinition¶
The note definition that this instrument will use.
- Type:
- type¶
The type value of this instrument. See
Instrument.Type
for more information.Warning
The type values for a single-note instrument and its note definition are encoded as a single shared value in the SBNK file; thus, they are required to be the same. As such, this property is an alias for
instrument.noteDefinition.type
(automatically cast to and fromint
for you).See also
NoteDefinition.type
– the attribute that this is an alias of.- Type:
- classmethod fromData(type, data, startOffset)¶
Create a single-note instrument from raw file data.
- Parameters:
type – The initial value for the
type
attribute. This should be between 1 and 15, inclusive.data (bytes) – The data to be read. The instrument data need not be at the beginning of it.
startOffset (int) – The offset in the data where the instrument data begins. This is not the place in the SBNK where the instrument type value is; rather, it is the place pointed to by the offset that comes just after that.
- Returns:
The instrument object, and the number of bytes that were read to create it.
- Return type:
(instrument, bytesRead)
, whereinstrument
is of typeSingleNoteInstrument
andbytesRead
is of typeint
.
- class ndspy.soundBank.RangeInstrument(firstPitch, noteDefinitions)¶
- Base class:
An instrument that contains one note definition for each pitch in a given range. This is usually used for drumsets, since it is ideal for instruments with many distinct sounds that each only need to be played at one pitch. This class is for instrument type (
Instrument.type
) value 16 (RANGE_INSTRUMENT_TYPE
).See the base class documentation (
Instrument
) for information about inherited functions and attributes.- Parameters:
firstPitch – The initial value for the
firstPitch
attribute.noteDefinitions – The initial value for the
noteDefinitions
attribute.
- firstPitch¶
The pitch number that can be played to access the first note in
noteDefinitions
. The second note (if there is one) can then be played as this value plus 1, and so on.This is measured in half-steps; 60 is middle C. Valid values are between 0 and 127, inclusive.
- Type:
- noteDefinitions¶
The list of note definitions that this instrument will use.
- Type:
- classmethod fromData(_, data, startOffset)¶
Create a range instrument from raw file data.
- Parameters:
_ (any type) – Ignored. This exists as a placeholder for the “type” parameter that exists in the signature of this function in the superclass (
Instrument
), so that this function can be called without any special-casing.data (bytes) – The data to be read. The instrument data need not be at the beginning of it.
startOffset (int) – The offset in the data where the instrument data begins. This is not the place in the SBNK where the instrument type value is; rather, it is the place pointed to by the offset that comes just after that.
- Returns:
The instrument object, and the number of bytes that were read to create it.
- Return type:
(instrument, bytesRead)
, whereinstrument
is of typeRangeInstrument
andbytesRead
is of typeint
.
- class ndspy.soundBank.RegionalInstrument(regions)¶
- Base class:
An instrument that partitions the range [0, 127] into sections, and contains one note definition for each. This is used for most musical instruments, because it lets you use a few samples to cover a large range of pitches. Using a different sample for each note would be more accurate, but would use much more memory. Using only one sample for an instrument would cause it to sound increasingly distorted when playing notes that are far away from the sample’s pitch.
This class is for instrument type (
Instrument.type
) value 17 (REGIONAL_INSTRUMENT_TYPE
).See the base class documentation (
Instrument
) for information about inherited functions and attributes.- Parameters:
regions – The initial value for the
regions
attribute.
- regions¶
The list of regions included in this instrument. These should be sorted in order of increasing
Region.lastPitch
, and the last region should haveRegion.lastPitch
= 127. This ensures that the entire range of pitches from 0 to 127 inclusive is covered.You can define up to 8 regions. The realistic minimum number of regions is 1 (although such an instrument would probably be better represented as a
SingleNoteInstrument
); you can save a regional instrument with no regions, but it is unknown how such an instrument would behave in an actual game.
- classmethod fromData(_, data, startOffset)¶
Create a regional instrument from raw file data.
- Parameters:
_ (any type) – Ignored. This exists as a placeholder for the “type” parameter that exists in the signature of this function in the superclass (
Instrument
), so that this function can be called without any special-casing.data (bytes) – The data to be read. The instrument data need not be at the beginning of it.
startOffset (int) – The offset in the data where the instrument data begins. This is not the place in the SBNK where the instrument type value is; rather, it is the place pointed to by the offset that comes just after that.
- Returns:
The instrument object, and the number of bytes that were read to create it.
- Return type:
(instrument, bytesRead)
, whereinstrument
is of typeRegionalInstrument
andbytesRead
is of typeint
.
- save()¶
Generate file data representing this instrument, and then return the instrument’s type value and that data as a pair.
- Returns:
The instrument’s type value and data representing the instrument, as a pair.
- Return type:
(type, data)
, wheretype
is of typeint
anddata
is of typebytes
- Raises:
ValueError – if there are more than 8 regions in
regions
- class RegionalInstrument.Region(lastPitch, noteDefinition)¶
A region within a regional instrument. The highest pitch included in the region is
lastPitch
. The lowest pitch included in the region is 0 if this is the first region in the instrument, or 1 + thelastPitch
of the previous region if it is not.- Parameters:
lastPitch – The initial value for the
lastPitch
attribute.noteDefinition – The initial value for the
noteDefinition
attribute.
- lastPitch¶
The highest pitch value included in this region.
This is measured in half-steps; 60 is middle C. Valid values are between 0 and 127, inclusive.
- Type:
- noteDefinition¶
The note definition that will be used to play notes within this region.
- Type:
- ndspy.soundBank.instrumentClass(type)¶
A convenience function that returns the
Instrument
subclass that should be used to load an instrument with the given type value.- Parameters:
type (int) – The type value to find the class for.
- Returns:
The class object or
None
:None
, iftype
isNO_INSTRUMENT_TYPE
(0)SingleNoteInstrument
, iftype
isSINGLE_NOTE_PCM_INSTRUMENT_TYPE
(1),SINGLE_NOTE_PSG_SQUARE_WAVE_INSTRUMENT_TYPE
(2),SINGLE_NOTE_PSG_WHITE_NOISE_INSTRUMENT_TYPE
(3), or any other value less than 16RangeInstrument
, iftype
isRANGE_INSTRUMENT_TYPE
(16)RegionalInstrument
, iftype
isREGIONAL_INSTRUMENT_TYPE
(17)
- Return type:
- Raises:
ValueError – if
type
is larger than 17
- ndspy.soundBank.guessInstrumentType(data, startOffset, possibleTypes, bytesAvailable)¶
Try to guess the type of instrument stored in some binary data based on both the data and a set of possible types (ones that haven’t been ruled out by the instrument’s position in the surrounding data). This function is entirely based on heuristics, so it may return different answers for similar data, and it cannot always be accurate.
Types 1, 2 and 3 (
SINGLE_NOTE_PCM_INSTRUMENT_TYPE
,SINGLE_NOTE_PSG_SQUARE_WAVE_INSTRUMENT_TYPE
, andSINGLE_NOTE_PSG_WHITE_NOISE_INSTRUMENT_TYPE
) are considered equivalent by this function, since they are very similar and all use the same Python class (SingleNoteInstrument
).None
will be returned if it’s very unlikely that there is an instrument at that position.- Parameters:
data (bytes) – The data to be read. The possible instrument data need not be at the beginning of it.
startOffset (int) – The offset in the data where the possible instrument data begins. This is not the place in the SBNK where the instrument type value is (as then this function would be trivial); rather, it is the place pointed to by the offset that comes just after that.
possibleTypes (
set
ofint
, orlist
ofint
) –The set of possible instrument types that should be considered.
SINGLE_NOTE_PSG_SQUARE_WAVE_INSTRUMENT_TYPE
andSINGLE_NOTE_PSG_SQUARE_WAVE_INSTRUMENT_TYPE
are both treated as aliases ofSINGLE_NOTE_PCM_INSTRUMENT_TYPE
.bytesAvailable (int) – The number of bytes that are available for a possible instrument to occupy. This lets the function rule out instrument types that would be too long and overlap the following instrument.
- Returns:
The best guess for the instrument type value, or
None
if it seems unlikely that there is any instrument in the data there.- Return type:
int
orNone
- class ndspy.soundBank.SBNK([file[, unk02[, waveArchiveIDs]]])¶
A SBNK instrument bank file. This defines a set of instruments that sequences and sequence archives can use.
- Parameters:
file (bytes) – The data to be read as an SBNK file. If this is not provided, the SBNK object will initially be empty.
unk02 – The initial value for the
unk02
attribute.waveArchiveIDs –
The initial value for the
waveArchiveIDs
attribute.There can be up to four IDs here. You may include
None
s to pad the list length to four, but they will be removed.
- dataMergeOptimizationID¶
When saving a SDAT file containing multiple SBNK 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 SBNK files, which you can use to exclude particular ones from this optimization.
Since this defaults to 0 for all SBNKs 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 SBNK file or in the SDAT file containing it.
- Type:
- inaccessibleInstruments¶
Some SBNK files contain data for instruments that aren’t defined anywhere in the instrument table. For maximum accuracy, ndspy attempts to find and load these instruments using heuristics, so they can be included with the file when it is re-saved. These instruments can be found here.
Each dictionary key is the ID of the previous instrument that does have an ID, and each dictionary value is the list of inaccessible instruments that follow that one.
This may be more clear with an example:
Suppose there exists data for two inaccessible instruments between the data for instruments 12 and 7 (which is a very possible scenario, since instrument data usually does not follow instrument ID order). Call them
inst1
andinst2
. In this example,inaccessibleInstruments
would contain the following:{12: [inst1, inst2]}
This is read as “the two inaccessible instruments following the data for instrument 12 are
inst1
andinst2
”.Since this attribute is mostly based on heuristics, it may miss instruments, or contain instruments of the wrong type.
Warning
While it is possible to put new instruments here, this is strongly recommended against, since it cannot be guaranteed that such instruments will be parsed correctly when the SBNK is saved and re-opened. Additionally, other tools that support SBNK may corrupt or remove this data. Also, why would you even do that?
You should either ignore this attribute, or treat it as read-only (although it’s fine to manually clear it if you want to ensure that your files will be as small as possible). In all cases, take whatever you find within it with a grain of salt.
In addition, this attribute may disappear in future versions of ndspy if it is discovered that these instruments do have an actual purpose.
- Type:
dict
:{previousID: instruments}
, wherepreviousID
is of typeint
orNone
, andinstruments
is alist
of instances of subclasses ofInstrument
- Default:
{}
- instruments¶
The list of instruments contained in the SBNK. “Instrument IDs” are indices into this list.
- Type:
list
both of instances of subclasses ofInstrument
, and ofNone
- Default:
[]
- unk02¶
The value following the SBNK’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 SBNK file, but it is saved in the SDAT file if the SBNK is within one.
- Type:
- Default:
0
- waveArchiveIDs¶
The list of SWAR IDs that instruments in this bank may use. This can contain up to four IDs.
If this SBNK is loaded through a sound group entry with its
ndspy.soundGroup.GroupEntry.loadSBNKSWARsFrom
attribute set tondspy.soundGroup.SWARLoadMethod.fileIDs
, the IDs in this list will be interpreted as raw SDAT file IDs instead of SWAR IDs.Note
ndspy doesn’t expose raw SDAT file IDs, and the functionality described above seems to never really be used in practice (and there’s honestly no good reason to do so), so you don’t really need to worry about that case very much.
- classmethod fromInstruments(instruments[, unk02[, waveArchiveIDs]])¶
Create a SBNK from a list of instruments.
- Parameters:
instruments – The initial value for the
instruments
attribute.unk02 – The initial value for the
unk02
attribute.waveArchiveIDs –
The initial value for the
waveArchiveIDs
attribute.There can be up to four IDs here. You may include
None
s to pad the list length to four, but they will be removed.
- Returns:
The SBNK object.
- Return type:
- classmethod fromFile(filePath[, ...])¶
Load an SBNK from a filesystem file. This is a convenience function.
- Parameters:
filePath (
str
or other path-like object) – The path to the SBNK file to open.
Further parameters are the same as those of the default constructor.
- Returns:
The SBNK object.
- Return type:
- save()¶
Generate file data representing this SBNK, and then return that data,
unk02
, andwaveArchiveIDs
as a triple. This matches the parameters of the default class constructor.