furnace-module-interface
TypeScript icon, indicating that this package has built-in type declarations

0.5.1 • Public • Published

furnace-module-interface

An interface for loading, processing and saving furnace modules in an object-oriented manner. Fully typed via TypeScript.

Installation

npm install furnace-module-interface

Here is an example of a typical usecase:

import fsp from "fs/promises";
import { loadFurnaceModule, deflateBuffer } from "furnace-module-interface";

const file = await fsp.readFile("testfile.fur")
const module = await loadFurnaceModule(file);

if(module instanceof FurnaceSongModule) {
    // only modify name IF this is a furnace song module (.fur extension should always be that!)
    module.info.name = "Example module name";

    const newdata = module.getAsBuffer();
    await fsp.writeFile("editedtestfile.fur", deflateBuffer(newdata));
}

API

Modules

There are 3 types of furnace modules: FurnaceSongModule for full songs, FurnaceInstrumentModule for instrument module files, and FurnaceWavetableModule for wavetable module files. furnace-module-interface supports all 3, but they have many differences. Checking modules you get by calling loadFurnaceModule is recommended as a way to ensure you are processing the right version:

import { loadFurnaceModule } from "furnace-module-interface";

const module = await loadFurnaceModule(fileBuffer);

if(module instanceof FurnaceSongModule) {
    // process song module

} else if(module instanceof FurnaceInstrumentModule) {
    // process instrument module

} else if(module instanceof FurnaceWavetableModule) {
    // process wavetable module

} else {
    // no idea what we got. Maybe this is a future version with even more modules?
}

Subsongs

dev95 introduced subsongs, but before they were not supported. furnace-module-interface pretends the main subsong is just like any subsong, even in older versions. Check FurnaceSongModule.songs[0] for that. The first subsong is handled in a special way when loading or saving, other indices work as subsongs normalöly.

Handling channels

Channels are internally handled by using "systems" and "chips", but to access their properties, its more advantageous to treat them as fully independent entities. furnace-module-interface handles this via creating an intermediate object, that processes the properties of channels into convenient objects. This means however, that some properties are not changeable, while others are. To load channels, you can simply do this:

import { loadFurnaceModule, FurnaceInstrumentTypeEnum } from "furnace-module-interface";

const module = await loadFurnaceModule(fileBuffer);

if(module instanceof FurnaceSongModule) {
    const song = module.info.songs[0];
    const channels = song.getChannels(module.info);
}

Handling instruments

Because of compatibility issues, instrument handling is a little weird. You are required to create a "view", that makes it easier to access relevant information about an instrument. You can create any number of views, but modifying one view can affect another. This is particularly a case for OPLL vs other FM instruments. Here is an example:

import { loadFurnaceModule, FurnaceInstrumentTypeEnum } from "furnace-module-interface";

const module = await loadFurnaceModule(fileBuffer);

if(module instanceof FurnaceSongModule) {
    const instrument = module.info.instruments[0];
    const view = instrument.getView(FurnaceInstrumentTypeEnum.OPMOPN);
}

Sample formats

A simple interface for sample conversions are provided. They can be converted between native format and 16-bit signed PCM. This allows easy handling of sample data without having to deal with the format specifics. Here is an example of how you might handle that in your program:

import { loadFurnaceModule, FurnaceInstrumentTypeEnum } from "furnace-module-interface";

const module = await loadFurnaceModule(fileBuffer);

if(module instanceof FurnaceSongModule) {
    const sample = module.info.samples[0];

    const rawSamples = sample.data.convertToArray();
    /**
     * manipulate sample data here!!!
     */
    sample.data.convertFromArray(rawSamples);
}

Accessing raw sample data is not recommended, as it is easier to get it wrong.

Metadata

Module metadata is a furnace-module-interface and is ignored by Furnace. This is not intended to be used to store critical information about modules. Instead, it is a tool that can be used to store information with a module that may be used for any personal purpose. This format is not formally documented yet.

Typings

furnace-module-interface provides full typings for all relevant user-faccing information. Please use Typescript to get the best experience!

Roadmap

furnace-module-interface follows the development of Furnace closely, and will periodically update to support the latest version.

License

This project is licensed under MIT.

Project status

Currently the project is in its very early days and is expected to be unstable and lack features.

Credits

  • Aurora*Fields Main developer of the project
  • tildearrow Main developer of Furnace

Package Sidebar

Install

npm i furnace-module-interface

Weekly Downloads

14

Version

0.5.1

License

MIT

Unpacked Size

170 kB

Total Files

19

Last publish

Collaborators

  • aurora-fields