rsnbs 0.1.2

IO functionality for the OpenNBS .nbs format
Documentation
# rsnbs

[![GitHub Actions](https://github.com/omninbs/rsnbs/workflows/Rust/badge.svg)](https://github.com/omninbs/rsnbs/actions)
[![crates.io](https://img.shields.io/crates/v/rsnbs.svg)](https://crates.io/crates/rsnbs)
[![Rust Version](https://img.shields.io/badge/rust-1.56.0%2B-orange.svg)](https://crates.io/crates/rsnbs)
[![Code style: rustfmt](https://img.shields.io/badge/code%20style-rustfmt-blue.svg)](https://github.com/rust-lang/rustfmt)

> A simple rust library to read and write [.nbs files]https://opennbs.org/nbs
> from [Open Note Block Studio]https://opennbs.org/.

`rsnbs` has all the functionality `pynbs` has, like iterating over Note Block Studio songs
```rust
use rsnbs::read_nbs;

let song = read_nbs("song.nbs");
for note in song.notes {
  println!("tick: {}, instrument: {}", note.tick.unwrap(), note.instrument.unwrap())
}
```

or generating new songs programmatically
```rust
use rsnbs::{Song, Note};

let song = Song::default();
for i in 0..10 {
  Song.notes.push(Note {
    tick: Some(i), layer: None, instrument: None,
    velocity: 30, panning: None, pitch: None, key: Some(i+35)
  })
}
```
the main difference is that every field is an option (for version differences sake) where None acts as 0/"".

## Installation

The package can be installed with `cargo`
```bash
$ cargo install rsnbs
```

## Reading / Writing
You can use the read_nbs function to read an parse a specific NBS file of any version.
```rust
  let song = rsnbs::read_nbs("song.nbs");
```
This returns a rsnbs::Song object wich can then be written using Song::save
```rust
  song.save("song.nbs", version);
```

## Song struct
Song implements the Default trait so you can instance a default with 1 layer and all None fields
```rust
  let song = Song::default();
```
### Fields
#### Header
the first field is `header`, the file header, of type struct `Header`
Attribute                   | Type    | Details
:---------------------------|:--------|:------------------------------------------------
`header.version`            | `i8`   | The NBS version this file was saved on.
`header.default_instruments`| `i8`   | The amount of instruments from vanilla Minecraft in the song.
`header.song_length`        | `i16`   | The length of the song, measured in ticks.
`header.song_layers`        | `i16`   | The ID of the last layer with at least one note block in it.
`header.song_name`          | `String`   | The name of the song.
`header.song_author`        | `String`   | The author of the song.
`header.original_author`    | `String`   | The original song author of the song.
`header.description`        | `String`   | The description of the song.
`header.tempo`              | `i16` | The tempo of the song multiplied by 100.
`header.auto_save`          | `bool`  | Whether auto-saving has been enabled.
`header.auto_save_duration` | `i8`   | The amount of minutes between each auto-save.
`header.time_signature`     | `i8`   | The time signature of the song.
`header.minutes_spent`      | `i32`   | The amount of minutes spent on the project.
`header.left_clicks`        | `i32`   | The amount of times the user has left-clicked.
`header.right_clicks`       | `i32`   | The amount of times the user has right-clicked.
`header.blocks_added`       | `i32`   | The amount of times the user has added a block.
`header.blocks_removed`     | `i32`   | The amount of times the user has removed a block.
`header.song_origin`        | `String`   | 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`     | `i8`   | The amount of times to loop. 0 = infinite.
`header.loop_start`         | `i16`   | The tick the song will loop back to at the end of playback.

#### Notes
the `notes` field has all the notes of type struct `Note` stored in a vec in order
Attribute         | Type  | Details
:---------------- |:------|:------------------------------------------------
`note.tick`       | `i32` | The tick at which the note plays.
`note.layer`      | `i32` | The ID of the layer in which the note is placed.
`note.instrument` | `i8` | The ID of the instrument.
`note.key`        | `i8` | The key of the note. (between 0 and 87)
`note.velocity`   | `i8` | The velocity of the note. (between 0 and 100)
`note.panning`    | `u8` | The stereo panning of the note. (between -100 and 100)
`note.pitch`      | `i16` | The detune of the note, in cents. (between -1200 and 1200)

#### Layers 
the `layers` field is a vec of all layers of type struct `Layer` in order
Attribute         | Type  | Details
:-----------------|:------|:------------------------
`layer.name`      | `String` | The name of the layer.
`layer.lock`      | `bool`| Whether the layer is locked.
`layer.volume`    | `i8` | The volume of the layer.
`layer.panning`   | `u8` | The stereo panning of the layer.

#### Instruments
the `instruments` field stores all the custom instruments of the song in order in a vec
Attribute              | Type   | Details
:----------------------|:-------|:----------------------------------------------------------
`instrument.name`      | `String`  | The name of the instrument.
`instrument.file`      | `String`  | The name of the sound file of the instrument.
`instrument.pitch`     | `i8`  | 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.