Delete non-essential files
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,5 +0,0 @@
|
|||||||
/bin
|
|
||||||
/.settings
|
|
||||||
/sound
|
|
||||||
.classpath
|
|
||||||
.project
|
|
||||||
31
build.gradle
31
build.gradle
@@ -1,31 +0,0 @@
|
|||||||
apply plugin: 'java'
|
|
||||||
apply plugin: 'maven'
|
|
||||||
apply plugin: 'eclipse'
|
|
||||||
|
|
||||||
task wrapper(type: Wrapper) {
|
|
||||||
gradleVersion = '2.14'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile 'com.github.boukefalos:jlibpipe:0.1'
|
|
||||||
compile 'com.github.boukefalos:jlibloader:0.2'
|
|
||||||
|
|
||||||
compile 'commons-io:commons-io:2.+'
|
|
||||||
compile 'commons-cli:commons-cli:1.+'
|
|
||||||
compile 'commons-pool:commons-pool:1.+'
|
|
||||||
compile 'org.slf4j:slf4j-api:1.+'
|
|
||||||
compile 'org.slf4j:slf4j-log4j12:1.7.5'
|
|
||||||
compile 'org.ostermiller:utils:1.+'
|
|
||||||
compile 'com.googlecode.soundlibs:jlayer:1.+'
|
|
||||||
compile 'net.sf.javamusictag:jid3lib:0.+'
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url 'https://github.com/Boukefalos/mimis/raw/mvn-repo/'
|
|
||||||
}
|
|
||||||
maven {
|
|
||||||
url 'https://github.com/Boukefalos/jlibloader/raw/mvn-repo/'
|
|
||||||
}
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +0,0 @@
|
|||||||
#Mon Jul 11 23:15:35 BST 2016
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
|
|
||||||
164
gradlew
vendored
164
gradlew
vendored
@@ -1,164 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS=""
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn ( ) {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die ( ) {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
|
||||||
function splitJvmOpts() {
|
|
||||||
JVM_OPTS=("$@")
|
|
||||||
}
|
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
|
||||||
90
gradlew.bat
vendored
90
gradlew.bat
vendored
@@ -1,90 +0,0 @@
|
|||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS=
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package old;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import javazoom.jl.decoder.Bitstream;
|
|
||||||
import javazoom.jl.decoder.BitstreamException;
|
|
||||||
import sound.util.Utils;
|
|
||||||
import base.exception.worker.ActivateException;
|
|
||||||
import base.exception.worker.DeactivateException;
|
|
||||||
import base.work.Work;
|
|
||||||
|
|
||||||
import com.Ostermiller.util.CircularByteBuffer;
|
|
||||||
|
|
||||||
public class Converter extends Work {
|
|
||||||
public static final String COMMAND = "lame --mp3input --cbr %s - - --quiet";
|
|
||||||
public static final int BYTES = 4096; // bytes
|
|
||||||
public static final int BUFFER = 30000; // milliseconds
|
|
||||||
public static final int BUFFERING = 1000; // milliseconds
|
|
||||||
|
|
||||||
protected int targetRate;
|
|
||||||
protected int rate;
|
|
||||||
protected int buffer;
|
|
||||||
protected boolean convert;
|
|
||||||
|
|
||||||
protected Process process;
|
|
||||||
protected InputStream sourceInputStream, processInputStream, inputStream;
|
|
||||||
protected OutputStream processOutputStream;
|
|
||||||
protected CircularByteBuffer circularByteBuffer;
|
|
||||||
protected BufferWorker bufferWorker;
|
|
||||||
|
|
||||||
public Converter(InputStream inputStream) {
|
|
||||||
this(inputStream, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Converter(InputStream inputStream, int targetRate) {
|
|
||||||
super();
|
|
||||||
this.sourceInputStream = inputStream;
|
|
||||||
this.targetRate = targetRate;
|
|
||||||
bufferWorker = new BufferWorker();
|
|
||||||
convert = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
super.exit();
|
|
||||||
bufferWorker.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void activate() throws ActivateException {
|
|
||||||
/* Read bitrate */
|
|
||||||
BufferedInputStream bufferedInputStream = new BufferedInputStream(sourceInputStream);
|
|
||||||
Bitstream bitStream = new Bitstream(bufferedInputStream);
|
|
||||||
try {
|
|
||||||
rate = bitStream.readFrame().bitrate() / 1000;
|
|
||||||
buffer = BUFFER * rate / 8;
|
|
||||||
} catch (BitstreamException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for need to convert */
|
|
||||||
if (targetRate < 0 || rate == targetRate) {
|
|
||||||
logger.debug("No conversion required");
|
|
||||||
inputStream = sourceInputStream;
|
|
||||||
} else {
|
|
||||||
logger.debug("Converting from " + rate + "kbps to " + targetRate + "kbps");
|
|
||||||
try {
|
|
||||||
String command = String.format(COMMAND, rate > targetRate ? "-B " + targetRate : "-F -b " + targetRate);
|
|
||||||
logger.debug("Starting process: " + command);
|
|
||||||
process = Runtime.getRuntime().exec(command);
|
|
||||||
processInputStream = process.getInputStream();
|
|
||||||
processOutputStream = process.getOutputStream();
|
|
||||||
|
|
||||||
/* Buffer output */
|
|
||||||
circularByteBuffer = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
|
|
||||||
inputStream = circularByteBuffer.getInputStream();
|
|
||||||
bufferWorker.start();
|
|
||||||
convert = true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.activate();
|
|
||||||
notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() throws DeactivateException {
|
|
||||||
super.deactivate();
|
|
||||||
try {
|
|
||||||
sourceInputStream.close();
|
|
||||||
bufferWorker.stop();
|
|
||||||
if (convert) {
|
|
||||||
circularByteBuffer.clear();
|
|
||||||
convert = false;
|
|
||||||
}
|
|
||||||
inputStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new DeactivateException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void work() {
|
|
||||||
if (!convert) {
|
|
||||||
try {
|
|
||||||
synchronized (this) {
|
|
||||||
wait();
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
byte[] bytes = new byte[BYTES];
|
|
||||||
int read = 0;
|
|
||||||
try {
|
|
||||||
logger.debug("Writing input to process");
|
|
||||||
// Should be interrupted by stop()/exit()
|
|
||||||
while ((read = sourceInputStream.read(bytes)) > 0) {
|
|
||||||
/* Limit buffer size */
|
|
||||||
while (inputStream.available() > buffer) {
|
|
||||||
int progress = (int) ((1 - (inputStream.available() - buffer) / (float) buffer) * 100);
|
|
||||||
logger.trace("Waiting for buffer to empty: " + progress + "%");
|
|
||||||
sleep(BUFFERING);
|
|
||||||
}
|
|
||||||
processOutputStream.write(bytes, 0, read);
|
|
||||||
}
|
|
||||||
processOutputStream.close();
|
|
||||||
logger.debug("Stopped writing input to process");
|
|
||||||
process.waitFor();
|
|
||||||
logger.debug("Process finished");
|
|
||||||
} catch (IOException e) {
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized InputStream getInputStream() {
|
|
||||||
if (!active()) {
|
|
||||||
start();
|
|
||||||
try {
|
|
||||||
wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return inputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void setInputStream(InputStream inputStream) {
|
|
||||||
this.inputStream = inputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
class BufferWorker extends Work {
|
|
||||||
public void work() {
|
|
||||||
byte[] bytes = new byte[BYTES];
|
|
||||||
int read = 0;
|
|
||||||
try {
|
|
||||||
OutputStream bufferOutputStream = circularByteBuffer.getOutputStream();
|
|
||||||
logger.debug("Start buffering process output");
|
|
||||||
while ((read = processInputStream.read(bytes, 0, BYTES)) > 0) {
|
|
||||||
bufferOutputStream.write(bytes, 0, read);
|
|
||||||
}
|
|
||||||
logger.debug("Finished buffering process output");
|
|
||||||
bufferOutputStream.close();
|
|
||||||
} catch (IOException e) {}
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Mp3 mp3 = new Mp3(new File("stream.mp3"), 128);
|
|
||||||
InputStream inputStream = mp3.getInputStream();
|
|
||||||
|
|
||||||
/* Play */
|
|
||||||
//Utils.play(inputStream);
|
|
||||||
|
|
||||||
/* Write to file */
|
|
||||||
Utils.write(inputStream, new File("output.mp3"));
|
|
||||||
mp3.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package old;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
import sound.consumer.Shoutcast;
|
|
||||||
import base.exception.worker.ActivateException;
|
|
||||||
import base.work.Work;
|
|
||||||
|
|
||||||
import com.Ostermiller.util.BufferOverflowException;
|
|
||||||
import com.Ostermiller.util.CircularByteBuffer;
|
|
||||||
import com.Ostermiller.util.CircularObjectBuffer;
|
|
||||||
|
|
||||||
public class List extends Work {
|
|
||||||
public static final int STEP = 80; // milliseconds
|
|
||||||
public static final int RATE = 192; // kbps
|
|
||||||
public static final int OVERLAP = 20000; // milliseconds
|
|
||||||
|
|
||||||
protected File file;
|
|
||||||
protected String[] fileArray;
|
|
||||||
|
|
||||||
protected int rate;
|
|
||||||
protected int chunk;
|
|
||||||
protected int overlap;
|
|
||||||
protected byte[] bytes;
|
|
||||||
protected boolean next;
|
|
||||||
protected Mp3 mp3, nextMp3;
|
|
||||||
|
|
||||||
protected InputStream mp3InputStream;
|
|
||||||
protected OutputStream audioOutputStream;
|
|
||||||
protected CircularByteBuffer circularByteBuffer;
|
|
||||||
protected CircularObjectBuffer<String> circularStringBuffer;
|
|
||||||
|
|
||||||
public List(File file) {
|
|
||||||
this(file, RATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List(File file, int rate) {
|
|
||||||
this.file = file;
|
|
||||||
this.rate = rate;
|
|
||||||
chunk = STEP * rate / 8;
|
|
||||||
overlap = OVERLAP * RATE / 8;
|
|
||||||
bytes = new byte[chunk];
|
|
||||||
next = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
super.exit();
|
|
||||||
if (mp3 != null) {
|
|
||||||
mp3.exit();
|
|
||||||
}
|
|
||||||
if (nextMp3 != null) {
|
|
||||||
nextMp3.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void activate() throws ActivateException {
|
|
||||||
try {
|
|
||||||
Scanner scanner = new Scanner(file);
|
|
||||||
ArrayList<String> fileList = new ArrayList<String>();
|
|
||||||
while (scanner.hasNextLine()) {
|
|
||||||
fileList.add(scanner.nextLine());
|
|
||||||
}
|
|
||||||
scanner.close();
|
|
||||||
if (fileList.size() > 0) {
|
|
||||||
fileArray = fileList.toArray(new String[0]);
|
|
||||||
|
|
||||||
circularByteBuffer = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
|
|
||||||
audioOutputStream = circularByteBuffer.getOutputStream();
|
|
||||||
|
|
||||||
circularStringBuffer = new CircularObjectBuffer<String>(CircularByteBuffer.INFINITE_SIZE);
|
|
||||||
setNext();
|
|
||||||
super.activate();
|
|
||||||
notifyAll();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void work() {
|
|
||||||
try {
|
|
||||||
int left = chunk;
|
|
||||||
while (left > 0) {
|
|
||||||
/* Check for need to load next mp3 */
|
|
||||||
int available = mp3InputStream == null ? -1 : mp3InputStream.available();
|
|
||||||
boolean expect = mp3 == null ? false : mp3.active();
|
|
||||||
|
|
||||||
/* Act when no more data is expected */
|
|
||||||
if (!expect) {
|
|
||||||
if (available < overlap) {
|
|
||||||
setNext();
|
|
||||||
next = false;
|
|
||||||
nextMp3.start();
|
|
||||||
}
|
|
||||||
if (available < 1) {
|
|
||||||
swap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transfer data */
|
|
||||||
int read = mp3InputStream.read(bytes, 0, left);
|
|
||||||
left -= read;
|
|
||||||
audioOutputStream.write(bytes, 0, read);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
/* Swap to next if stream has stopped */
|
|
||||||
setNext();
|
|
||||||
swap();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
sleep(STEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected File getRandomFile() {
|
|
||||||
return new File(fileArray[(int) (Math.random() * fileArray.length)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void setNext() {
|
|
||||||
if (nextMp3 == null) {
|
|
||||||
logger.debug("Initialize next mp3");
|
|
||||||
nextMp3 = new Mp3(getRandomFile(), rate);
|
|
||||||
} else if (next) {
|
|
||||||
logger.debug("Load next mp3");
|
|
||||||
nextMp3.setFile(getRandomFile());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void next() {
|
|
||||||
logger.debug("Stop current mp3");
|
|
||||||
mp3.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void swap() {
|
|
||||||
logger.debug("Swap to next mp3");
|
|
||||||
Mp3 swapMp3 = mp3;
|
|
||||||
mp3 = nextMp3;
|
|
||||||
nextMp3 = swapMp3;
|
|
||||||
next = true;
|
|
||||||
|
|
||||||
/* Swap stream and announce title */
|
|
||||||
mp3InputStream = mp3.getInputStream();
|
|
||||||
try {
|
|
||||||
circularStringBuffer.write(mp3.getTitle());
|
|
||||||
} catch (BufferOverflowException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized InputStream getInputStream() {
|
|
||||||
if (circularByteBuffer == null) {
|
|
||||||
start();
|
|
||||||
try {
|
|
||||||
wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return circularByteBuffer.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized CircularObjectBuffer<String> getMetaBuffer() {
|
|
||||||
if (circularStringBuffer == null) {
|
|
||||||
start();
|
|
||||||
try {
|
|
||||||
wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return circularStringBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
int rate = 192;
|
|
||||||
List list = new List(new File(List.class.getClassLoader().getResource("txt/mp3").toURI()), rate);
|
|
||||||
Shoutcast shoutcast = new Shoutcast(rate, 9876);
|
|
||||||
|
|
||||||
shoutcast.setInputStream(list.getInputStream());
|
|
||||||
shoutcast.setMetaBuffer(list.getMetaBuffer());
|
|
||||||
shoutcast.start();
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(15000);
|
|
||||||
list.next();
|
|
||||||
} catch (InterruptedException e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package old;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.farng.mp3.MP3File;
|
|
||||||
import org.farng.mp3.TagException;
|
|
||||||
|
|
||||||
import sound.util.Utils;
|
|
||||||
import base.exception.worker.ActivateException;
|
|
||||||
|
|
||||||
public class Mp3 extends Converter {
|
|
||||||
protected File file;
|
|
||||||
protected String title;
|
|
||||||
|
|
||||||
public Mp3(File file) {
|
|
||||||
this(file, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mp3(File file, int targetRate) {
|
|
||||||
super(null, targetRate);
|
|
||||||
setFile(file);
|
|
||||||
title = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void activate() throws ActivateException {
|
|
||||||
/* Open file */
|
|
||||||
try {
|
|
||||||
sourceInputStream = new FileInputStream(file);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read ID3V2 tags */
|
|
||||||
try {
|
|
||||||
MP3File mp3File = new MP3File(file);
|
|
||||||
String album = clean(mp3File.getID3v2Tag().getAlbumTitle());
|
|
||||||
String artist = clean(mp3File.getID3v2Tag().getLeadArtist());
|
|
||||||
String track = clean(mp3File.getID3v2Tag().getSongTitle());
|
|
||||||
if (album.isEmpty()) {
|
|
||||||
title = String.format("%s - %s", artist, track, album);
|
|
||||||
} else {
|
|
||||||
title = String.format("%s - %s {%s}", artist, track, album);
|
|
||||||
}
|
|
||||||
logger.debug("Title: " + title);
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
} catch (TagException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
sourceInputStream.skip(100000);
|
|
||||||
} catch (IOException e) {}
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String clean(String input) {
|
|
||||||
String output = input.replace("\0", "");
|
|
||||||
return output.replace("<EFBFBD><EFBFBD>", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFile(File file) {
|
|
||||||
this.file = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final Mp3 mp3 = new Mp3(new File("input.mp3"), 128);
|
|
||||||
Utils.write(mp3.getInputStream(), new File("one.mp3"));
|
|
||||||
mp3.setFile(new File("stream.mp3"));
|
|
||||||
Utils.write(mp3.getInputStream(), new File("two.mp3"));
|
|
||||||
mp3.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package old;
|
|
||||||
|
|
||||||
import sound.Consumer;
|
|
||||||
import sound.Producer;
|
|
||||||
|
|
||||||
public abstract class Transducer implements Consumer, Producer {
|
|
||||||
public int rate;
|
|
||||||
|
|
||||||
public Transducer(Producer producer) {
|
|
||||||
//setProducer(producer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRate() {
|
|
||||||
return rate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound;
|
|
||||||
|
|
||||||
public interface Consumer {
|
|
||||||
public void start(Producer producer);
|
|
||||||
public void stop();
|
|
||||||
public void exit();
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
|
|
||||||
public interface Format extends Cloneable {
|
|
||||||
public interface Standard extends Format {
|
|
||||||
public AudioFormat getAudioFormat();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Mp3 extends Format {
|
|
||||||
public int getRate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public interface Producer extends Format {
|
|
||||||
public InputStream getInputStream();
|
|
||||||
public void start();
|
|
||||||
public void stop();
|
|
||||||
public void exit();
|
|
||||||
}
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
import javax.sound.sampled.LineUnavailableException;
|
|
||||||
import javax.sound.sampled.SourceDataLine;
|
|
||||||
|
|
||||||
import javazoom.jl.decoder.JavaLayerException;
|
|
||||||
import javazoom.jl.player.Player;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sound.util.Tool;
|
|
||||||
import base.exception.worker.ActivateException;
|
|
||||||
import base.exception.worker.DeactivateException;
|
|
||||||
import base.work.Work;
|
|
||||||
|
|
||||||
public class Source implements Consumer {
|
|
||||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
protected static final int BUFFER_SIZE = 1024 * 4; // in bytes
|
|
||||||
protected static final int FRAMES = 10; // count
|
|
||||||
|
|
||||||
protected String name;
|
|
||||||
protected Producer producer;
|
|
||||||
protected InputStream producerInputStream;
|
|
||||||
protected Work work;
|
|
||||||
|
|
||||||
public Source(String name) throws LineUnavailableException {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
if (work != null) {
|
|
||||||
work.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Producer producer) {
|
|
||||||
this.producer = producer;
|
|
||||||
producerInputStream = producer.getInputStream();
|
|
||||||
if (work != null) {
|
|
||||||
work.exit();
|
|
||||||
}
|
|
||||||
if (producer instanceof Format.Standard) {
|
|
||||||
logger.debug("Format.Standard");
|
|
||||||
work = new DefaultWorker((Format.Standard) producer);
|
|
||||||
} else if (producer instanceof Format.Mp3) {
|
|
||||||
logger.debug("Format.Mp3");
|
|
||||||
work = new Mp3Worker((Format.Mp3) producer);
|
|
||||||
}
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
if (work != null) {
|
|
||||||
work.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
if (work != null) {
|
|
||||||
work.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class DefaultWorker extends Work {
|
|
||||||
protected Format.Standard format;
|
|
||||||
protected SourceDataLine line;
|
|
||||||
|
|
||||||
public DefaultWorker(Format.Standard format) {
|
|
||||||
this.format = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() throws ActivateException {
|
|
||||||
AudioFormat audioFormat = format.getAudioFormat();
|
|
||||||
try {
|
|
||||||
if (line == null) {
|
|
||||||
line = Tool.getSourceDataLine(name, audioFormat);
|
|
||||||
}
|
|
||||||
if (!line.isOpen()) {
|
|
||||||
line.open();
|
|
||||||
}
|
|
||||||
} catch (LineUnavailableException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
if (!line.isRunning()) {
|
|
||||||
line.start();
|
|
||||||
}
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() throws DeactivateException {
|
|
||||||
super.deactivate();
|
|
||||||
line.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
super.exit();
|
|
||||||
line.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void work() {
|
|
||||||
try {
|
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
int read = producerInputStream.read(buffer, 0, buffer.length);
|
|
||||||
if (read > 0) {
|
|
||||||
line.write(buffer, 0, read);
|
|
||||||
} else {
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class Mp3Worker extends Work {
|
|
||||||
protected Format.Mp3 format;
|
|
||||||
protected Player player;
|
|
||||||
|
|
||||||
public Mp3Worker(Format.Mp3 format) {
|
|
||||||
this.format = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() throws ActivateException {
|
|
||||||
producer.start();
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() throws DeactivateException {
|
|
||||||
super.deactivate();
|
|
||||||
producer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
super.exit();
|
|
||||||
player.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void work() {
|
|
||||||
try {
|
|
||||||
if (player == null) {
|
|
||||||
player = new Player(producerInputStream);
|
|
||||||
sleep(100);
|
|
||||||
}
|
|
||||||
player.play(FRAMES);
|
|
||||||
} catch (JavaLayerException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
if (player.isComplete()) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.consumer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
|
|
||||||
import sound.Consumer;
|
|
||||||
import sound.Format;
|
|
||||||
import sound.Format.Standard;
|
|
||||||
import sound.Producer;
|
|
||||||
import sound.util.SoxBuilder;
|
|
||||||
import sound.util.SoxBuilder.File;
|
|
||||||
import sound.util.SoxBuilder.File.Type;
|
|
||||||
import sound.util.SoxBuilder.Option;
|
|
||||||
import base.exception.worker.ActivateException;
|
|
||||||
import base.exception.worker.DeactivateException;
|
|
||||||
import base.work.Work;
|
|
||||||
|
|
||||||
public class Port extends Work implements Consumer {
|
|
||||||
protected static final int BUFFER_SIZE = 1024 * 4; // in bytes
|
|
||||||
|
|
||||||
protected String device;
|
|
||||||
protected Producer producer;
|
|
||||||
protected Process process;
|
|
||||||
protected InputStream producerInputStream;
|
|
||||||
protected OutputStream processOutputStream;
|
|
||||||
protected ProcessBuilder processBuilder;
|
|
||||||
|
|
||||||
public Port() {
|
|
||||||
this("0");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Port(String device) {
|
|
||||||
this.device = device;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Producer producer) {
|
|
||||||
start(producer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("static-access")
|
|
||||||
public void start(Producer producer, boolean thread) {
|
|
||||||
this.producer = producer;
|
|
||||||
producerInputStream = producer.getInputStream();
|
|
||||||
|
|
||||||
String command = "";
|
|
||||||
if (producer instanceof Standard) {
|
|
||||||
AudioFormat audioFormat = ((Standard) producer).getAudioFormat();
|
|
||||||
SoxBuilder.addFile(File.setType(Type.STANDARD).setOptions(audioFormat));
|
|
||||||
} else if (producer instanceof Format.Mp3) {
|
|
||||||
SoxBuilder.addFile(File.setType(Type.STANDARD).setOption(File.Format.MP3));
|
|
||||||
}
|
|
||||||
command = SoxBuilder
|
|
||||||
.setOption(Option.QUIET)
|
|
||||||
.addFile(File.setType(Type.DEVICE))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
logger.debug(String.format("Build process (\"%s\")", command));
|
|
||||||
processBuilder = new ProcessBuilder(command.split(" "));
|
|
||||||
processBuilder.environment().put("AUDIODEV", device);
|
|
||||||
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() throws ActivateException {
|
|
||||||
producer.start();
|
|
||||||
if (process == null) {
|
|
||||||
try {
|
|
||||||
process = processBuilder.start();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
processOutputStream = process.getOutputStream();
|
|
||||||
}
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() throws DeactivateException {
|
|
||||||
super.deactivate();
|
|
||||||
try {
|
|
||||||
processOutputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new DeactivateException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
try {
|
|
||||||
logger.debug("close process output stream");
|
|
||||||
processOutputStream.close();
|
|
||||||
|
|
||||||
logger.debug("wait for process to terminate");
|
|
||||||
process.waitFor();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
} finally {
|
|
||||||
process = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void work() {
|
|
||||||
try {
|
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
int read = producerInputStream.read(buffer, 0, buffer.length);
|
|
||||||
if (read > 0) {
|
|
||||||
processOutputStream.write(buffer, 0, read);
|
|
||||||
} else {
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.consumer;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
|
|
||||||
import sound.Consumer;
|
|
||||||
import sound.Producer;
|
|
||||||
import sound.data.Data;
|
|
||||||
import sound.util.Buffer;
|
|
||||||
import base.exception.worker.ActivateException;
|
|
||||||
import base.exception.worker.DeactivateException;
|
|
||||||
import base.work.Listen;
|
|
||||||
import base.work.Work;
|
|
||||||
|
|
||||||
import com.Ostermiller.util.CircularObjectBuffer;
|
|
||||||
|
|
||||||
public class Shoutcast extends Work implements Consumer {
|
|
||||||
public static final int PORT = 9876;
|
|
||||||
public static final int RATE = 192; // in kbps
|
|
||||||
public static final int META = 8192; // in bytes
|
|
||||||
public static final int STEP = 80; // in milliseconds
|
|
||||||
public static final int BUFFER = 2000; // in bytes
|
|
||||||
public static final int BUFFERING = 500; // in milliseconds
|
|
||||||
public static final String DATA = "StreamTitle='%s';StreamUrl='%s';";
|
|
||||||
protected int rate;
|
|
||||||
protected int port;
|
|
||||||
protected Server server;
|
|
||||||
protected HashMap<String, String> headerMap;
|
|
||||||
protected ConcurrentLinkedQueue<Client> clientList;
|
|
||||||
protected InputStream producerInputStream;
|
|
||||||
protected int chunk;
|
|
||||||
protected Buffer buffer;
|
|
||||||
protected byte[] bytes;
|
|
||||||
protected Data data;
|
|
||||||
protected String metaData;
|
|
||||||
private CircularObjectBuffer<String> circularStringBuffer;
|
|
||||||
|
|
||||||
public Shoutcast() {
|
|
||||||
this(RATE, PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Shoutcast(int rate) {
|
|
||||||
this(rate, PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Shoutcast(int rate, int port) {
|
|
||||||
this.rate = rate;
|
|
||||||
this.port = port;
|
|
||||||
clientList = new ConcurrentLinkedQueue<Client>();
|
|
||||||
metaData = "";
|
|
||||||
|
|
||||||
chunk = STEP * rate / 8;
|
|
||||||
bytes = new byte[chunk];
|
|
||||||
buffer = new Buffer(BUFFER * rate / 8);
|
|
||||||
|
|
||||||
headerMap = new HashMap<String, String>();
|
|
||||||
headerMap.put("icy-notice1", "This stream requires <a href=\"http://www.winamp.com/\">Winamp</a>");
|
|
||||||
headerMap.put("icy-notice2", "Java SHOUTcast Server");
|
|
||||||
headerMap.put("icy-name", "Java Radio");
|
|
||||||
headerMap.put("icy-genre", "Java");
|
|
||||||
headerMap.put("icy-url", "http://localhost");
|
|
||||||
headerMap.put("content-type:", "audio/mpeg");
|
|
||||||
headerMap.put("icy-pub", "0");
|
|
||||||
headerMap.put("icy-metaint", String.valueOf(META));
|
|
||||||
headerMap.put("icy-br", String.valueOf(rate));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() throws ActivateException {
|
|
||||||
logger.trace("Activate Server");
|
|
||||||
server = new Server(port);
|
|
||||||
server.start();
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean active() {
|
|
||||||
return server.active();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() throws DeactivateException {
|
|
||||||
super.deactivate();
|
|
||||||
server.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void work() {
|
|
||||||
int progress;
|
|
||||||
try {
|
|
||||||
int read = 0;
|
|
||||||
if (producerInputStream != null) {
|
|
||||||
while (producerInputStream.available() < buffer.capacity) {
|
|
||||||
progress = (int) (producerInputStream.available() / (buffer.capacity / 100.0F));
|
|
||||||
logger.debug("Filling buffer: " + progress + "%");
|
|
||||||
sleep(BUFFERING);
|
|
||||||
}
|
|
||||||
read = producerInputStream.read(bytes);
|
|
||||||
}
|
|
||||||
data = new Data(bytes, read);
|
|
||||||
buffer.write(bytes, 0, read);
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Client client : clientList) {
|
|
||||||
if (client.active) {
|
|
||||||
client.add(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sleep(STEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMetaBuffer(CircularObjectBuffer<String> circularStringBuffer) {
|
|
||||||
logger.debug("Set meta input stream");
|
|
||||||
this.circularStringBuffer = circularStringBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMeta(String meta) {
|
|
||||||
logger.debug("Set meta string: " + meta);
|
|
||||||
metaData = meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class Client extends Listen<Data> {
|
|
||||||
protected Socket socket;
|
|
||||||
protected InputStream inputStream;
|
|
||||||
protected OutputStream outputStream;
|
|
||||||
protected boolean writeMeta;
|
|
||||||
protected int untilMeta;
|
|
||||||
protected boolean active;
|
|
||||||
|
|
||||||
public Client(Socket socket) throws IOException {
|
|
||||||
this.socket = socket;
|
|
||||||
inputStream = socket.getInputStream();
|
|
||||||
outputStream = socket.getOutputStream();
|
|
||||||
active = false;
|
|
||||||
clientList.add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() throws ActivateException {
|
|
||||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
|
||||||
try {
|
|
||||||
String line;
|
|
||||||
while ((line = bufferedReader.readLine()) != null) {
|
|
||||||
if (line.startsWith("Icy-MetaData")) {
|
|
||||||
writeMeta = Integer.valueOf(line.substring(line.indexOf(":") + 1).trim()).intValue() == 1;
|
|
||||||
untilMeta = META;
|
|
||||||
} else if (line.equals("")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug(String.format("Client accept meta: %s", Boolean.valueOf(writeMeta)));
|
|
||||||
|
|
||||||
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
|
|
||||||
outputStreamWriter.write("ICY 200 OK\r\n");
|
|
||||||
for (Entry<String, String> header : headerMap.entrySet()) {
|
|
||||||
outputStreamWriter.write(String.format("%s: %s\r\n", header.getKey(), header.getValue()));
|
|
||||||
}
|
|
||||||
outputStreamWriter.write("\r\n");
|
|
||||||
outputStreamWriter.flush();
|
|
||||||
|
|
||||||
add(new Data(buffer.get()));
|
|
||||||
active = true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
logger.debug("Client exit");
|
|
||||||
super.exit();
|
|
||||||
clientList.remove(this);
|
|
||||||
try {
|
|
||||||
inputStream.close();
|
|
||||||
outputStream.close();
|
|
||||||
socket.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void input(Data data) {
|
|
||||||
try {
|
|
||||||
byte[] bytes = data.get();
|
|
||||||
if (writeMeta) {
|
|
||||||
int offset = 0;
|
|
||||||
while (data.length() - offset >= untilMeta) {
|
|
||||||
outputStream.write(bytes, offset, untilMeta);
|
|
||||||
writeMeta();
|
|
||||||
offset += untilMeta;
|
|
||||||
untilMeta = META;
|
|
||||||
}
|
|
||||||
int length = data.length() - offset;
|
|
||||||
outputStream.write(bytes, offset, length);
|
|
||||||
untilMeta -= length;
|
|
||||||
} else {
|
|
||||||
outputStream.write(bytes);
|
|
||||||
}
|
|
||||||
} catch (SocketException e) {
|
|
||||||
exit();
|
|
||||||
} catch (IOException e) {
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void writeMeta() throws IOException {
|
|
||||||
if ((circularStringBuffer != null)
|
|
||||||
&& (circularStringBuffer.getAvailable() > 0)) {
|
|
||||||
try {
|
|
||||||
String newMetaData = circularStringBuffer.read();
|
|
||||||
if (!newMetaData.isEmpty() && !newMetaData.equals(metaData)) {
|
|
||||||
metaData = newMetaData;
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String meta = String.format("StreamTitle='%s';StreamUrl='%s';", metaData, "???");
|
|
||||||
byte[] metaBytes = meta.getBytes();
|
|
||||||
|
|
||||||
int length = (int) Math.ceil(metaBytes.length / 16.0F);
|
|
||||||
outputStream.write(length);
|
|
||||||
outputStream.write(metaBytes);
|
|
||||||
|
|
||||||
int padding = 16 * length - metaBytes.length;
|
|
||||||
outputStream.write(new byte[padding], 0, padding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class Server extends Work {
|
|
||||||
protected int port;
|
|
||||||
protected ServerSocket serverSocket;
|
|
||||||
|
|
||||||
public Server(int port) {
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean active() {
|
|
||||||
return serverSocket.isClosed() ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() throws ActivateException {
|
|
||||||
try {
|
|
||||||
serverSocket = new ServerSocket(port);
|
|
||||||
logger.debug("Server listening at port " + port);
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new ActivateException();
|
|
||||||
}
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void work() {
|
|
||||||
try {
|
|
||||||
Socket socket = serverSocket.accept();
|
|
||||||
logger.trace("Client connected: " + socket.getInetAddress().toString());
|
|
||||||
Shoutcast.Client client = new Shoutcast.Client(socket);
|
|
||||||
client.start();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() throws DeactivateException {
|
|
||||||
logger.debug("Server deactivate");
|
|
||||||
super.deactivate();
|
|
||||||
try {
|
|
||||||
serverSocket.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
}
|
|
||||||
for (Shoutcast.Client client : clientList) {
|
|
||||||
client.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Producer producer) {
|
|
||||||
producerInputStream = producer.getInputStream();
|
|
||||||
producer.start();
|
|
||||||
super.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInputStream(InputStream inputStream) {
|
|
||||||
producerInputStream = inputStream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.data;
|
|
||||||
|
|
||||||
public class Data {
|
|
||||||
protected byte[] bytes;
|
|
||||||
protected int length;
|
|
||||||
|
|
||||||
public Data(byte[] bytes) {
|
|
||||||
this(bytes, bytes.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Data(byte[] bytes, int length) {
|
|
||||||
this.bytes = bytes;
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] get() {
|
|
||||||
return this.bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return this.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.producer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import sound.Format;
|
|
||||||
import sound.Producer;
|
|
||||||
import sound.stream.HoardedInputStream;
|
|
||||||
import base.exception.worker.ActivateException;
|
|
||||||
import base.exception.worker.DeactivateException;
|
|
||||||
import base.work.Work;
|
|
||||||
|
|
||||||
import com.Ostermiller.util.CircularByteBuffer;
|
|
||||||
import com.Ostermiller.util.CircularObjectBuffer;
|
|
||||||
|
|
||||||
public class Stream extends Work implements Producer, Format.Mp3 {
|
|
||||||
public static final int STEP = 80; // in milliseconds
|
|
||||||
|
|
||||||
protected String http;
|
|
||||||
protected Socket socket;
|
|
||||||
protected InputStream socketInputStream;
|
|
||||||
protected OutputStreamWriter socketOutputStreamWriter;
|
|
||||||
protected HoardedInputStream hoardedInputStream;
|
|
||||||
protected int meta;
|
|
||||||
protected int rate;
|
|
||||||
protected int chunk;
|
|
||||||
protected int untilMeta;
|
|
||||||
protected CircularByteBuffer audioCircularByteBuffer;
|
|
||||||
protected CircularObjectBuffer<String> metaCircularObjectBuffer;
|
|
||||||
protected String metaData;
|
|
||||||
|
|
||||||
public Stream(String http) {
|
|
||||||
super();
|
|
||||||
this.http = http;
|
|
||||||
meta = -1;
|
|
||||||
rate = -1;
|
|
||||||
audioCircularByteBuffer = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
|
|
||||||
metaCircularObjectBuffer = new CircularObjectBuffer<String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void connect(URL url) {
|
|
||||||
try {
|
|
||||||
/* Open socket communication */
|
|
||||||
socket = new Socket(url.getHost(), url.getPort());
|
|
||||||
socketInputStream = socket.getInputStream();
|
|
||||||
socketOutputStreamWriter = new OutputStreamWriter(socket.getOutputStream());
|
|
||||||
|
|
||||||
/* Write stream request */
|
|
||||||
if (url.getFile().equals("")) {
|
|
||||||
socketOutputStreamWriter.write("GET / HTTP/1.1\r\n");
|
|
||||||
} else {
|
|
||||||
socketOutputStreamWriter.write("GET " + url.getFile() + " HTTP/1.1\r\n");
|
|
||||||
}
|
|
||||||
socketOutputStreamWriter.write("Host: " + url.getHost() + "\r\n");
|
|
||||||
//socketOutputStreamWriter.write("Icy-MetaData: 1\r\n");
|
|
||||||
socketOutputStreamWriter.write("Connection: close\r\n");
|
|
||||||
socketOutputStreamWriter.write("\r\n");
|
|
||||||
socketOutputStreamWriter.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() throws ActivateException {
|
|
||||||
try {
|
|
||||||
/* Initialize connection */
|
|
||||||
URL url = new URL(http);
|
|
||||||
|
|
||||||
/* Parse headers */
|
|
||||||
connect(url);
|
|
||||||
InputStreamReader inputStreamReader = new InputStreamReader(socketInputStream);
|
|
||||||
StringBuffer stringBuffer = new StringBuffer();
|
|
||||||
char character;
|
|
||||||
int skip = 0;
|
|
||||||
while ((character = (char) inputStreamReader.read()) > 0) {
|
|
||||||
++skip;
|
|
||||||
if (character == '\n') {
|
|
||||||
/* Fetch relevant headers */
|
|
||||||
String line = stringBuffer.toString().trim();
|
|
||||||
if (line.startsWith("icy-metaint")) {
|
|
||||||
meta = Integer.valueOf(line.substring(line.indexOf(":") + 1).trim());
|
|
||||||
} else if (line.startsWith("icy-br")) {
|
|
||||||
rate = Integer.valueOf(line.substring(line.indexOf(":") + 1).trim());
|
|
||||||
} else if (line.equals("")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
stringBuffer = new StringBuffer();
|
|
||||||
} else {
|
|
||||||
stringBuffer.append(character);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inputStreamReader.close();
|
|
||||||
|
|
||||||
/* Reconnect to bypass pre-buffering problems */
|
|
||||||
connect(url);
|
|
||||||
socketInputStream = socket.getInputStream();
|
|
||||||
socketInputStream.skip(skip);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate streaming parameters */
|
|
||||||
//untilMeta = meta;
|
|
||||||
chunk = STEP * rate / 8;
|
|
||||||
super.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() throws DeactivateException {
|
|
||||||
super.deactivate();
|
|
||||||
audioCircularByteBuffer.clear();
|
|
||||||
metaCircularObjectBuffer.clear();
|
|
||||||
try {
|
|
||||||
hoardedInputStream.clear();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
throw new DeactivateException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void work() {
|
|
||||||
int left = chunk;
|
|
||||||
|
|
||||||
/* Handle media at appropriate times *
|
|
||||||
while (meta > 0 && left >= untilMeta) {
|
|
||||||
stream(untilMeta);
|
|
||||||
left -= untilMeta;
|
|
||||||
meta();
|
|
||||||
untilMeta = meta;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/* Stream at fixed rate */
|
|
||||||
stream(left);
|
|
||||||
//untilMeta -= left;
|
|
||||||
sleep(STEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void stream(int length) {
|
|
||||||
try {
|
|
||||||
byte[] bytes = new byte[length];
|
|
||||||
int read = 0;
|
|
||||||
while (length > 0 && (read = socketInputStream.read(bytes)) > 0) {
|
|
||||||
length -= read;
|
|
||||||
audioCircularByteBuffer.getOutputStream().write(bytes);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void meta() {
|
|
||||||
try {
|
|
||||||
/* Retrieve data length */
|
|
||||||
byte[] data = new byte[1];
|
|
||||||
socketInputStream.read(data);
|
|
||||||
|
|
||||||
int length = 16 * data[0];
|
|
||||||
data = new byte[length];
|
|
||||||
socketInputStream.read(data);
|
|
||||||
|
|
||||||
/* Check for new data */
|
|
||||||
String newMetaData = new String(data);
|
|
||||||
if (!newMetaData.isEmpty() && !newMetaData.equals(metaData)) {
|
|
||||||
metaData = newMetaData;
|
|
||||||
metaCircularObjectBuffer.write(new String(data));
|
|
||||||
logger.debug("data: " + metaData);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getInputStream() {
|
|
||||||
if (hoardedInputStream == null) {
|
|
||||||
hoardedInputStream = new HoardedInputStream(audioCircularByteBuffer.getInputStream());
|
|
||||||
}
|
|
||||||
return hoardedInputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CircularObjectBuffer<String> getMetaBufferStream() {
|
|
||||||
return metaCircularObjectBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRate() {
|
|
||||||
return rate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.producer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
import javax.sound.sampled.LineUnavailableException;
|
|
||||||
import javax.sound.sampled.TargetDataLine;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sound.Format;
|
|
||||||
import sound.Producer;
|
|
||||||
import sound.stream.HoardedInputStream;
|
|
||||||
import sound.util.Tool;
|
|
||||||
|
|
||||||
public class Target implements Producer, Format.Standard {
|
|
||||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
protected Standard format;
|
|
||||||
|
|
||||||
protected TargetDataLine line;
|
|
||||||
protected InputStream targetInputStream;
|
|
||||||
protected HoardedInputStream hoardedInputStream;
|
|
||||||
|
|
||||||
protected AudioFormat audioFormat;
|
|
||||||
|
|
||||||
public Target(String name) throws LineUnavailableException {
|
|
||||||
logger.debug(String.format("Target \"%s\" without format", name));
|
|
||||||
line = Tool.getTargetDataLine(name);
|
|
||||||
audioFormat = line.getFormat();
|
|
||||||
targetInputStream = new TargetInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Target(String name, AudioFormat audioFormat) throws LineUnavailableException {
|
|
||||||
logger.debug(String.format("Target \"%s\" with format: %s", name, audioFormat));
|
|
||||||
this.audioFormat = audioFormat;
|
|
||||||
line = Tool.getTargetDataLine(name, audioFormat);
|
|
||||||
targetInputStream = new TargetInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public AudioFormat getAudioFormat() {
|
|
||||||
return audioFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getInputStream() {
|
|
||||||
return targetInputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TargetInputStream extends InputStream {
|
|
||||||
protected boolean open;
|
|
||||||
|
|
||||||
public TargetInputStream() {
|
|
||||||
open = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read() throws IOException {
|
|
||||||
start();
|
|
||||||
byte[] buffer = new byte[1];
|
|
||||||
line.read(buffer, 0, 1);
|
|
||||||
return (int) buffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] buffer, int offset, int length) {
|
|
||||||
start();
|
|
||||||
line.read(buffer, offset, length);
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int available() {
|
|
||||||
start();
|
|
||||||
return line.available();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
if (!line.isOpen()) {
|
|
||||||
try {
|
|
||||||
line.open();
|
|
||||||
} catch (LineUnavailableException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!line.isRunning()) {
|
|
||||||
line.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
line.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exit() {
|
|
||||||
line.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.stream;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class HoardedInputStream extends BufferedInputStream {
|
|
||||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
protected static final int SLEEP = 500; // in milliseconds
|
|
||||||
protected static final int BUFFER_SIZE = 30000; // in bytes
|
|
||||||
protected static final int MINIMUM_SIZE = 1000; // in bytes
|
|
||||||
|
|
||||||
protected int bufferSize;
|
|
||||||
protected int minimumSize;
|
|
||||||
protected boolean hoard;
|
|
||||||
|
|
||||||
public HoardedInputStream(InputStream inputStream) {
|
|
||||||
this(inputStream, BUFFER_SIZE, MINIMUM_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HoardedInputStream(InputStream inputStream, int bufferSize) {
|
|
||||||
super(inputStream, bufferSize);
|
|
||||||
this.bufferSize = bufferSize;
|
|
||||||
hoard = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HoardedInputStream(InputStream inputStream, int bufferSize, int minimumSize) {
|
|
||||||
this(inputStream, bufferSize);
|
|
||||||
this.minimumSize = minimumSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read() throws IOException {
|
|
||||||
hoard();
|
|
||||||
byte[] buffer = new byte[1];
|
|
||||||
in.read(buffer, 0, 1);
|
|
||||||
return (int) buffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] buffer, int offset, int length) throws IOException {
|
|
||||||
hoard();
|
|
||||||
in.read(buffer, offset, length);
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void hoard() throws IOException {
|
|
||||||
int available = available();
|
|
||||||
if (hoard && available < MINIMUM_SIZE) {
|
|
||||||
long time = System.currentTimeMillis();
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
Thread.sleep(SLEEP);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.warn("", e);
|
|
||||||
}
|
|
||||||
} while (available() < BUFFER_SIZE);
|
|
||||||
logger.debug(String.format("Buffered %d bytes in %s milliseconds", BUFFER_SIZE - available, System.currentTimeMillis() - time));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() throws IOException {
|
|
||||||
this.buf = new byte[buf.length];
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drain() {
|
|
||||||
drain(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drain(boolean drain) {
|
|
||||||
hoard = !drain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.util;
|
|
||||||
|
|
||||||
public class Buffer {
|
|
||||||
protected byte[] elements;
|
|
||||||
public int capacity;
|
|
||||||
protected int index;
|
|
||||||
protected int size;
|
|
||||||
|
|
||||||
public Buffer(int capacity) {
|
|
||||||
elements = new byte[capacity];
|
|
||||||
this.capacity = capacity;
|
|
||||||
index = 0;
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void add(byte[] elements) {
|
|
||||||
for (byte element : elements) {
|
|
||||||
elements[index++ % capacity] = element;
|
|
||||||
if (size < capacity) {
|
|
||||||
++size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void write(byte[] elements, int offset, int length) {
|
|
||||||
for (int i = offset; i < length; ++i) {
|
|
||||||
this.elements[(index++ % capacity)] = elements[i];
|
|
||||||
if (size < capacity) {
|
|
||||||
++size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized byte[] get() {
|
|
||||||
byte[] elements = new byte[size];
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
elements[i] = elements[((index + i) % size)];
|
|
||||||
}
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.util;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
|
|
||||||
import sound.util.SoxBuilder.Option.Combine;
|
|
||||||
import sound.util.SoxBuilder.Option.Replay;
|
|
||||||
|
|
||||||
public final class SoxBuilder {
|
|
||||||
protected static SoxBuilder instance;
|
|
||||||
protected static HashMap<String, String> optionMap;
|
|
||||||
protected static String files;
|
|
||||||
protected static String effects;
|
|
||||||
|
|
||||||
static {
|
|
||||||
instance = new SoxBuilder();
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void reset() {
|
|
||||||
optionMap = new HashMap<String, String>();
|
|
||||||
files = "";
|
|
||||||
effects = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder setOption(Option option, String value) {
|
|
||||||
optionMap.put(option.getCode(), value);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder setOption(Option option) {
|
|
||||||
return SoxBuilder.setOption(option, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder setOption(Option option, int value) {
|
|
||||||
return SoxBuilder.setOption(option, String.valueOf(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder setOption(Option option, Combine combine) {
|
|
||||||
return SoxBuilder.setOption(option, combine.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder setOption(Combine combine) {
|
|
||||||
return SoxBuilder.setOption(Option.COMBINE, combine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder setOption(Option option, Replay replay) {
|
|
||||||
return SoxBuilder.setOption(option, replay.toString().toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder setOption(Replay replay) {
|
|
||||||
return SoxBuilder.setOption(Option.REPLAY, replay);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder addFile(File file) {
|
|
||||||
files = String.format("%s %s", files, file.build());
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoxBuilder addEffect(Effect effect) {
|
|
||||||
effects = String.format("%s %s", effects, effect.build());
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String build() {
|
|
||||||
String build = "sox";
|
|
||||||
for (Entry<String, String> entry : optionMap.entrySet()) {
|
|
||||||
String value = entry.getValue();
|
|
||||||
if (value.equals("")) {
|
|
||||||
build = String.format("%s %s", build, entry.getKey());
|
|
||||||
} else {
|
|
||||||
String option = String.format("%s %s", entry.getKey(), value);
|
|
||||||
build = String.format("%s %s", build, option);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
build = String.format("%s%s%s", build, files, effects);
|
|
||||||
reset();
|
|
||||||
return build;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Environment {
|
|
||||||
AUDIODRIVER, AUDIODEV
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Option {
|
|
||||||
BUFFER ("--buffer"), // default=8192
|
|
||||||
INPUT_BUFFER ("--input-buffer"),
|
|
||||||
CLOBBER ("--clobber"),
|
|
||||||
COMBINE ("--combine"), // |Combine|
|
|
||||||
NO_DITHER ("--no-dither"), // (-D)
|
|
||||||
EFFECTS_FILE ("--efects-file"),
|
|
||||||
GUARD ("--guard"), // (-G)
|
|
||||||
MIX ("-m"), // (--combine mix)
|
|
||||||
MERGE ("-M"), // (--combine merge)
|
|
||||||
MAGIC ("--magic"),
|
|
||||||
MULTI_THREADED ("--multi-threaded"),
|
|
||||||
SINGLE_THREADED ("--single-threaded"),
|
|
||||||
NORM ("--norm"), // [=dB-level]
|
|
||||||
PLAY_RATE_ARG ("--play-rate-arg"),
|
|
||||||
QUIET ("--no-show-progress"), // (-q)
|
|
||||||
REPEATABLE ("-R"),
|
|
||||||
REPLAY ("--replay-gain"), // |Replay|
|
|
||||||
MULTIPLY ("-T"), // (--combine multiply)
|
|
||||||
TEMP ("--temp");
|
|
||||||
|
|
||||||
protected String code;
|
|
||||||
|
|
||||||
private Option(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Combine {
|
|
||||||
CONCATENATE ("concatenate"),
|
|
||||||
MERGE ("merge"), // (-M)
|
|
||||||
MIX ("mix"), // (-m)
|
|
||||||
MIX_POWER ("mix-power"),
|
|
||||||
MULTIPLY ("multiply"), // (-T)
|
|
||||||
SEQUENCE ("sequence");
|
|
||||||
|
|
||||||
protected String code;
|
|
||||||
|
|
||||||
private Combine(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Replay {
|
|
||||||
TRACK, ALBUM, OFF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class File {
|
|
||||||
protected static File instance;
|
|
||||||
|
|
||||||
protected static HashMap<String, String> optionMap;
|
|
||||||
protected static Type type;
|
|
||||||
|
|
||||||
static {
|
|
||||||
instance = new File();
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void reset() {
|
|
||||||
optionMap = new HashMap<String, String>();
|
|
||||||
type = Type.PIPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Option option, String value) {
|
|
||||||
optionMap.put(option.getCode(), value);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Option option) {
|
|
||||||
return File.setOption(option, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Option option, int value) {
|
|
||||||
return File.setOption(option, String.valueOf(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Option option, Encoding encoding) {
|
|
||||||
return File.setOption(option, encoding.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Encoding encoding) {
|
|
||||||
return File.setOption(Option.ENCODING, encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Option option, Format format) {
|
|
||||||
return File.setOption(option, format.toString().toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption( Format format) {
|
|
||||||
return File.setOption(Option.FORMAT, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Option option, Endian endian) {
|
|
||||||
return File.setOption(option, endian.toString().toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setOption(Endian endian) {
|
|
||||||
return File.setOption(Option.ENDIAN, endian);
|
|
||||||
}
|
|
||||||
|
|
||||||
public File setOptions(AudioFormat audioFormat) {
|
|
||||||
setOption(Option.CHANNELS, audioFormat.getChannels());
|
|
||||||
setOption(Option.RATE, String.format("%sk", String.valueOf(audioFormat.getSampleRate() / 1000f)));
|
|
||||||
AudioFormat.Encoding encoding = audioFormat.getEncoding();
|
|
||||||
int bits = audioFormat.getSampleSizeInBits();
|
|
||||||
if (encoding.equals(AudioFormat.Encoding.ALAW)) {
|
|
||||||
setOption(Format.AL);
|
|
||||||
setOption(Encoding.A_LAW);
|
|
||||||
} else if (encoding.equals(AudioFormat.Encoding.ULAW)) {
|
|
||||||
setOption(Format.UL);
|
|
||||||
setOption(Encoding.U_LAW);
|
|
||||||
} else if (encoding.equals(AudioFormat.Encoding.PCM_SIGNED)) {
|
|
||||||
setOption(Format.valueOf(String.format("S%d", bits)));
|
|
||||||
setOption(Encoding.SIGNED_INTEGER);
|
|
||||||
} else if (encoding.equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
|
|
||||||
setOption(Format.valueOf(String.format("U%d", bits)));
|
|
||||||
setOption(Encoding.UNSIGNED_INTEGER);
|
|
||||||
}
|
|
||||||
setOption(audioFormat.isBigEndian() ? Endian.BIG : Endian.LITTLE);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File setType(Type type) {
|
|
||||||
File.type = type;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String build() {
|
|
||||||
String build = type.getCode();
|
|
||||||
for (Entry<String, String> entry : optionMap.entrySet()) {
|
|
||||||
String value = entry.getValue();
|
|
||||||
if (value.equals("")) {
|
|
||||||
build = String.format("%s %s", entry.getKey(), build);
|
|
||||||
} else {
|
|
||||||
String option = String.format("%s %s", entry.getKey(), value);
|
|
||||||
build = String.format("%s %s", option, build);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reset();
|
|
||||||
return build;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Option {
|
|
||||||
BITS ("--bits"), // (-b)
|
|
||||||
CHANNELS ("--channels"), // (-c)
|
|
||||||
ENCODING ("--encoding"), // (-e), |Encoding|
|
|
||||||
NO_GLOB ("--no-glob"),
|
|
||||||
RATE ("--rate"), // (-r)
|
|
||||||
FORMAT ("--type"), // (-t), |Format|
|
|
||||||
ENDIAN ("--endian"), // (-L, -B, -x), |Endian|
|
|
||||||
REVERSE_NIBBLES ("--reverse-nibbles"), // (-N)
|
|
||||||
REVERSE_BITS ("--reverse-bits"), // (-X)
|
|
||||||
/* Input only */
|
|
||||||
IGNORE_LENGTH ("--ignore-length"),
|
|
||||||
VOLUME ("--volume"), // (-v)
|
|
||||||
/* Output only */
|
|
||||||
ADD_COMMENT ("--add-comment"),
|
|
||||||
COMMENT ("--comment"),
|
|
||||||
COMMENT_FILE ("--comment-file"),
|
|
||||||
COMPRESSION ("--compression"); // -C
|
|
||||||
|
|
||||||
protected String code;
|
|
||||||
|
|
||||||
private Option(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Encoding {
|
|
||||||
SIGNED_INTEGER ("signed-integer"), // PCM data stored as signed integers
|
|
||||||
UNSIGNED_INTEGER ("unsigned-integer"), // PCM data stored as unsigned integers
|
|
||||||
FLOATING_POINT ("floating-point"), // PCM data stored as single precision (32-bit) or double precision (64-bit) floating-point numbers
|
|
||||||
A_LAW ("a-lawW"), // International telephony standard for logarithmic encoding to 8 bits per sample (~13-bit PCM)
|
|
||||||
U_LAW ("u-law"), // North American telephony standard for logarithmic encoding to 8 bits per sample (~14-bit PCM)
|
|
||||||
MU_LAW ("mu-law"), // alias for u-law (~14-bit PCM)
|
|
||||||
OKI_ADPCM ("oki-adpcm"), // OKI (VOX, Dialogic or Intel) 4-bit ADPCM (~12-bit PCM)
|
|
||||||
IMA_ADPCM ("ima-adpcm"), // IMA (DVI) 4-bit ADPCM (~13-bit PCM)
|
|
||||||
MS_ADPCM ("ms-adpcm"), // Microsoft 4-bit ADPCM (~14-bit PCM)
|
|
||||||
GSM_FULL_RATE ("gsm-full-rate"); // Several audio formats used for digital wireless telephone calls
|
|
||||||
|
|
||||||
protected String code;
|
|
||||||
|
|
||||||
private Encoding(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Format {
|
|
||||||
AIF, AIFC, AIFF, AIFFC, AL, AMB, AMR, ANY, ARL, AU, AVR, BIN, CAF, CDDA, CDR, CVS, CVSD, CVU, DAT, DVMS, EDU, F32, F64, FAP, FLAC, FSSD, GSM, GSRT, HCOM, HTK, IMA, IRCAM, LA, LPC, LPC10, LU, M3U, M4A, MAT, MAT4, MAT5, MAUD, MP2, MP3, MP4, NIST, OGG, PAF, PLS, PRC, PVF, RAW, S16, S24, S32, S8, SD2, SDS, SF, SLN, SMP, SND, SNDR, SNDT, SOU, SOX, SPH, TXW, U16, U24, U32, U8, UL, VMS, VOC, VORBIS, VOX, W64, WAV, WAVPCM, WV, WVE, XA, XI;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Endian {
|
|
||||||
LITTLE, BIG, SWAP;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
STANDARD ("-"), // -t must be given
|
|
||||||
PIPE ("-p"), // (--sox-pipe)
|
|
||||||
DEVICE ("-d"), // (--default-device)
|
|
||||||
NULL ("-n"); // (--null)
|
|
||||||
|
|
||||||
protected String code;
|
|
||||||
|
|
||||||
private Type(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect {
|
|
||||||
public String build() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.util;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
import javax.sound.sampled.AudioSystem;
|
|
||||||
import javax.sound.sampled.DataLine;
|
|
||||||
import javax.sound.sampled.Line;
|
|
||||||
import javax.sound.sampled.LineUnavailableException;
|
|
||||||
import javax.sound.sampled.Mixer;
|
|
||||||
import javax.sound.sampled.Port;
|
|
||||||
import javax.sound.sampled.Port.Info;
|
|
||||||
import javax.sound.sampled.SourceDataLine;
|
|
||||||
import javax.sound.sampled.TargetDataLine;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class Tool {
|
|
||||||
protected static Logger logger = LoggerFactory.getLogger(Tool.class);
|
|
||||||
|
|
||||||
protected static HashMap<String, Device<TargetDataLine>> targetMap;
|
|
||||||
protected static HashMap<String, Device<SourceDataLine>> sourceMap;
|
|
||||||
protected static ArrayList<String> portList;
|
|
||||||
|
|
||||||
protected static ArrayList<String> targetList;
|
|
||||||
protected static ArrayList<String> sourceList;
|
|
||||||
|
|
||||||
static {
|
|
||||||
Tool tool = new Tool();
|
|
||||||
|
|
||||||
targetMap = new HashMap<String, Device<TargetDataLine>>();
|
|
||||||
sourceMap = new HashMap<String, Device<SourceDataLine>>();
|
|
||||||
targetList = new ArrayList<String>();
|
|
||||||
sourceList = new ArrayList<String>();
|
|
||||||
portList = new ArrayList<String>();
|
|
||||||
|
|
||||||
for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
|
|
||||||
String name = mixerInfo.getName();
|
|
||||||
Mixer mixer = AudioSystem.getMixer(mixerInfo);
|
|
||||||
|
|
||||||
for (Line.Info lineInfo : mixer.getSourceLineInfo()) {
|
|
||||||
String lineClassName = lineInfo.getLineClass().getName();
|
|
||||||
if (lineClassName.equals("javax.sound.sampled.SourceDataLine")) {
|
|
||||||
if (mixer.isLineSupported(lineInfo)) {
|
|
||||||
logger.debug("<Source> " + name);
|
|
||||||
sourceMap.put(name, tool.new Device<SourceDataLine>(mixer, lineInfo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Line.Info lineInfo : mixer.getTargetLineInfo()) {
|
|
||||||
String lineClassName = lineInfo.getLineClass().getName();
|
|
||||||
if (lineClassName.equals("javax.sound.sampled.TargetDataLine")) {
|
|
||||||
if (mixer.isLineSupported(lineInfo)) {
|
|
||||||
logger.debug("<Target> " + name);
|
|
||||||
targetMap.put(name, tool.new Device<TargetDataLine>(mixer, lineInfo));
|
|
||||||
}
|
|
||||||
} else if (lineClassName.equals("javax.sound.sampled.Port")) {
|
|
||||||
name = name.substring(5);
|
|
||||||
try {
|
|
||||||
Port port = (Port) mixer.getLine(lineInfo);
|
|
||||||
Port.Info portInfo = (Info) port.getLineInfo();
|
|
||||||
if (!targetMap.containsKey(name) || portInfo.equals(Port.Info.LINE_OUT) || portInfo.equals(Port.Info.SPEAKER)) {
|
|
||||||
logger.debug("<Port> " + name);
|
|
||||||
portList.add(name);
|
|
||||||
}
|
|
||||||
} catch (LineUnavailableException e) {
|
|
||||||
logger.error("", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getTargets() {
|
|
||||||
return targetMap.keySet().toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getSources() {
|
|
||||||
return sourceMap.keySet().toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getPorts() {
|
|
||||||
return portList.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TargetDataLine getTargetDataLine(String name) throws LineUnavailableException {
|
|
||||||
if (targetMap.containsKey(name)) {
|
|
||||||
return targetMap.get(name).getLine();
|
|
||||||
} else {
|
|
||||||
throw new LineUnavailableException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TargetDataLine getTargetDataLine(String name, AudioFormat audioFormat) throws LineUnavailableException {
|
|
||||||
if (targetMap.containsKey(name)) {
|
|
||||||
return targetMap.get(name).getLine(audioFormat);
|
|
||||||
} else {
|
|
||||||
throw new LineUnavailableException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SourceDataLine getSourceDataLine(String name) throws LineUnavailableException {
|
|
||||||
if (sourceMap.containsKey(name)) {
|
|
||||||
return sourceMap.get(name).getLine();
|
|
||||||
} else {
|
|
||||||
throw new LineUnavailableException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SourceDataLine getSourceDataLine(String name, AudioFormat audioFormat) throws LineUnavailableException {
|
|
||||||
if (sourceMap.containsKey(name)) {
|
|
||||||
return sourceMap.get(name).getLine(audioFormat);
|
|
||||||
} else {
|
|
||||||
throw new LineUnavailableException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Device<T> {
|
|
||||||
protected Mixer mixer;
|
|
||||||
protected Line.Info lineInfo;
|
|
||||||
|
|
||||||
public Device(Mixer mixer, Line.Info lineInfo) {
|
|
||||||
this.mixer = mixer;
|
|
||||||
this.lineInfo = lineInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T getLine() throws LineUnavailableException {
|
|
||||||
return (T) mixer.getLine(lineInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public T getLine(AudioFormat audioFormat) throws LineUnavailableException {
|
|
||||||
DataLine.Info dataLineInfo = new DataLine.Info(lineInfo.getLineClass(), audioFormat);
|
|
||||||
return (T) mixer.getLine(dataLineInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package sound.util;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import javazoom.jl.decoder.JavaLayerException;
|
|
||||||
import javazoom.jl.player.Player;
|
|
||||||
|
|
||||||
public class Utils {
|
|
||||||
public static final int BUFFER = 2048; // bytes
|
|
||||||
|
|
||||||
public static void play(InputStream inputStream) {
|
|
||||||
try {
|
|
||||||
new Player(new BufferedInputStream(inputStream)).play();
|
|
||||||
} catch (JavaLayerException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void write(InputStream inputStream, File file) {
|
|
||||||
byte[] bytes = new byte[BUFFER];
|
|
||||||
int read = 0;
|
|
||||||
try {
|
|
||||||
FileOutputStream fileOutputStream = new FileOutputStream(file);
|
|
||||||
while ((read = inputStream.read(bytes)) > 0) {
|
|
||||||
fileOutputStream.write(bytes, 0, read);
|
|
||||||
}
|
|
||||||
fileOutputStream.close();
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
from pcm:
|
|
||||||
|
|
||||||
-r -s <freq in khz> [--unsigned] [--big-endian]
|
|
||||||
|
|
||||||
to mp3:
|
|
||||||
--cbr -b <bitrate>
|
|
||||||
|
|
||||||
|
|
||||||
mp3 to pcm:
|
|
||||||
--decode
|
|
||||||
|
|
||||||
always:
|
|
||||||
- - --quiet
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
LAME 32bits version 3.98.4 (http://www.mp3dev.org/)
|
|
||||||
|
|
||||||
usage: lame [options] <infile> [outfile]
|
|
||||||
|
|
||||||
<infile> and/or <outfile> can be "-", which means stdin/stdout.
|
|
||||||
|
|
||||||
RECOMMENDED:
|
|
||||||
lame -V2 input.wav output.mp3
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
Input options:
|
|
||||||
--scale <arg> scale input (multiply PCM data) by <arg>
|
|
||||||
--scale-l <arg> scale channel 0 (left) input (multiply PCM data) by <arg>
|
|
||||||
--scale-r <arg> scale channel 1 (right) input (multiply PCM data) by <arg>
|
|
||||||
--mp1input input file is a MPEG Layer I file
|
|
||||||
--mp2input input file is a MPEG Layer II file
|
|
||||||
--mp3input input file is a MPEG Layer III file
|
|
||||||
--nogap <file1> <file2> <...>
|
|
||||||
gapless encoding for a set of contiguous files
|
|
||||||
--nogapout <dir>
|
|
||||||
output dir for gapless encoding (must precede --nogap)
|
|
||||||
--nogaptags allow the use of VBR tags in gapless encoding
|
|
||||||
|
|
||||||
Input options for RAW PCM:
|
|
||||||
-r input is raw pcm
|
|
||||||
-x force byte-swapping of input
|
|
||||||
-s sfreq sampling frequency of input file (kHz) - default 44.1 kHz
|
|
||||||
--bitwidth w input bit width is w (default 16)
|
|
||||||
--signed input is signed (default)
|
|
||||||
--unsigned input is unsigned
|
|
||||||
--little-endian input is little-endian (default)
|
|
||||||
--big-endian input is big-endian
|
|
||||||
|
|
||||||
|
|
||||||
Operational options:
|
|
||||||
-a downmix from stereo to mono file for mono encoding
|
|
||||||
-m <mode> (j)oint, (s)imple, (f)orce, (d)dual-mono, (m)ono
|
|
||||||
default is (j) or (s) depending on bitrate
|
|
||||||
joint = joins the best possible of MS and LR stereo
|
|
||||||
simple = force LR stereo on all frames
|
|
||||||
force = force MS stereo on all frames.
|
|
||||||
--preset type type must be "medium", "standard", "extreme", "insane",
|
|
||||||
or a value for an average desired bitrate and depending
|
|
||||||
on the value specified, appropriate quality settings will
|
|
||||||
be used.
|
|
||||||
"--preset help" gives more info on these
|
|
||||||
--comp <arg> choose bitrate to achive a compression ratio of <arg>
|
|
||||||
--replaygain-fast compute RG fast but slightly inaccurately (default)
|
|
||||||
--replaygain-accurate compute RG more accurately and find the peak sample
|
|
||||||
--noreplaygain disable ReplayGain analysis
|
|
||||||
--clipdetect enable --replaygain-accurate and print a message whether
|
|
||||||
clipping occurs and how far the waveform is from full scale
|
|
||||||
--flush flush output stream as soon as possible
|
|
||||||
--freeformat produce a free format bitstream
|
|
||||||
--decode input=mp3 file, output=wav
|
|
||||||
-t disable writing wav header when using --decode
|
|
||||||
|
|
||||||
|
|
||||||
Verbosity:
|
|
||||||
--disptime <arg>print progress report every arg seconds
|
|
||||||
-S don't print progress report, VBR histograms
|
|
||||||
--nohist disable VBR histogram display
|
|
||||||
--silent don't print anything on screen
|
|
||||||
--quiet don't print anything on screen
|
|
||||||
--brief print more useful information
|
|
||||||
--verbose print a lot of useful information
|
|
||||||
|
|
||||||
Noise shaping & psycho acoustic algorithms:
|
|
||||||
-q <arg> <arg> = 0...9. Default -q 5
|
|
||||||
-q 0: Highest quality, very slow
|
|
||||||
-q 9: Poor quality, but fast
|
|
||||||
-h Same as -q 2. Recommended.
|
|
||||||
-f Same as -q 7. Fast, ok quality
|
|
||||||
|
|
||||||
|
|
||||||
CBR (constant bitrate, the default) options:
|
|
||||||
-b <bitrate> set the bitrate in kbps, default 128 kbps
|
|
||||||
--cbr enforce use of constant bitrate
|
|
||||||
|
|
||||||
ABR options:
|
|
||||||
--abr <bitrate> specify average bitrate desired (instead of quality)
|
|
||||||
|
|
||||||
VBR options:
|
|
||||||
-V n quality setting for VBR. default n=4
|
|
||||||
0=high quality,bigger files. 9=smaller files
|
|
||||||
-v the same as -V 4
|
|
||||||
--vbr-old use old variable bitrate (VBR) routine
|
|
||||||
--vbr-new use new variable bitrate (VBR) routine (default)
|
|
||||||
-b <bitrate> specify minimum allowed bitrate, default 32 kbps
|
|
||||||
-B <bitrate> specify maximum allowed bitrate, default 320 kbps
|
|
||||||
-F strictly enforce the -b option, for use with players that
|
|
||||||
do not support low bitrate mp3
|
|
||||||
-t disable writing LAME Tag
|
|
||||||
-T enable and force writing LAME Tag
|
|
||||||
|
|
||||||
|
|
||||||
PSY related:
|
|
||||||
--temporal-masking x x=0 disables, x=1 enables temporal masking effect
|
|
||||||
--nssafejoint M/S switching criterion
|
|
||||||
--nsmsfix <arg> M/S switching tuning [effective 0-3.5]
|
|
||||||
--interch x adjust inter-channel masking ratio
|
|
||||||
--ns-bass x adjust masking for sfbs 0 - 6 (long) 0 - 5 (short)
|
|
||||||
--ns-alto x adjust masking for sfbs 7 - 13 (long) 6 - 10 (short)
|
|
||||||
--ns-treble x adjust masking for sfbs 14 - 21 (long) 11 - 12 (short)
|
|
||||||
--ns-sfb21 x change ns-treble by x dB for sfb21
|
|
||||||
|
|
||||||
|
|
||||||
experimental switches:
|
|
||||||
-Y lets LAME ignore noise in sfb21, like in CBR
|
|
||||||
|
|
||||||
|
|
||||||
MP3 header/stream options:
|
|
||||||
-e <emp> de-emphasis n/5/c (obsolete)
|
|
||||||
-c mark as copyright
|
|
||||||
-o mark as non-original
|
|
||||||
-p error protection. adds 16 bit checksum to every frame
|
|
||||||
(the checksum is computed correctly)
|
|
||||||
--nores disable the bit reservoir
|
|
||||||
--strictly-enforce-ISO comply as much as possible to ISO MPEG spec
|
|
||||||
|
|
||||||
Filter options:
|
|
||||||
--lowpass <freq> frequency(kHz), lowpass filter cutoff above freq
|
|
||||||
--lowpass-width <freq> frequency(kHz) - default 15% of lowpass freq
|
|
||||||
--highpass <freq> frequency(kHz), highpass filter cutoff below freq
|
|
||||||
--highpass-width <freq> frequency(kHz) - default 15% of highpass freq
|
|
||||||
--resample <sfreq> sampling frequency of output file(kHz)- default=automatic
|
|
||||||
|
|
||||||
|
|
||||||
ID3 tag options:
|
|
||||||
--tt <title> audio/song title (max 30 chars for version 1 tag)
|
|
||||||
--ta <artist> audio/song artist (max 30 chars for version 1 tag)
|
|
||||||
--tl <album> audio/song album (max 30 chars for version 1 tag)
|
|
||||||
--ty <year> audio/song year of issue (1 to 9999)
|
|
||||||
--tc <comment> user-defined text (max 30 chars for v1 tag, 28 for v1.1)
|
|
||||||
--tn <track[/total]> audio/song track number and (optionally) the total
|
|
||||||
number of tracks on the original recording. (track
|
|
||||||
and total each 1 to 255. just the track number
|
|
||||||
creates v1.1 tag, providing a total forces v2.0).
|
|
||||||
--tg <genre> audio/song genre (name or number in list)
|
|
||||||
--ti <file> audio/song albumArt (jpeg/png/gif file, 128KB max, v2.3)
|
|
||||||
--tv <id=value> user-defined frame specified by id and value (v2.3 tag)
|
|
||||||
--add-id3v2 force addition of version 2 tag
|
|
||||||
--id3v1-only add only a version 1 tag
|
|
||||||
--id3v2-only add only a version 2 tag
|
|
||||||
--space-id3v1 pad version 1 tag with spaces instead of nulls
|
|
||||||
--pad-id3v2 same as '--pad-id3v2-size 128'
|
|
||||||
--pad-id3v2-size <value> adds version 2 tag, pad with extra <value> bytes
|
|
||||||
--genre-list print alphabetically sorted ID3 genre list and exit
|
|
||||||
--ignore-tag-errors ignore errors in values passed for tags
|
|
||||||
|
|
||||||
Note: A version 2 tag will NOT be added unless one of the input fields
|
|
||||||
won't fit in a version 1 tag (e.g. the title string is longer than 30
|
|
||||||
characters), or the '--add-id3v2' or '--id3v2-only' options are used,
|
|
||||||
or output is redirected to stdout.
|
|
||||||
|
|
||||||
|
|
||||||
MS-Windows-specific options:
|
|
||||||
--priority <type> sets the process priority:
|
|
||||||
0,1 = Low priority (IDLE_PRIORITY_CLASS)
|
|
||||||
2 = normal priority (NORMAL_PRIORITY_CLASS, default)
|
|
||||||
3,4 = High priority (HIGH_PRIORITY_CLASS))
|
|
||||||
Note: Calling '--priority' without a parameter will select priority 0.
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
--license print License information
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Platform specific:
|
|
||||||
--noasm <instructions> disable assembly optimizations for mmx/3dnow/sse
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MPEG-1 layer III sample frequencies (kHz): 32 48 44.1
|
|
||||||
bitrates (kbps): 32 40 48 56 64 80 96 112 128 160 192 224 256 320
|
|
||||||
|
|
||||||
MPEG-2 layer III sample frequencies (kHz): 16 24 22.05
|
|
||||||
bitrates (kbps): 8 16 24 32 40 48 56 64 80 96 112 128 144 160
|
|
||||||
|
|
||||||
MPEG-2.5 layer III sample frequencies (kHz): 8 12 11.025
|
|
||||||
bitrates (kbps): 8 16 24 32 40 48 56 64
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
|||||||
junk (with or without header)
|
|
||||||
PCM_SIGNED 8000.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian
|
|
||||||
-r 8k -t s16 -c 1 -e signed-integer
|
|
||||||
|
|
||||||
|
|
||||||
out (without header)
|
|
||||||
PCM_SIGNED 8000.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian
|
|
||||||
-r 128k -t s32 -c 2 -2 signed integer [reasonable]
|
|
||||||
|
|
||||||
out (without header)
|
|
||||||
PCM_SIGNED 192000.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian
|
|
||||||
-r 192k -t s16 -c 2 [-e signed-integer]
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package test;
|
|
||||||
|
|
||||||
import javax.sound.sampled.*;
|
|
||||||
public class SoundAudit {
|
|
||||||
public static void main(String[] args) { try {
|
|
||||||
System.out.println("OS: "+System.getProperty("os.name")+" "+
|
|
||||||
System.getProperty("os.version")+"/"+
|
|
||||||
System.getProperty("os.arch")+"\nJava: "+
|
|
||||||
System.getProperty("java.version")+" ("+
|
|
||||||
System.getProperty("java.vendor")+")\n");
|
|
||||||
for (Mixer.Info thisMixerInfo : AudioSystem.getMixerInfo()) {
|
|
||||||
System.out.println("Mixer: "+thisMixerInfo.getDescription()+
|
|
||||||
" ["+thisMixerInfo.getName()+"]");
|
|
||||||
Mixer thisMixer = AudioSystem.getMixer(thisMixerInfo);
|
|
||||||
for (Line.Info thisLineInfo:thisMixer.getSourceLineInfo()) {
|
|
||||||
if (thisLineInfo.getLineClass().getName().equals(
|
|
||||||
"javax.sound.sampled.Port")) {
|
|
||||||
Line thisLine = thisMixer.getLine(thisLineInfo);
|
|
||||||
thisLine.open();
|
|
||||||
System.out.println(" Source Port: "
|
|
||||||
+thisLineInfo.toString());
|
|
||||||
for (Control thisControl : thisLine.getControls()) {
|
|
||||||
System.out.println(AnalyzeControl(thisControl));}
|
|
||||||
thisLine.close();}}
|
|
||||||
for (Line.Info thisLineInfo:thisMixer.getTargetLineInfo()) {
|
|
||||||
if (thisLineInfo.getLineClass().getName().equals(
|
|
||||||
"javax.sound.sampled.Port")) {
|
|
||||||
Line thisLine = thisMixer.getLine(thisLineInfo);
|
|
||||||
thisLine.open();
|
|
||||||
System.out.println(" Target Port: "
|
|
||||||
+thisLineInfo.toString());
|
|
||||||
for (Control thisControl : thisLine.getControls()) {
|
|
||||||
System.out.println(AnalyzeControl(thisControl));}
|
|
||||||
thisLine.close();}}}
|
|
||||||
} catch (Exception e) {e.printStackTrace();}}
|
|
||||||
public static String AnalyzeControl(Control thisControl) {
|
|
||||||
String type = thisControl.getType().toString();
|
|
||||||
if (thisControl instanceof BooleanControl) {
|
|
||||||
return " Control: "+type+" (boolean)"; }
|
|
||||||
if (thisControl instanceof CompoundControl) {
|
|
||||||
System.out.println(" Control: "+type+
|
|
||||||
" (compound - values below)");
|
|
||||||
String toReturn = "";
|
|
||||||
for (Control children:
|
|
||||||
((CompoundControl)thisControl).getMemberControls()) {
|
|
||||||
toReturn+=" "+AnalyzeControl(children)+"\n";}
|
|
||||||
return toReturn.substring(0, toReturn.length()-1);}
|
|
||||||
if (thisControl instanceof EnumControl) {
|
|
||||||
return " Control:"+type+" (enum: "+thisControl.toString()+")";}
|
|
||||||
if (thisControl instanceof FloatControl) {
|
|
||||||
return " Control: "+type+" (float: from "+
|
|
||||||
((FloatControl) thisControl).getMinimum()+" to "+
|
|
||||||
((FloatControl) thisControl).getMaximum()+")";}
|
|
||||||
return " Control: unknown type";}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package test;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
|
|
||||||
import sound.Consumer;
|
|
||||||
import sound.Producer;
|
|
||||||
import sound.Source;
|
|
||||||
import sound.consumer.Port;
|
|
||||||
import sound.consumer.Shoutcast;
|
|
||||||
import sound.producer.Stream;
|
|
||||||
|
|
||||||
public class Test {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 48000f, 16, 2, 4, 48000f, true);
|
|
||||||
try {
|
|
||||||
//Producer p1 = new Target("Line-In (Creative SB X-Fi)");
|
|
||||||
//Producer p2 = new Target("Line 1 (Virtual Audio Cable)", audioFormat);
|
|
||||||
//p2.start();
|
|
||||||
Producer p3 = new Stream("http://ics2gss.omroep.nl:80/3fm-bb-mp3");
|
|
||||||
Producer p4 = new Stream("http://sc7.mystreamserver.com:8004");
|
|
||||||
|
|
||||||
Consumer c1 = new Source("Java Sound Audio Engine");
|
|
||||||
Consumer c2 = new Port("Speakers (Creative SB X-Fi)");
|
|
||||||
Consumer c3 = new Shoutcast();
|
|
||||||
//Consumer c4 = new Player();
|
|
||||||
//Consumer c5 = new Writer(new File("stream.out"));
|
|
||||||
|
|
||||||
//Utils.write(p3.getInputStream(), new File("stream.out"));
|
|
||||||
//Utils.play(p3.getInputStream());
|
|
||||||
c3.start(p4);
|
|
||||||
|
|
||||||
//while (true) {
|
|
||||||
//Thread.sleep(300000);
|
|
||||||
//c1.stop();
|
|
||||||
//}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package test.lines;
|
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
|
||||||
import javax.sound.sampled.AudioSystem;
|
|
||||||
import javax.sound.sampled.Line;
|
|
||||||
import javax.sound.sampled.LineUnavailableException;
|
|
||||||
import javax.sound.sampled.Mixer;
|
|
||||||
import javax.sound.sampled.SourceDataLine;
|
|
||||||
import javax.sound.sampled.TargetDataLine;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println(System.getProperty("javax.sound.sampled.SourceDataLine"));
|
|
||||||
|
|
||||||
new AudioFormat(44100, 16, 2, true, false);
|
|
||||||
|
|
||||||
for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
|
|
||||||
Mixer mixer = AudioSystem.getMixer(mixerInfo);
|
|
||||||
for (Line.Info lineInfo : mixer.getTargetLineInfo()) {
|
|
||||||
try {
|
|
||||||
Line line = mixer.getLine(lineInfo);
|
|
||||||
if (mixer.isLineSupported(lineInfo)) {
|
|
||||||
if (line instanceof TargetDataLine) {
|
|
||||||
new TargetLine(mixer, (TargetDataLine) line);
|
|
||||||
}/* else if (line instanceof SourceDataLine) {
|
|
||||||
new SourceLine(mixer, (SourceDataLine) line);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
} catch (LineUnavailableException e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package test.lines;
|
|
||||||
|
|
||||||
import javax.sound.sampled.Mixer;
|
|
||||||
import javax.sound.sampled.SourceDataLine;
|
|
||||||
|
|
||||||
public class SourceLine {
|
|
||||||
//private Mixer mixer;
|
|
||||||
private SourceDataLine line;
|
|
||||||
|
|
||||||
public SourceLine(Mixer mixer, SourceDataLine line) {
|
|
||||||
//this.mixer = mixer;
|
|
||||||
this.line = line;
|
|
||||||
System.out.println("SOURCE " + mixer.getMixerInfo().getName() + " || " + line.getLineInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int write(byte[] bytes, int offset, int length) {
|
|
||||||
return line.write(bytes, offset, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2016 Rik Veenboer <rik.veenboer@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package test.lines;
|
|
||||||
|
|
||||||
import javax.sound.sampled.Mixer;
|
|
||||||
import javax.sound.sampled.TargetDataLine;
|
|
||||||
|
|
||||||
public class TargetLine {
|
|
||||||
//private Mixer mixer;
|
|
||||||
private TargetDataLine line;
|
|
||||||
|
|
||||||
public TargetLine(Mixer mixer, TargetDataLine line) {
|
|
||||||
//this.mixer = mixer;
|
|
||||||
this.line = line;
|
|
||||||
System.out.println("TARGET " + mixer.getMixerInfo().getName() + " || " + line.getLineInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] bytes, int offset, int length) {
|
|
||||||
return line.read(bytes, offset, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user