Skip to main content

pynbs

GitHub Actions PyPI PyPI - Python Version Code style: black

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)

Source distribution for pynbs 1.1.0
File Size Uploaded Provenance
pynbs-1.1.0.tar.gz 7.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pynbs 1.1.0
File Interpreter ABI Platform
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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page