Skip to content

Latest commit

 

History

History
967 lines (759 loc) · 29.8 KB

README.md

File metadata and controls

967 lines (759 loc) · 29.8 KB

Bassaudio-updated-light

A simple bass library wrapper, maintained and tested. To use, your must download the base library of bass from un4seen website. To uses tag, encoder, or mix add on, you must add it to your project. For a fast startup, with all the bass files included, check out bassaudio-updated

Tested on

macos-latest windows-latest ubuntu-latest

With

npm version npm version npm version npm version

Tests results :

github build status Coverage Status

Documentation :

Examples partials examples features structs callbacks Official documentation

Others :

install size npm downloads npm downloads MIT License

Disclaimer

This package has not been fully tested. Some features may not be fully functionning, if you encounter such a feature, please email me with your traces. I'm still working on it.

Also, I'm not in anyway linked to the bass library. I just like their lib and want it to be accessible to the world of node.

Announcement

The necessaries dll ARE NOT included in this library. You can download them from the un4seen website. You need to add them either in the root folder, or specify the source folder when invoquing

var basslib = new bass();

for example

var basslib = new bass({ basePath: "libFolderName" });

You need the original bass library, and the plugins you want to use, in the same folder.

If you want the necessaries binaries library included, please, check out bassaudio-updated

Do you need more features?

There is two way to use functions that I did not include in this wrapper. Either you send me a mail asking me to officially add it, which I will, either you "patch it" while you use the wrapper as explained here

Un4Seen Bass Audio Library Wrapper

Bass Audio library is the best audio library to play, edit, convert, stream etc. this wrapper wraps most of the "audio playback" features using ffi-napi, ref-napi, ref-struct-di, ref-array-di. It uses os to determines which dynamic library are needed.

ffi-napi enables to call c library methods, properties, callbacks etc.

Compatible with?

Included binaries library files for Windows 64/32bits, Linux 64/32bits, and macOs. Not fully tested yet, so report any encountered issues please.

Note on node 14

There is ongoing issues with node 14.9.0 and later that may cause segfault when loading a library file, that are outside my skills. I strongly discourage you from using node 14.9.0 and later until this problem is stabilized. If you want to find more info about this issue, here is a first lead : node-ffi-napi/node-ffi-napi#99

Documentation

Bass documentation is available here : http://www.un4seen.com/doc/ You can also see this version : http://bass.radio42.com/help/

You can find direct link from wrapped content, to un4seen documentation here

There is also some documentation directly in the README files accompanying the library files on the un4seen website.

Let me now if there is other useful documentation that I can share here. :)

Original library files, bass community, licensing, other apis and more is available here : http://www.un4seen.com.

You can see more code examples from the wrapper original creator, Serkanp, in its git repositories linked here. The example I have build here are fully adapted with my version of the wrapper.

Partials examples

Wrapper parameters

// There is a diversity of parameter accepted by this wrapper, here is a full list of them :

var basslib = getBass({
  basePath: "libFolderName", //facultative if the lib files are in the base folder of the process. If not set, it's process.cwd which is used.
  silent: true, //there is a few console log that may appear to indicate that everything is going smoothly, if you don't want to see it, you can set it to silent
  generatedFfiFunDeclaration: {
    bass: {
      // addon id
      ffiFunDeclaration: {
        BASS_ORIGINAL_FUN_NAME: ["bool", []],
      },
    },
    webm: {
      // addon id
      ffiFunDeclaration: {
        BASS_ORIGINAL_FUN_NAME: [
          // Original name of the bass function
          "int", // return type of the desired function
          ["string", "float", "double", "long", "pointer", "bool"], // Arguments types
        ],
      },
      path: "path/to/lib/file.dylib/dll/so", // A path must be given to the added addon if it's not one already covered by the wrapper. If it is an addon covered, the path would be ignored
    },
  },
});

Arguments types : You must choose the most relevants types for each arguments. You can see a list of correspondances here.

