diff --git a/Bin/x86_64-linux/bs2bconvert b/Bin/x86_64-linux/bs2bconvert
new file mode 100755
index 0000000..dc74978
Binary files /dev/null and b/Bin/x86_64-linux/bs2bconvert differ
diff --git a/HTML/EN/plugins/BS2B/settings/player.html b/HTML/EN/plugins/BS2B/settings/player.html
new file mode 100644
index 0000000..655afd7
--- /dev/null
+++ b/HTML/EN/plugins/BS2B/settings/player.html
@@ -0,0 +1,12 @@
+[% PROCESS settings/header.html %]
+
+[% WRAPPER settingSection %]
+
+ [% WRAPPER setting title="Enable BS2B" desc="" %]
+
+
+ [% END %]
+
+[% END %]
+
+[% PROCESS settings/footer.html %]
diff --git a/PlayerSettings.pm b/PlayerSettings.pm
new file mode 100644
index 0000000..446e1e1
--- /dev/null
+++ b/PlayerSettings.pm
@@ -0,0 +1,47 @@
+package Plugins::BS2B::PlayerSettings;
+
+use strict;
+
+use base qw(Slim::Web::Settings);
+
+use Slim::Utils::Prefs;
+use Slim::Utils::Log;
+use Slim::Player::CapabilitiesHelper;
+
+use Plugins::BS2B::Plugin;
+
+my $prefs = preferences('plugin.bs2b');
+my $log = logger('plugin.bs2b');
+
+sub getDisplayName {
+ return 'PLUGIN_BS2B';
+}
+
+sub needsClient {
+ return 1;
+}
+
+sub name {
+ return Slim::Web::HTTP::CSRF->protectName('PLUGIN_BS2B');
+}
+
+sub page {
+ return Slim::Web::HTTP::CSRF->protectURI('plugins/BS2B/settings/player.html');
+}
+
+sub handler {
+ my ($class, $client, $params, $callback, @args) = @_;
+
+ if ($params->{'saveSettings'}) {
+
+ $prefs->client($client)->set('bs2b', $params->{'pref_bs2b'} || 0);
+
+ Plugins::BS2B::Plugin::setupTranscoder($client);
+ }
+
+ $params->{'prefs'}->{'pref_bs2b'}= $prefs->client($client)->get('bs2b') || 0;
+
+ return $class->SUPER::handler($client, $params);
+}
+
+1;
diff --git a/Plugin.pm b/Plugin.pm
new file mode 100644
index 0000000..e8fe5aa
--- /dev/null
+++ b/Plugin.pm
@@ -0,0 +1,59 @@
+package Plugins::BS2B::Plugin;
+
+use strict;
+
+use base qw(Slim::Plugin::OPMLBased);
+
+use Slim::Utils::Log;
+use Slim::Utils::Prefs;
+use Slim::Player::TranscodingHelper;
+
+use Plugins::BS2B::PlayerSettings;
+
+my $prefs = preferences('plugin.bs2b');
+
+my $log = Slim::Utils::Log->addLogCategory({
+ 'category' => 'plugin.bs2b',
+ 'defaultLevel' => 'WARN',
+ 'description' => 'PLUGIN_BS2B',
+});
+
+sub initPlugin {
+ my $class = shift;
+
+ Plugins::BS2B::PlayerSettings->new;
+
+ Slim::Control::Request::subscribe(\&initClient, [['client'],['new','reconnect']]);
+}
+
+sub setupTranscoder {
+ my $client = $_[0] || return;
+
+ my $usebs2b = $prefs->client($client)->get('bs2b');
+
+ my $flc = 'flc-flc-*-' . lc($client->macaddress);
+
+ if ($usebs2b) {
+
+ # AU is specifically designed to be written to a pipe (http://www.mega-nerd.com/libsndfile/FAQ.html#Q017)
+ my $cmdTable = '[sox] -q -t flac $FILE$ -t au - $START$ | [bs2bconvert] /dev/stdin /dev/stdout | [sox] -q -t au - -t flac -C 0 -';
+ my $capabilities = { F => 'noArgs', T => 'START=trim %s' };
+
+ $Slim::Player::TranscodingHelper::commandTable{ $flc } = $cmdTable;
+ $Slim::Player::TranscodingHelper::capabilities{ $flc } = $capabilities;
+
+ } else {
+
+ $Slim::Player::TranscodingHelper::commandTable{ $flc } = "-";
+ $Slim::Player::TranscodingHelper::capabilities{ $flc } = {};
+
+ }
+}
+
+sub initClient {
+ my $request = shift;
+
+ setupTranscoder($request->client());
+}
+
+1;
diff --git a/install.xml b/install.xml
new file mode 100644
index 0000000..aa7bdb5
--- /dev/null
+++ b/install.xml
@@ -0,0 +1,17 @@
+
+
+ PLUGIN_BS2B
+ Plugins::BS2B::Plugin
+ 0.01
+ PLUGIN_BS2B_DESC
+ Terual
+ https://github.com/terual/BS2B
+ enabled
+ 2
+
+
+ SlimServer
+ 7.9
+ 8.*
+
+
diff --git a/src/Dockerfile b/src/Dockerfile
new file mode 100644
index 0000000..a4d9d85
--- /dev/null
+++ b/src/Dockerfile
@@ -0,0 +1,6 @@
+FROM ubuntu:14.04
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN apt-get -y update && apt-get -y upgrade && \
+ apt-get install -y gcc g++ make libsndfile-dev build-essential
+
diff --git a/src/build.sh b/src/build.sh
new file mode 100755
index 0000000..2fff56c
--- /dev/null
+++ b/src/build.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+docker build . -t bs2b
+
+rm -rf "libbs2b-3.1.0"
+tar -xvf "libbs2b-3.1.0.tar.bz2"
+patch -p0 < fix-stderr.patch
+
+cd "libbs2b-3.1.0"
+docker run -t --rm -u "${UID}" -v "${PWD}:${PWD}" -w "${PWD}" \
+ bs2b \
+ sh -c "./configure --help && LIBS=-lm ./configure --enable-static --disable-shared && make"
+
+
diff --git a/src/fix-stderr.patch b/src/fix-stderr.patch
new file mode 100644
index 0000000..aab3639
--- /dev/null
+++ b/src/fix-stderr.patch
@@ -0,0 +1,76 @@
+--- libbs2b-3.1.0/src/bs2bconvert.c.orig 2009-06-04 20:01:15.000000000 +0200
++++ libbs2b-3.1.0/src/bs2bconvert.c 2020-10-05 15:00:34.332595456 +0200
+@@ -146,20 +146,20 @@
+
+ if( strcmp( infilename, outfilename ) == 0 )
+ {
+- printf( "Error : Input and output filenames are the same.\n\n" );
++ fprintf( stderr, "Error : Input and output filenames are the same.\n\n" );
+ return 1;
+ }
+
+ if( ( infile = sf_open( infilename, SFM_READ, &sfinfo ) ) == NULL )
+ {
+- printf( "Not able to open input file %s.\n", infilename );
+- printf( sf_strerror( NULL ) );
++ fprintf( stderr, "Not able to open input file %s.\n", infilename );
++ fprintf( stderr, sf_strerror( NULL ) );
+ return 1;
+ }
+
+ if( sfinfo.channels != 2 )
+ {
+- printf( "Input file is not a stereo.\n" );
++ fprintf( stderr, "Input file is not a stereo.\n" );
+ sf_close( infile );
+ return 1;
+ }
+@@ -168,7 +168,7 @@
+
+ if( srate < BS2B_MINSRATE || srate > BS2B_MAXSRATE )
+ {
+- printf( "Not supported sample rate '%d'.\n", srate );
++ fprintf( stderr, "Not supported sample rate '%d'.\n", srate );
+ sf_close( infile );
+ return 1;
+ }
+@@ -176,7 +176,7 @@
+ /* Open the output file. */
+ if( ( outfile = sf_open( outfilename, SFM_WRITE, &sfinfo ) ) == NULL )
+ {
+- printf( "Not able to open output file %s : %s\n",
++ fprintf( stderr, "Not able to open output file %s : %s\n",
+ outfilename, sf_strerror( NULL ) );
+ sf_close( infile );
+ return 1;
+@@ -184,7 +184,7 @@
+
+ if( NULL == ( bs2bdp = bs2b_open() ) )
+ {
+- printf( "Not able to allocate data\n" );
++ fprintf( stderr, "Not able to allocate data\n" );
+ sf_close( infile );
+ sf_close( outfile );
+ return 1;
+@@ -193,10 +193,10 @@
+ bs2b_set_srate( bs2bdp, srate );
+ bs2b_set_level( bs2bdp, level );
+
+- printf( "Crossfeed level: %.1f dB, %d Hz, %d us.\n",
++ fprintf( stderr, "Crossfeed level: %.1f dB, %d Hz, %d us.\n",
+ ( double )bs2b_get_level_feed( bs2bdp ) / 10.0,
+ bs2b_get_level_fcut( bs2bdp ), bs2b_get_level_delay( bs2bdp ) );
+- printf( "Converting file '%s' to file '%s'\nsample rate = %u...",
++ fprintf( stderr, "Converting file '%s' to file '%s'\nsample rate = %u...",
+ infilename, outfilename, bs2b_get_srate( bs2bdp ) );
+
+ copy_metadata( outfile, infile );
+@@ -209,7 +209,7 @@
+ sf_close( infile );
+ sf_close( outfile );
+
+- printf( " Done.\n" );
++ fprintf( stderr, " Done.\n" );
+
+ return 0;
+ } /* main() */
diff --git a/src/libbs2b-3.1.0.tar.bz2 b/src/libbs2b-3.1.0.tar.bz2
new file mode 100644
index 0000000..6e0e5bb
Binary files /dev/null and b/src/libbs2b-3.1.0.tar.bz2 differ
diff --git a/strings.txt b/strings.txt
new file mode 100644
index 0000000..f856232
--- /dev/null
+++ b/strings.txt
@@ -0,0 +1,10 @@
+# String file for BS2B plugin
+
+PLUGIN_BS2B
+ EN Bauer stereophonic-to-binaural DSP
+
+PLUGIN_BS2B_DESC
+ EN Bauer stereophonic-to-binaural DSP: headphone filter
+
+PLUGIN_BS2B_ENABLE
+ EN Enable Bauer stereophonic-to-binaural DSP for this player