diff --git a/main/src/main/java/com/sedmelluq/discord/lavaplayer/container/mp3/Mp3FrameReader.java b/main/src/main/java/com/sedmelluq/discord/lavaplayer/container/mp3/Mp3FrameReader.java index 31e2930e..0698c626 100644 --- a/main/src/main/java/com/sedmelluq/discord/lavaplayer/container/mp3/Mp3FrameReader.java +++ b/main/src/main/java/com/sedmelluq/discord/lavaplayer/container/mp3/Mp3FrameReader.java @@ -88,16 +88,22 @@ private int copyScanBufferEndToBeginning() { } private boolean parseFrameAt(int scanOffset) { - if (scanOffset >= HEADER_SIZE && (frameSize = Mp3Decoder.getFrameSize(scanBuffer, scanOffset - HEADER_SIZE)) > 0) { - for (int i = 0; i < HEADER_SIZE; i++) { - frameBuffer[i] = scanBuffer[scanOffset - HEADER_SIZE + i]; - } + int offset = scanOffset - HEADER_SIZE; + boolean invalid = offset < 0 + || !Mp3Decoder.hasFrameSync(scanBuffer, offset) + || Mp3Decoder.isUnsupportedVersion(scanBuffer, offset) + || !Mp3Decoder.isValidFrame(scanBuffer, offset); - frameBufferPosition = HEADER_SIZE; - return true; + if (invalid) + return false; + + frameSize = Mp3Decoder.getFrameSize(scanBuffer, offset); + for (int i = 0; i < HEADER_SIZE; i++) { + frameBuffer[i] = scanBuffer[offset + i]; } - return false; + frameBufferPosition = HEADER_SIZE; + return true; } /** diff --git a/main/src/main/java/com/sedmelluq/discord/lavaplayer/natives/mp3/Mp3Decoder.java b/main/src/main/java/com/sedmelluq/discord/lavaplayer/natives/mp3/Mp3Decoder.java index 6df56ac1..715f4aec 100644 --- a/main/src/main/java/com/sedmelluq/discord/lavaplayer/natives/mp3/Mp3Decoder.java +++ b/main/src/main/java/com/sedmelluq/discord/lavaplayer/natives/mp3/Mp3Decoder.java @@ -2,6 +2,8 @@ import com.sedmelluq.lava.common.natives.NativeResourceHolder; +import java.util.Arrays; + import java.nio.ByteBuffer; import java.nio.ShortBuffer; @@ -69,81 +71,7 @@ protected void freeResources() { } private static int getFrameBitRate(byte[] buffer, int offset) { - return isMpegVersionOne(buffer, offset) ? getFrameBitRateV1(buffer, offset) : getFrameBitRateV2(buffer, offset); - } - - private static int getFrameBitRateV1(byte[] buffer, int offset) { - switch ((buffer[offset + 2] & 0xF0) >>> 4) { - case 1: - return 32000; - case 2: - return 40000; - case 3: - return 48000; - case 4: - return 56000; - case 5: - return 64000; - case 6: - return 80000; - case 7: - return 96000; - case 8: - return 112000; - case 9: - return 128000; - case 10: - return 160000; - case 11: - return 192000; - case 12: - return 224000; - case 13: - return 256000; - case 14: - return 320000; - default: - throw new IllegalArgumentException("Not valid bitrate"); - } - } - - private static int getFrameBitRateV2(byte[] buffer, int offset) { - switch ((buffer[offset + 2] & 0xF0) >>> 4) { - case 1: - return 8000; - case 2: - return 16000; - case 3: - return 24000; - case 4: - return 32000; - case 5: - return 40000; - case 6: - return 48000; - case 7: - return 56000; - case 8: - return 64000; - case 9: - return 80000; - case 10: - return 96000; - case 11: - return 112000; - case 12: - return 128000; - case 13: - return 144000; - case 14: - return 160000; - default: - throw new IllegalArgumentException("Not valid bitrate"); - } - } - - private static int calculateFrameSize(boolean isVersionOne, int bitRate, int sampleRate, boolean hasPadding) { - return (isVersionOne ? 144 : 72) * bitRate / sampleRate + (hasPadding ? 1 : 0); + return MpegVersion.getVersion(buffer, offset).getBitRate(buffer, offset); } /** @@ -154,7 +82,7 @@ private static int calculateFrameSize(boolean isVersionOne, int bitRate, int sam * @return Sample rate */ public static int getFrameSampleRate(byte[] buffer, int offset) { - return isMpegVersionOne(buffer, offset) ? getFrameSampleRateV1(buffer, offset) : getFrameSampleRateV2(buffer, offset); + return MpegVersion.getVersion(buffer, offset).getSampleRate(buffer, offset); } /** @@ -168,30 +96,22 @@ public static int getFrameChannelCount(byte[] buffer, int offset) { return (buffer[offset + 3] & 0xC0) == 0xC0 ? 1 : 2; } - private static int getFrameSampleRateV1(byte[] buffer, int offset) { - switch ((buffer[offset + 2] & 0x0C) >>> 2) { - case 0: - return 44100; - case 1: - return 48000; - case 2: - return 32000; - default: - throw new IllegalArgumentException("Not valid sample rate"); - } + public static boolean hasFrameSync(byte[] buffer, int offset) { + // must start with 11 high bits + return (buffer[offset] & 0xFF) == 0xFF && (buffer[offset + 1] & 0xE0) == 0xE0; } - private static int getFrameSampleRateV2(byte[] buffer, int offset) { - switch ((buffer[offset + 2] & 0x0C) >>> 2) { - case 0: - return 22050; - case 1: - return 24000; - case 2: - return 16000; - default: - throw new IllegalArgumentException("Not valid sample rate"); - } + public static boolean isUnsupportedVersion(byte[] buffer, int offset) { + return (buffer[offset + 1] & 0x18) >> 3 == 0x01; + } + + public static boolean isValidFrame(byte[] buffer, int offset) { + int second = buffer[offset + 1] & 0xFF; + int third = buffer[offset + 2] & 0xFF; + return (second & 0x06) == 0x02 // Is Layer III + && (third & 0xF0) != 0x00 // Has defined bitrate + && (third & 0xF0) != 0xF0 // Valid bitrate + && (third & 0x0C) != 0x0C; // Valid sampling rate } /** @@ -202,26 +122,7 @@ private static int getFrameSampleRateV2(byte[] buffer, int offset) { * @return Frame size, or zero if not a valid frame header */ public static int getFrameSize(byte[] buffer, int offset) { - int first = buffer[offset] & 0xFF; - int second = buffer[offset + 1] & 0xFF; - int third = buffer[offset + 2] & 0xFF; - - boolean invalid = (first != 0xFF || (second & 0xE0) != 0xE0) // Frame sync does not match - || (second & 0x10) != 0x10 // Not MPEG-1 nor MPEG-2, not dealing with this stuff - || (second & 0x06) != 0x02 // Not Layer III, not dealing with this stuff - || (third & 0xF0) == 0x00 // No defined bitrate - || (third & 0xF0) == 0xF0 // Invalid bitrate - || (third & 0x0C) == 0x0C; // Invalid sampling rate - - if (invalid) { - return 0; - } - - int bitRate = getFrameBitRate(buffer, offset); - int sampleRate = getFrameSampleRate(buffer, offset); - boolean hasPadding = (third & 0x02) != 0; - - return calculateFrameSize(isMpegVersionOne(buffer, offset), bitRate, sampleRate, hasPadding); + return MpegVersion.getVersion(buffer, offset).getFrameSize(buffer, offset); } /** @@ -232,10 +133,7 @@ public static int getFrameSize(byte[] buffer, int offset) { * @return Average frame size, assuming CBR */ public static double getAverageFrameSize(byte[] buffer, int offset) { - int bitRate = getFrameBitRate(buffer, offset); - int sampleRate = getFrameSampleRate(buffer, offset); - - return (isMpegVersionOne(buffer, offset) ? 144.0 : 72.0) * bitRate / sampleRate; + return MpegVersion.getVersion(buffer, offset).getAverageFrameSize(buffer, offset); } /** @@ -244,14 +142,99 @@ public static double getAverageFrameSize(byte[] buffer, int offset) { * @return Number of samples per frame. */ public static long getSamplesPerFrame(byte[] buffer, int offset) { - return isMpegVersionOne(buffer, offset) ? MPEG1_SAMPLES_PER_FRAME : MPEG2_SAMPLES_PER_FRAME; - } - - private static boolean isMpegVersionOne(byte[] buffer, int offset) { - return (buffer[offset + 1] & 0x08) == 0x08; + return MpegVersion.getVersion(buffer, offset).getSamplesPerFrame(); } public static int getMaximumFrameSize() { - return calculateFrameSize(true, 320000, 32000, true); + return MpegVersion.MAX_FRAME_SIZE; + } + + private static final int[] SAMPLE_RATE_BASE = { 11025, 12000, 8000 }; + + public static enum MpegVersion { + + MPEG_1(4, 1152, new int[] { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 }), + MPEG_2(2, 576, new int[] { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 }), + MPEG_2_5(1, MPEG_2.samplesPerFrame, MPEG_2.bitrateIndex); + + public static final int MAX_FRAME_SIZE = getMaxFrameSize(); + + public static MpegVersion getVersion(byte[] buffer, int offset) { + // 0 - MPEG 2.5 + // 1 - reserved (unsupported) + // 2 - MPEG 2 + // 3 - MPEG 1 + int index = (buffer[offset + 1] & 0x18) >> 3; + switch (index) { + case 0: + return MPEG_2_5; + case 2: + return MPEG_2; + case 3: + return MPEG_1; + default: + throw new IllegalArgumentException("Invalid version"); + } + } + + private static int getMaxFrameSize() { + int bitRate = MPEG_1.bitrateIndex[MPEG_1.bitrateIndex.length - 1] * 1000; + int sampleRate = MPEG_1.samplerateIndex[1]; + return MPEG_1.calculateFrameSize(bitRate, sampleRate, true); + } + + private final int samplesPerFrame; + private final int frameLengthMultiplier; + private final int[] bitrateIndex; + private final int[] samplerateIndex; + + MpegVersion(int samplerateMultiplier, int samplesPerFrame, int[] bitrateIndex) { + this.samplesPerFrame = samplesPerFrame; + this.frameLengthMultiplier = samplesPerFrame / 8; + this.bitrateIndex = bitrateIndex; + this.samplerateIndex = Arrays.stream(SAMPLE_RATE_BASE).map(r -> r * samplerateMultiplier).toArray(); + } + + public int getSamplesPerFrame() { + return this.samplesPerFrame; + } + + public int getFrameLengthMultiplier() { + return this.frameLengthMultiplier; + } + + public int getBitRate(byte[] buffer, int offset) { + int index = (buffer[offset + 2] & 0xF0) >> 4; + if (index == 0 || index == 15) + throw new IllegalArgumentException("Invalid bitrate"); + + return this.bitrateIndex[index - 1] * 1000; + } + + public int getSampleRate(byte[] buffer, int offset) { + int index = (buffer[offset + 2] & 0x0C) >> 2; + if (index == 3) + throw new IllegalArgumentException("Invalid samplerate"); + + return this.samplerateIndex[index]; + } + + public int getFrameSize(byte[] buffer, int offset) { + return calculateFrameSize(getBitRate(buffer, offset), getSampleRate(buffer, offset), + hasPadding(buffer, offset)); + } + + public double getAverageFrameSize(byte[] buffer, int offset) { + return (double) getFrameLengthMultiplier() * getBitRate(buffer, offset) / getSampleRate(buffer, offset); + } + + private int calculateFrameSize(int bitRate, int sampleRate, boolean hasPadding) { + return getFrameLengthMultiplier() * bitRate / sampleRate + (hasPadding ? 1 : 0); + } + + private static boolean hasPadding(byte[] buffer, int offset) { + return (buffer[offset + 2] & 0x02) != 0; + } + } } diff --git a/natives/CMakeLists.txt b/natives/CMakeLists.txt index 031c3fbf..3db031c7 100644 --- a/natives/CMakeLists.txt +++ b/natives/CMakeLists.txt @@ -1,4 +1,5 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.12) +project(lpnatives C) add_subdirectory(samplerate) add_subdirectory(fdk-aac) diff --git a/natives/build.gradle b/natives/build.gradle index ee31cf4c..9eb05b41 100644 --- a/natives/build.gradle +++ b/natives/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'de.undercouch.download' + id "de.undercouch.download" version "5.4.0" } import org.apache.tools.ant.taskdefs.condition.Os @@ -8,26 +8,30 @@ import java.util.regex.Pattern apply from: 'natives.gradle' -ext.opusVersion = '1.3' -ext.mpg123Version = '1.25.10' -ext.oggVersion = '1.3.3' -ext.vorbisVersion = '1.3.6' -ext.sampleRateVersion = '0.1.9' -ext.fdkAacVersion = '2.0.0' +ext.opusVersion = '1.4' +ext.mpg123Version = '1.31.3' +ext.oggVersion = '1.3.5' +ext.vorbisVersion = '1.3.7' +ext.sampleRateVersion = '0.2.2' +ext.fdkAacVersion = '2.0.2' task load { doLast { if (!file("$projectDir/samplerate/src").exists()) { - def downloadPath = "$buildDir/tmp/libsamplerate.tar.gz" + def tarPath = "$buildDir/tmp/libsamplerate.tar" + def downloadPath = "${tarPath}.xz" def unpackPath = "$buildDir/tmp" - download.run { - src "https://www.mega-nerd.com/SRC/libsamplerate-${sampleRateVersion}.tar.gz" + src "https://github.com/libsndfile/libsamplerate/releases/download/${sampleRateVersion}/libsamplerate-${sampleRateVersion}.tar.xz" dest downloadPath } + exec { + commandLine('xz', '-d', downloadPath) + } + copy { - from tarTree(resources.gzip(downloadPath)) + from tarTree(file(tarPath)) into unpackPath } @@ -38,53 +42,47 @@ task load { } if (!file("$projectDir/fdk-aac/libAACdec").exists()) { - def downloadPath = "$buildDir/tmp/fdk-aac-v${fdkAacVersion}.zip" - def unpackPath = "$buildDir" - + def downloadPath = "$buildDir/tmp/fdk-aac-v${fdkAacVersion}.tar.gz" + def unpackPath = "$projectDir/fdk-aac" download.run { - src "https://github.com/mstorsjo/fdk-aac/archive/v${fdkAacVersion}.zip" + src "https://github.com/mstorsjo/fdk-aac/archive/v${fdkAacVersion}.tar.gz" dest downloadPath } copy { - from zipTree(file(downloadPath)) + from tarTree(file(downloadPath)) into unpackPath } - - copy { - from "$unpackPath/fdk-aac-${fdkAacVersion}" - into "$projectDir/fdk-aac" - } } if (!file("$projectDir/vorbis/libogg-${oggVersion}").exists()) { - def downloadPath = "$buildDir/tmp/temp.zip" - def unpackPath = "$buildDir" - + def downloadPath = "$buildDir/tmp/libogg.tar.gz" + def unpackPath = "$projectDir/vorbis" download.run { - src "https://downloads.xiph.org/releases/ogg/libogg-${oggVersion}.zip" + src "https://downloads.xiph.org/releases/ogg/libogg-${oggVersion}.tar.gz" dest downloadPath } copy { - from zipTree(file(downloadPath)) - into "$projectDir/vorbis" + from tarTree(file(downloadPath)) + into unpackPath } + downloadPath = "$buildDir/tmp/libvorbis.tar.gz" download.run { - src "https://downloads.xiph.org/releases/vorbis/libvorbis-${vorbisVersion}.zip" + src "https://downloads.xiph.org/releases/vorbis/libvorbis-${vorbisVersion}.tar.gz" dest downloadPath } copy { - from zipTree(file(downloadPath)) - into "$projectDir/vorbis" + from tarTree(file(downloadPath)) + into unpackPath } } if (!file("$projectDir/opus/opus-${opusVersion}").exists()) { - def downloadPath = "$buildDir/tmp/temp.tar.gz" - def unpackPath = "$buildDir" + def downloadPath = "$buildDir/tmp/libopus.tar.gz" + def unpackPath = "$projectDir/opus" download.run { src "https://downloads.xiph.org/releases/opus/opus-${opusVersion}.tar.gz" @@ -93,13 +91,13 @@ task load { copy { from tarTree(file(downloadPath)) - into "$projectDir/opus" + into unpackPath } } if (!Os.isFamily(Os.FAMILY_WINDOWS) && !file("$projectDir/mp3/mpg123-${mpg123Version}").exists()) { - def downloadPath = "$buildDir/tmp/temp.tar.bz2" - def unpackPath = "$buildDir" + def downloadPath = "$buildDir/tmp/libmpg123.tar.bz2" + def unpackPath = "$projectDir/mp3" download.run { src "https://www.mpg123.de/download/mpg123-${mpg123Version}.tar.bz2" @@ -108,7 +106,7 @@ task load { copy { from tarTree(file(downloadPath)) - into "$projectDir/mp3" + into unpackPath } } } @@ -198,27 +196,10 @@ def buildOpusOnLinux(force) { } } -def extractVersionPrefix(fullVersion, partCount) { - def parts = fullVersion.split('\\.').toList() - return parts.subList(0, Math.min(partCount, parts.size())).join('.') -} - -def replaceAutotoolsVersion(directory, originalVersion) { - def localVersion = (['automake', '--version'].execute().text =~ /\(GNU automake\) ([0-9.]+)/)[0][1] - def localMajorVersion = extractVersionPrefix(localVersion, 2) - def originalMajorVersion = extractVersionPrefix(originalVersion, 2) - - [file("$directory/aclocal.m4"), file("$directory/configure")].each { - it.text = it.text.replace("am__api_version='$originalMajorVersion'", "am__api_version='$localMajorVersion'").replace(originalVersion, localVersion) - } -} - def buildMpg123OnLinux(force) { def present = file("${projectDir}/libs/64/libmpg123.a").exists() if (force || !present) { - replaceAutotoolsVersion("$projectDir/mp3/mpg123-${mpg123Version}", '1.15.1') - def flags = "-fPIC -O3 -fdata-sections -ffunction-sections" def process = ['./configure', '--enable-static', '--with-cpu=x86-64', '--with-pic', "CFLAGS=$flags", "CXXFLAGS=$flags"]. execute(null as String[], file("$projectDir/mp3/mpg123-${mpg123Version}")) diff --git a/natives/connector/CMakeLists.txt b/natives/connector/CMakeLists.txt index 55bd66b7..0ef7bd77 100644 --- a/natives/connector/CMakeLists.txt +++ b/natives/connector/CMakeLists.txt @@ -38,11 +38,11 @@ set(CMAKE_CXX_FLAGS_RELEASE "${COMPILER_FLAGS} ${COMPILER_FLAGS_RELEASE}") include_directories("$ENV{JAVA_HOME}/include/") include_directories("${samplerate_SOURCE_DIR}/src") -include_directories("../opus/opus-1.3/include") -include_directories("../fdk-aac/libAACdec/include") -include_directories("../fdk-aac/libSYS/include") -include_directories("../vorbis/libvorbis-1.3.6/include") -include_directories("../vorbis/libogg-1.3.3/include") +include_directories("../opus/opus-1.4/include") +include_directories("../fdk-aac/fdk-aac-2.0.2/libAACdec/include") +include_directories("../fdk-aac/fdk-aac-2.0.2/libSYS/include") +include_directories("../vorbis/libvorbis-1.3.7/include") +include_directories("../vorbis/libogg-1.3.5/include") link_directories("../libs/64") if (DEFINED ENV{DIST_DIR}) diff --git a/natives/fdk-aac/CMakeLists.txt b/natives/fdk-aac/CMakeLists.txt index 2b785d7b..68bd1506 100644 --- a/natives/fdk-aac/CMakeLists.txt +++ b/natives/fdk-aac/CMakeLists.txt @@ -4,12 +4,14 @@ project(fdk-aac CXX) get_filename_component(ROOT_DIR "." ABSOLUTE) -set(MAIN_DIRS "${ROOT_DIR}/libAACdec" "${ROOT_DIR}/libFDK" "${ROOT_DIR}/libSYS" "${ROOT_DIR}/libMpegTPDec" "${ROOT_DIR}/libSBRdec" "${ROOT_DIR}/libPCMutils" "${ROOT_DIR}/libArithCoding" "${ROOT_DIR}/libDRCdec" "${ROOT_DIR}/libSACdec") +set(FDK_SOURCE "${ROOT_DIR}/fdk-aac-2.0.2") + +set(FDK_DIRS "${FDK_SOURCE}/libAACdec" "${FDK_SOURCE}/libFDK" "${FDK_SOURCE}/libSYS" "${FDK_SOURCE}/libMpegTPDec" "${FDK_SOURCE}/libSBRdec" "${FDK_SOURCE}/libPCMutils" "${FDK_SOURCE}/libArithCoding" "${FDK_SOURCE}/libDRCdec" "${FDK_SOURCE}/libSACdec") set(MAIN_SOURCES "") -message(STATUS "${MAIN_DIRS}") +message(STATUS "${FDK_DIRS}") -foreach(subdir ${MAIN_DIRS}) +foreach(subdir ${FDK_DIRS}) file (GLOB dir_sources "${subdir}/src/*.cpp" "${subdir}/src/*.h" "${subdir}/include/*.h") set (MAIN_SOURCES ${MAIN_SOURCES} ${dir_sources}) diff --git a/natives/samplerate/CMakeLists.txt b/natives/samplerate/CMakeLists.txt index 934b5da4..5ab8b102 100644 --- a/natives/samplerate/CMakeLists.txt +++ b/natives/samplerate/CMakeLists.txt @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.0) project(samplerate C) if(NOT ${CMAKE_C_COMPILER_ID} STREQUAL "MSVC") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fdata-sections -ffunction-sections") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fdata-sections -ffunction-sections -DHAVE_CONFIG_H") else() - set(CMAKE_C_FLAGS_RELEASE "/MT") + set(CMAKE_C_FLAGS_RELEASE "/MT /DHAVE_CONFIG_H") endif() include_directories(.) diff --git a/natives/samplerate/config.h b/natives/samplerate/config.h index 69b772ed..ef2e8c41 100644 --- a/natives/samplerate/config.h +++ b/natives/samplerate/config.h @@ -6,9 +6,10 @@ #define HAVE_LRINT 1 #define HAVE_LRINTF 1 #define HAVE_STDINT_H 1 +#define HAVE_STDBOOL_H 1 #define PACKAGE "libsamplerate" -#define VERSION "0.1.9" +#define VERSION "0.2.2" #ifdef _MSC_VER #define inline __inline diff --git a/natives/vorbis/CMakeLists.txt b/natives/vorbis/CMakeLists.txt index 1e1b4cc5..290733c7 100644 --- a/natives/vorbis/CMakeLists.txt +++ b/natives/vorbis/CMakeLists.txt @@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.0) project(vorbis C) get_filename_component(ROOT_DIR "." ABSOLUTE) -set(VORBIS_SOURCE "${ROOT_DIR}/libvorbis-1.3.6/lib") -set(OGG_SOURCE "${ROOT_DIR}/libogg-1.3.3/src") +set(VORBIS_SOURCE "${ROOT_DIR}/libvorbis-1.3.7/lib") +set(OGG_SOURCE "${ROOT_DIR}/libogg-1.3.5/src") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") set(CMAKE_C_FLAGS_RELEASE "/MT") @@ -17,8 +17,8 @@ file(GLOB MAIN_SOURCES "${VORBIS_SOURCE}/*.c" "${OGG_SOURCE}/*.c") list(REMOVE_ITEM MAIN_SOURCES "${VORBIS_SOURCE}/psytune.c") list(REMOVE_ITEM MAIN_SOURCES "${VORBIS_SOURCE}/tone.c") -include_directories("${ROOT_DIR}/libogg-1.3.3/include") -include_directories("${ROOT_DIR}/libvorbis-1.3.6/include") -include_directories("${ROOT_DIR}/libvorbis-1.3.6/lib") +include_directories("${ROOT_DIR}/libogg-1.3.5/include") +include_directories("${ROOT_DIR}/libvorbis-1.3.7/include") +include_directories("${ROOT_DIR}/libvorbis-1.3.7/lib") add_library(vorbis STATIC ${MAIN_SOURCES})