Addon id : Identification of the addon, two choices :

  • Either it's one of the covered ones (bass, tags, encoder, and mixer are already covered) so, by using one of those id, you will add covering for new fun, without losing the ones already managed by the wrapper.

  • Either it's a new addon, for which you can put the name you want. You can put as much diffents addons as you want. Some may have issues, that I did not investigates since I did not test this functionnality with every addon offered with bass, so, don't hesitate to contact me if needed. The name you choose will generate a [Name]Enable() function, as well as a Enabled[Name]() function, as for the ones already covered to activate an addon, and check if it is activated.

basic capture and play microphone

var bass = require("bassaudio-updated");
var basslib = new bass();

var init = basslib.BASS_Init(
  -1,
  44100,
  basslib.BASS_Initflags.BASS_DEVICE_STEREO
);
if (init === false) {
  console.log("error at BASS_Init: " + basslib.BASS_ErrorGetCode());
  process.exit();
} else {
  console.log("Bass initialized");
}

basslib.EnableMixer(true);
var sampleRate = 44100;
var stereoChannel = 2;
var mixer = basslib.BASS_Mixer_StreamCreate(
  sampleRate,
  stereoChannel,
  basslib.BASSFlags.BASS_SAMPLE_FLOAT
);

if (mixer === 0) {
  console.log("error at Mixer_StreamCreate: " + basslib.BASS_ErrorGetCode());
  //   process.exit();
} else {
  console.log("Mixer channel: " + mixer);
}

var init = basslib.BASS_RecordInit(-1); //initialise default microphone
if (!init) {
  console.log("error at BASS_RecordInit: " + basslib.BASS_ErrorGetCode());
  process.exit();
}
var micChan = basslib.BASS_RecordStart(44100, 2, 0, null); // create a recording channel with 10ms period
if (!micChan) {
  console.log("error at BASS_RecordStart: " + basslib.BASS_ErrorGetCode());
  process.exit();
}

var isAdded = basslib.BASS_Mixer_StreamAddChannel(
  mixer,
  micChan,
  basslib.BASSFlags.BASS_STREAM_AUTOFREE | basslib.BASSFlags.BASS_MIXER_LIMIT
);
if (!isAdded) {
  console.log(
    "error adding microphone into mixer: " + basslib.BASS_ErrorGetCode()
  );
  process.exit();
}
// BASS_ChannelPlay
var success = basslib.BASS_ChannelPlay(mixer, true);
if (!success) {
  console.log("error at ChannelPlay: " + basslib.BASS_ErrorGetCode());
  process.exit();
}

basic load and play file

var bass = require("bassaudio-updated");
var basslib = new bass();

//get all sound cards
var cards = basslib.getDevices();
console.log("total found sound cards:" + cards.length);
//lets print first sound card's info, find out more inside source code..
//first item in array '[0]' is "no sound", then use the item [1]
//you will see that card isInitialized will be false, because we did not init it yet..
var card = cards[1];
console.log(
  card.name +
    " is enabled:" +
    card.enabled +
    " ,IsDefault:" +
    card.IsDefault +
    " , IsInitialized:" +
    card.IsInitialized +
    " ,typeSpeakers:" +
    card.typeSpeakers
);

// [device],[freq],[flags], -1 is default sound card
var result = basslib.BASS_Init(
  -1,
  44100,
  basslib.BASS_Initflags.BASS_DEVICE_STEREO
);
if (!result) {
  console.log("error init sound card:" + basslib.BASS_ErrorGetCode());
}

console.log("first card is init?:" + basslib.getDevice(1).IsInitialized);

// isMemoryFile,filename,offset,length,flags, returns pointer of file
var chan = basslib.BASS_StreamCreateFile(0, "c:\\mp3\\test.mp3", 0, 0, 0);
if (basslib.BASS_ErrorGetCode() != basslib.BASS_ErrorCode.BASS_OK) {
  console.log("error opening file:" + basslib.BASS_ErrorGetCode());
}

