pynbs
A simple python library to read and write .nbs files from Open Note Block Studio.
pynbs makes it possible to easily iterate over Note Block Studio songs.
import pynbs
for tick, chord in pynbs.read('demo_song.nbs'):
print(tick, [note.key for note in chord])
You can also use pynbs to generate new songs programmatically.
import pynbs
new_file = pynbs.new_file(song_name='Hello world')
new_file.notes.extend([
pynbs.Note(tick=i, layer=0, instrument=0, key=i + 35) for i in range(10)
])
new_file.save('new_file.nbs')
Installation
The package can be installed with pip.
$ pip install pynbs
The latest release follows the latest version of the NBS file format specification (version 5). However, it also allows you to load and save files in any of the older versions.
Basic usage
Reading files
You can use the read() function to read and parse a specific NBS file.
demo_song = pynbs.read('demo_song.nbs')
The read() function returns a pynbs file object. These objects have several
attributes that mirror the binary structure of NBS files.
Header
The first attribute is header, the file header. It contains information about
the file.
header = demo_song.header
| Attribute | Type | Details |
|---|---|---|
header.version |
int |
The NBS version this file was saved on. |
header.default_instruments |
int |
The amount of instruments from vanilla Minecraft in the song. |
header.song_length |
int |
The length of the song, measured in ticks. |
header.song_layers |
int |
The ID of the last layer with at least one note block in it. |
header.song_name |
str |
The name of the song. |
header.song_author |
str |
The author of the song. |
header.original_author |
str |
The original song author of the song. |
header.description |
str |
The description of the song. |
header.tempo |
float |
The tempo of the song. |
header.auto_save |
bool |
Whether auto-saving has been enabled. |
header.auto_save_duration |
int |
The amount of minutes between each auto-save. |
header.time_signature |
int |
The time signature of the song. |
header.minutes_spent |
int |
The amount of minutes spent on the project. |
header.left_clicks |
int |
The amount of times the user has left-clicked. |
header.right_clicks |
int |
The amount of times the user has right-clicked. |
header.blocks_added |
int |
The amount of times the user has added a block. |
header.blocks_removed |
int |
The amount of times the user has removed a block. |
header.song_origin |
str |
The file name of the original MIDI or schematic. |
header.loop |
bool |
Whether the song should loop back to the start after ending. |
header.max_loop_count |
int |
The amount of times to loop. 0 = infinite. |
header.loop_start |
int |
The tick the song will loop back to at the end of playback. |
For more information about all these fields, check out the official specification.
Notes
The notes attribute holds a list of all the notes of the song in order.
first_note = demo_song.notes[0]
| Attribute | Type | Details |
|---|---|---|
note.tick |
int |
The tick at which the note plays. |
note.layer |
int |
The ID of the layer in which the note is placed. |
note.instrument |
int |
The ID of the instrument. |
note.key |
int |
The key of the note. (between 0 and 87) |
note.velocity |
int |
The velocity of the note. (between 0 and 100) |
note.panning |
int |
The stereo panning of the note. (between -100 and 100) |
note.pitch |
int |
The detune of the note, in cents. (between -1200 and 1200) |
Layers
The layers attribute holds a list of all the layers of the song in order.
first_layer = demo_song.layers[0]
| Attribute | Type | Details |
|---|---|---|
layer.id |
int |
The ID of the layer. |
layer.name |
str |
The name of the layer. |
layer.lock |
bool |
Whether the layer is locked. |
layer.volume |
int |
The volume of the layer. |
layer.panning |
int |
The stereo panning of the layer. |
Instruments
The instruments attribute holds a list of all the custom instruments of the
song in order.
first_custom_instrument = demo_song.instruments[0]
| Attribute | Type | Details |
|---|---|---|
instrument.id |
int |
The ID of the instrument. |
instrument.name |
str |
The name of the instrument. |
instrument.file |
str |
The name of the sound file of the instrument. |
instrument.pitch |
int |
The pitch of the instrument. (between 0 and 87) |
instrument.press_key |
bool |
Whether the piano should automatically press keys with the instrument when the marker passes them. |
Iterating over songs
Iterating over a pynbs file object yields consecutively all the chords of the song with
the associated tick.
for tick, chord in demo_song:
...
chord is a list of all the notes that play during the tick tick.
Creating new files
You can create new files using the new_file() function. The function lets
you specify header attributes with keyword arguments.
new_file = pynbs.new_file(song_name='Hello world')
The function returns a new pynbs file object that you can now edit
programmatically.
Saving files
You can use the save() method to encode and write the file to a specified
location.
new_file.save('new_file.nbs')
By default, the file will be saved in the latest NBS version available.
To save the file in an older version, you can use the version parameter:
# This will save the song in the classic format.
new_file.save('new_file.nbs', version=0)
(Keep in mind some of the song properties may be lost when saving in older versions.)
Upgrading old files
While pynbs is up-to-date with the latest version of the Open Note Block Studio
specification, all previous versions — including the original file format — are still
supported by the read() function, making it possible to bulk upgrade songs to the
most recent version:
import glob
import pynbs
for old_file in glob.glob('*.nbs'):
pynbs.read(old_file).save(old_file)
Contributing
Contributions are welcome. Make sure to first open an issue discussing the problem or the new feature before creating a pull request. The project uses poetry.
$ poetry install
You can run the tests with poetry run pytest.
$ poetry run pytest
The code follows the black code style. Import statements are sorted with isort.
$ poetry run isort pynbs tests
$ poetry run black pynbs tests
$ poetry run black --check pynbs tests
License - MIT
Metadata
Release files for pynbs 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pynbs-1.1.0.tar.gz | 7.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pynbs-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.7 kB
Release files / pynbs-1.1.0.tar.gz
| Download URL | pynbs-1.1.0.tar.gz |
|---|---|
| Size | 7.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bc883de0b32dceaccf606b74d7a99a3ee7522d147bde3d8d3742ec0401b21759
|
|
BLAKE2b-256 checksum How to use checksums |
f2257414ef9db71f6edad03b4c527c9c8c57e9ec6c0fab3768b3216c994ca278
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.8.0 pkginfo/1.8.2 readme-renderer/34.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.9 tqdm/4.64.0 importlib-metadata/4.11.3 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.12
|
Release files / pynbs-1.1.0-py3-none-any.whl
| Download URL | pynbs-1.1.0-py3-none-any.whl |
|---|---|
| Size | 6.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1b25d2497af0f70e294a093ddef063d612baeb77fef0110cdf84638815061366
|
|
BLAKE2b-256 checksum How to use checksums |
705c8e9904201812d8319345566ada8b24bbba5a7e1d36b4d16d618ec0f7be97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.8.0 pkginfo/1.8.2 readme-renderer/34.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.9 tqdm/4.64.0 importlib-metadata/4.11.3 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.12
|
Security for pynbs 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.