//lets play
//channel, restart, returns  (also there are stop, pause commands)
var success = basslib.BASS_ChannelPlay(chan, -1);
if (!success) {
  console.log("error playing file:" + basslib.BASS_ErrorGetCode());
}

Get Artist

// get artist or other meta data thanks to the Tags add-on
// This example return the artist name or "No artist" if the artist is not set. But you can doo much more with tags.

basslib.EnableTags(true);

var tagsEnabled = basslib.TagsEnabled();
if (tagsEnabled) {
  console.log("Tags enabled");
} else {
  console.log("Tags disabled");
  process.exit();
}

var artist = basslib.TAGS_Read(
  chan,
  basslib.BASS_TAGS_FORMAT_CONDITION.IF_X_THEN_A_IF_NOT_THEN_B(
    basslib.BASS_TAGS_FORMAT_STRINGS.SONG_ARTIST,
    basslib.BASS_TAGS_FORMAT_STRINGS.SONG_ARTIST,
    "No artist"
  )
);

Get Duration

//get the duration, bass returns the total bytes of the channel pointer, then we must convert it to seconds :)
var durationInBytes = basslib.BASS_ChannelGetLength(chan, 0);
var durationInSeconds = basslib.BASS_ChannelBytes2Seconds(
  chan,
  durationInBytes
);

Get Duration Example2

//if stream is active (playing), then get position and duration..
setInterval(function () {
  if (
    basslib.BASS_ChannelIsActive(chan) ==
    basslib.BASS_ChannelIsActiveAttribs.BASS_ACTIVE_PLAYING
  ) {
    var position = basslib.BASS_ChannelBytes2Seconds(
      chan,
      basslib.BASS_ChannelGetPosition(chan, 0)
    );
    var duration = basslib.BASS_ChannelBytes2Seconds(
      chan,
      basslib.BASS_ChannelGetLength(chan, 0)
    );
    console.log(position + " / " + duration);
  } else {
    console.log("stopped");
  }
}, 500);

Get Volume of channel

var ref = require("ref");
//set a float pointer
var volume = ref.alloc("float");
//get the volume
var result = basslib.BASS_ChannelGetAttribute(
  chan,
  basslib.BASS_ChannelAttributes.BASS_ATTRIB_VOL,
  volume
);
//now deref volume to get the value
console.log(ref.deref(volume));

Set Volume

//lets set to 0.3
basslib.BASS_ChannelSetAttribute(
  chan,
  basslib.BASS_ChannelAttributes.BASS_ATTRIB_VOL,
  0.3
);

Get current Position of playback

var positionInBytes = basslib.BASS_ChannelGetPosition(chan, 0);
//now convert it to seconds
var position = basslib.BASS_ChannelBytes2Seconds(chan, positionInBytes);

Set Position

//first get the byte position of desired seconds (ex:to last 10 seconds
var Last10SecondsBytePos = basslib.BASS_ChannelSeconds2Bytes(
  chan,
  durationInSeconds - 10
);
basslib.BASS_ChannelSetPosition(chan, Last10SecondsBytePos);

Is channel playing?

var result = basslib.BASS_ChannelIsActive(chan);
if (result == basslib.BASS_ChannelIsActiveAttribs.BASS_ACTIVE_PLAYING) {
  console.log("channel is playing");
}

sliding

//Lets slide volume to 0 in 3 seconds (3000 milliseconds)
basslib.BASS_ChannelSlideAttribute(
  chan,
  basslib.BASS_ChannelAttributes.BASS_ATTRIB_VOL,
  0,
  3000
);

callback

//lets make a callback when position reaches to 20. seconds.
var Pos20SecondsBytePos = basslib.BASS_ChannelSeconds2Bytes(chan, 20);
var proc20SecondsID = basslib.BASS_ChannelSetSync(
  chan,
  basslib.BASS_ChannelSyncTypes.BASS_SYNC_POS,
  Pos20SecondsBytePos,
  function (handle, channel, data, user) {
    if (handle == proc20SecondsID) {
      console.log("position reached to the 20 seconds..");
    }
  }
);

//lets get the event when the position reaches to end
var procTOENDID = basslib.BASS_ChannelSetSync(
  chan,
  basslib.BASS_ChannelSyncTypes.BASS_SYNC_END,
  0,
  function (handle, channel, data, user) {
    if (handle == procTOENDID) {
      console.log("playback finished..");
    }
  }
);

Vumeter

//lets get vumeter :)
var levels = basslib.BASS_ChannelGetLevel(chan);
//its a 64 bit value, lets get lo and hiwords
var rightlevel = basslib.toFloat64(levels)[0];
var leftlevel = basslib.toFloat64(levels)[1];

close the file

if (
  basslib.BASS_ChannelIsActive(chan) ==
  basslib.BASS_ChannelIsActiveAttribs.BASS_ACTIVE_PLAYING
) {
  //stop the channel
  basslib.BASS_ChannelStop(chan);
}

var result = basslib.BASS_StreamFree(chan);
if (!result) {
  console.log("stream free error:" + basslib.BASS_ErrorGetCode());
}

change sound card

//first check if this sound card is initialized
var soundCardIndex = 1;
var info = basslib.getDevice(soundCardIndex);
if (!info.enabled) {
  console.log("this device is not enabled");
}
if (!info.IsInitialized) {
  var result = basslib.BASS_Init(
    soundCardIndex,
    44100,
    basslib.BASS_Initflags.BASS_DEVICE_STEREO
  );
  if (result != basslib.BASS_ErrorCode.BASS_OK) {
    console.log("error init sound card:" + basslib.BASS_ErrorGetCode());
  }
}
var success = basslib.BASS_ChannelSetDevice(chan, soundCardIndex);
if (!success) {
  console.log("error init sound card:" + basslib.BASS_ErrorGetCode());
}

Info of a channel

var info = basslib.BASS_ChannelGetInfo(chan);
console.log("info.ctype:" + info.ctype);
console.log(
  "is channel an mp3 stream?:" +
    (info.ctype == basslib.BASS_CHANNELINFOtypes.BASS_CTYPE_STREAM_MP3)
);
//other infos are: freq,chans,flags,ctype,origres,plugin,sample,filename

Info of a device

var info = basslib.getInfo();
console.log("speaker count:" + info.speakers);
console.log("minimum buffer:" + info.minbuf);
console.log("latency:" + info.latency);

Free the memory from bass

basslib.BASS_Free();

MIXER FEATURES

Enable Mixer

//before using mixer, first enable it. and put the required component to root folder.
basslib.EnableMixer(true);

Mixer is Enabled?

//before using mixer, first enable it. and put the required component to root folder.
console.log(basslib.MixerEnabled());

Create mixer stream

basslib.EnableMixer(true);
var mixer = basslib.BASS_Mixer_StreamCreate(
  44100,
  2,
  basslib.BASSFlags.BASS_SAMPLE_FLOAT
);
var chan1 = basslib.BASS_StreamCreateFile(
  0,
  "d:\\mp3\\tes1.mp3",
  0,
  0,
  basslib.BASSFlags.BASS_STREAM_DECODE | basslib.BASSFlags.BASS_SAMPLE_FLOAT
);
var chan2 = basslib.BASS_StreamCreateFile(
  0,
  "d:\\mp3\\test2.mp3",
  0,
  0,
  basslib.BASSFlags.BASS_STREAM_DECODE | basslib.BASSFlags.BASS_SAMPLE_FLOAT
);
var ok1 = basslib.BASS_Mixer_StreamAddChannel(
  mixer,
  chan1,
  basslib.BASSFlags.BASS_SAMPLE_DEFAULT
);
var ok2 = basslib.BASS_Mixer_StreamAddChannel(
  mixer,
  chan2,
  basslib.BASSFlags.BASS_SAMPLE_DEFAULT
);
basslib.BASS_ChannelPlay(mixer, 0);

Get current Position of mixer playback

var positionInBytes = basslib.BASS_Mixer_ChannelGetPosition(chan, 0);
//now convert it to seconds
var position = basslib.BASS_ChannelBytes2Seconds(chan, positionInBytes);

ENCODER FEATURES

In order to be used to its full potential, you need to use an encoder like lame to stream audio to a distant server. Alternatively, bass encode mp3 addon does work the same, and is now availaible with this wrapper. I recommend using it directly. Instead of :

var _encoder = basslib.BASS_Encode_Start(
  mixer,
  `${LAME_PATH}lame -r -m s -s ${SAMPLE_RATE} -b ${BIT_RATE} -`,
  basslib.BASS_Encode_Startflags.BASS_ENCODE_NOHEAD
);

You can now use

var _encoder = basslib.BASS_Encode_MP3_Start(
  mixer,
  ` -r -m s -s ${SAMPLE_RATE} -b ${BIT_RATE} -`,
  basslib.BASS_Encode_Startflags.BASS_ENCODE_NOHEAD
);

Without having to find lame executables by yourself. If you still do prefer to use lame directly, you may find what you want here

you can directly encode and send output to shoutcast and icecast servers

use mixer as a trick, because if the channel freed or added new channel, the encoder stops itself.

add channels to mixer every time, and add mixer channel to encoder, so the encoder never stops.

Init encoder

basslib.EnableMixer(true);
var mixer = basslib.BASS_Mixer_StreamCreate(
  44100,
  2,
  basslib.BASSFlags.BASS_SAMPLE_FLOAT
);
var chan = basslib.BASS_StreamCreateFile(
  0,
  "d:\\mp3\\tes1.mp3",
  0,
  0,
  basslib.BASSFlags.BASS_STREAM_DECODE | basslib.BASSFlags.BASS_SAMPLE_FLOAT
);
var ok = basslib.BASS_Mixer_StreamAddChannel(
  mixer,
  chan,
  basslib.BASSFlags.BASS_SAMPLE_DEFAULT
);

basslib.EnableEncoder(true);

//lets try icecast
var enc_chan = basslib.BASS_Encode_Start(
  mixer,
  "lame -r -m s -s 22050 -b 56 -",
  basslib.BASS_Encode_Startflags.BASS_ENCODE_NOHEAD
);
var result = basslib.BASS_Encode_CastInit(
  enc_chan,
  "http://server-ip:8000/test",
  "password",
  basslib.BASS_Encode_CastInitcontentMIMEtypes.BASS_ENCODE_TYPE_MP3,
  "test stream",
  "http://your-server-ip",
  "pop",
  "this is my new icecast test",
  "header1\r\nheader2\r\n",
  44100,
  true //public
);

basslib.BASS_ChannelPlay(mixer, 0);

get notification from encoder server

var result=basslib.BASS_Encode_SetNotify(enc_chan,function(handle,status,user){
  if(status==basslib.EncoderNotifyStatus.BASS_ENCODE_NOTIFY_CAST){
  console.log('server connection is dead');
});

mono speaker output

//lets say if you have 5.1 speaker and want to use each output stereo or mono
//basically with 5.1 output you can use 6 different output channels.
//this example shows how to do it
var bass = require("bassaudio-updated");
var basslib = new bass();

//set init to speakers
var result = basslib.BASS_Init(
  -1,
  44100,
  basslib.BASS_Initflags.BASS_DEVICE_SPEAKERS
);
if (!result) {
  console.log("error init sound card:" + basslib.BASS_ErrorGetCode());
}

//to use mixer feature, you have to enable it
basslib.EnableMixer(true);

var cards = basslib.getDevices();
var speakerCount = basslib.getInfo().speakers;
console.log("we have", speakerCount, "speakers");
var path = require("path");
var f1 = path.join(__dirname, "1.mp3");

//create a mixer and tell it to output front right
var mixer = basslib.BASS_Mixer_StreamCreate(
  44100,
  1,
  basslib.BASS_SPEAKERtypes.BASS_SPEAKER_FRONTRIGHT
);
console.log("mixer:", mixer, " error code:", basslib.BASS_ErrorGetCode());

//set channel to decode
var chan1 = basslib.BASS_StreamCreateFile(
  0,
  f1,
  0,
  0,
  basslib.BASSFlags.BASS_STREAM_DECODE
);

//if your file is stereo, you have to downmix to mono, else you cannot get it mono output to only 1 speaker.
var ok1 = basslib.BASS_Mixer_StreamAddChannel(
  mixer,
  chan1,
  basslib.BASS_MIXERsourceflags.BASS_MIXER_DOWNMIX
);
var ok2 = basslib.BASS_ChannelPlay(mixer, 0);

console.log("chan1:", chan1, " error code:", basslib.BASS_ErrorGetCode());
console.log("ok1:", ok1, " error code:", basslib.BASS_ErrorGetCode());

setInterval(() => {}, 1000);

splitting channels

//if you want to add a mixer to another mixer, it is not possible/supported
//but there is another way to do it.
//you can split any channel or mixer into two, then you can use the new splitted channel on any other mixer.
//A "splitter" basically does the opposite of a mixer: it splits a single source into multiple streams rather then mixing multiple sources into a single stream. Like mixer sources, splitter sources must be decoding channels.

var splitChan = basslib.BASS_Split_StreamCreate(mixer, 0);
var splits = basslib.BASS_Split_StreamGetSplits(mixer);
var splitsource = basslib.BASS_Split_StreamGetSource(splitChan);
var avail1 = basslib.BASS_Split_StreamGetAvailable(splitChan);
var avail2 = basslib.BASS_Split_StreamGetAvailable(mixer);

UPDATE LOG

--------------2.X.X------------------

  • 2.1.0

    • Allowing special heritage function to be able to function as they used too from Serkan's work
    • Adding getCodeMessageFrom to translate an error/flag code to the string, for human readability.
    • Adding "EnableAllAvailable" to activate in all call any lib that may have been set naturally, or added on the run.
    • Adding "AreAllAvailableEnabled" to check if all lib available have been set, and send back the one that are not activated
    • Adding support for bass encode MP3
    • Adding what was needed to support new lib files dependant on other. If you add support for new lib files, order might be important.
  • 2.0.0

    Complete rebuilding of the wrapper to be easier to test, to evolve, and to suit the needs of everyone.

    • Adding examples
    • Adding tests
    • Adding coverage
    • Adding documentation
    • Leaving out the features lists of Readme to allow to automatise it's content
    • Changing dependencies to ref-struct-di, ref-array-di because ref-napi version that can differe in ref-array-napi and ref-struct-napi from ffi-napi.
    • Allowing to load non covered addons by adding the proper parameter in the constructor call of the lib. See how to do so in the test here. Adding fun works on any platform, but, in order to add support for new library file for mac, all the dylib must be in the same folder.

--------------1.X.X------------------

  • 1.0.8-1.3.5

    Updating BASS_ChannelAttributes to add missing values

  • 1.0.8-1.3.4

    ffi code correction done

  • 1.0.8-1.3.3

    Fixing ffi version until code correction

  • 1.0.8-1.3.2

    Important fix (linux) in shim

  • 1.0.8-1.3.1

    Important fix in variable name

  • 1.0.8-1.3.0

    new features added:

    • TAGS_GetVersion
    • TAGS_Read
    • TAGS_ReadEx
    • TAGS_SetUTF8
    • TAGS_GetLastErrorDesc
  • 1.0.8-1.2.0

    new features added:

    • BASS_StreamCreate
    • BASS_RecordFree
    • BASS_RecordGetDevice
    • BASS_RecordGetDeviceInfo
    • BASS_RecordGetInfo
    • BASS_RecordGetInput
    • BASS_RecordGetInputName
    • BASS_RecordInit
    • BASS_RecordSetDevice
    • BASS_RecordSetInput
    • BASS_RecordStart

    features corrected:

    • BASS_Mixer_ChannelSetSync
  • 1.0.8-1.1.0 news:

    • spliting version with and without library files.
    • Correcting call to BASS_Encode_IsActive
  • 1.0.8-1.0.2 news:

    • adding repo link into package.json
  • 1.0.8-1.0.1 news:

    • Forgot to fully update package references in readme, and correcting package.json too.
  • 1.0.8-1.0.0 news:

-----BEFORE FORK-UPDATE LOG-----

  • 1.0.8

    new features added:

    • BASS_Split_StreamCreate

    • BASS_Split_StreamGetAvailable

    • BASS_Split_StreamGetSource

    • BASS_Split_StreamGetSplits

    • BASS_Split_StreamReset

    • BASS_Split_StreamResetEx

  • 1.0.7

    • BASS_SetConfigflags, BASS_SetConfig, BASS_GetConfig, BASS_Update, BASS_ChannelUpdate features added
  • 1.0.6

    • correct an arg type in BASS_Encode_CastInit handler
  • 1.0.5

    • lock installed "ffi" version
    • add shim to automate the changes to the "ffi" source code
  • 1.0.4

    • BASS_Encode_CastSetTitle has a minor bug. fixed.
  • 1.0.3

    • constructor now accepts and options object
    • examples folder comes with link files
  • 1.0.2

    • getVolume() gives ref error when channel is 0. fixed.
  • 1.0.1

    • some types fixed for raspberrypi compability.
    • examples folder added
    • mono speaker out example added
  • 1.0.0 Release

    • i hope i fixed everything :) lets cross the fingers..
  • 1.0.0-rc.22

    • some types in BASS_StreamCreateFile are changed to ref.types.int64
  • 1.0.0-rc.21

    • these fixes are for linux environment
    • fixed BASS_ChannelBytes2Seconds
    • fixed BASS_ChannelSeconds2Bytes
    • fixed BASS_ChannelSetPosition
  • 1.0.0-rc.20

    • added BASS_MIXERsourceflags
    • found a bug on ffi source code, see above change for linux os..
  • 1.0.0-rc.18

    • BASS_ChannelGetAttribute returns float pointer. fixed.see getvolume example for usage.
    • BASS_GETInfo now works.
  • 1.0.0-rc.17

    • BASS_Encode_IsActive fixed
  • 1.0.0-rc.16

    • getDevice(-1) must find the default sound card and return it.
    • BASS_GetDevice takes 1 argument, but missing in code. fixed.
  • 1.0.0-rc.15

    • documentation fix
  • 1.0.0-rc.14

    • documentation fix
  • 1.0.0-rc.13

    • new mixer features:

      • BASS_Mixer_StreamCreate
      • BASS_Mixer_StreamAddChannel
      • BASS_Mixer_ChannelGetLevel
      • BASS_Mixer_ChannelGetMixer
      • BASS_Mixer_ChannelGetPosition
      • BASS_Mixer_ChannelRemove
      • BASS_Mixer_ChannelRemoveSync
      • BASS_Mixer_ChannelSetPosition
      • BASS_Mixer_ChannelSetSync
    • new encoder features:

      • BASS_Encode_Start
      • BASS_Encode_IsActive
      • BASS_Encode_SetNotify
      • BASS_Encode_SetPaused
      • BASS_Encode_Stop
      • BASS_Encode_CastInit
      • BASS_Encode_CastGetStats
      • BASS_Encode_CastSetTitle
  • 1.0.0-rc.12

    • BASS_ChannelBytes2Seconds and BASS_ChannelSeconds2Bytes returns wrong on arm cpu. pos value type changed to int64. now works correctly