Showing preview only (921K chars total). Download the full file or copy to clipboard to get everything.
Repository: fanyuan/MyMp3Convert
Branch: master
Commit: 3c25cbd543da
Files: 100
Total size: 875.2 KB
Directory structure:
gitextract_rnfvjqig/
├── .gitignore
├── README.md
├── app/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── build.gradle
│ ├── key02.keystore
│ ├── proguard-rules.pro
│ ├── src/
│ │ ├── androidTest/
│ │ │ └── java/
│ │ │ └── com/
│ │ │ └── convert/
│ │ │ └── mymp3convert/
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── convert/
│ │ │ │ └── mymp3convert/
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── MainActivity2.kt
│ │ │ │ ├── Mp3ConvertUtil.java
│ │ │ │ ├── Mp3ConvertUtilHelper.java
│ │ │ │ ├── MyTest.java
│ │ │ │ └── test/
│ │ │ │ └── Demo.java
│ │ │ ├── jni/
│ │ │ │ ├── NativeMp3ConvertUtil.cpp
│ │ │ │ ├── NativeMp3ConvertUtil.cpp.bak
│ │ │ │ ├── NativeMp3ConvertUtil.h
│ │ │ │ ├── NativeMyTest.cpp
│ │ │ │ ├── com_convert_mymp3convert_Mp3ConvertUtil.h
│ │ │ │ ├── com_convert_mymp3convert_MyTest.h
│ │ │ │ └── libmp3lame/
│ │ │ │ ├── VbrTag.c
│ │ │ │ ├── VbrTag.h
│ │ │ │ ├── bitstream.c
│ │ │ │ ├── bitstream.h
│ │ │ │ ├── encoder.c
│ │ │ │ ├── encoder.h
│ │ │ │ ├── fft.c
│ │ │ │ ├── fft.h
│ │ │ │ ├── gain_analysis.c
│ │ │ │ ├── gain_analysis.h
│ │ │ │ ├── id3tag.c
│ │ │ │ ├── id3tag.h
│ │ │ │ ├── l3side.h
│ │ │ │ ├── lame-analysis.h
│ │ │ │ ├── lame.c
│ │ │ │ ├── lame.h
│ │ │ │ ├── lame_global_flags.h
│ │ │ │ ├── lameerror.h
│ │ │ │ ├── machine.h
│ │ │ │ ├── mpglib_interface.c
│ │ │ │ ├── newmdct.c
│ │ │ │ ├── newmdct.h
│ │ │ │ ├── presets.c
│ │ │ │ ├── psymodel.c
│ │ │ │ ├── psymodel.h
│ │ │ │ ├── quantize.c
│ │ │ │ ├── quantize.h
│ │ │ │ ├── quantize_pvt.c
│ │ │ │ ├── quantize_pvt.h
│ │ │ │ ├── reservoir.c
│ │ │ │ ├── reservoir.h
│ │ │ │ ├── set_get.c
│ │ │ │ ├── set_get.h
│ │ │ │ ├── tables.c
│ │ │ │ ├── tables.h
│ │ │ │ ├── takehiro.c
│ │ │ │ ├── util.c
│ │ │ │ ├── util.h
│ │ │ │ ├── vbrquantize.c
│ │ │ │ ├── vbrquantize.h
│ │ │ │ ├── version.c
│ │ │ │ └── version.h
│ │ │ ├── library/
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── drawable-v24/
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── layout/
│ │ │ │ ├── activity_main.xml
│ │ │ │ └── activity_main2.xml
│ │ │ ├── mipmap-anydpi-v26/
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── values/
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── themes.xml
│ │ │ └── values-night/
│ │ │ └── themes.xml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── convert/
│ │ └── mymp3convert/
│ │ └── ExampleUnitTest.java
│ └── 说明 .txt
├── build.gradle
├── demo/
│ ├── .gitignore
│ ├── build.gradle
│ ├── libs/
│ │ └── app-release.aar
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── convert/
│ │ └── demo/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── convert/
│ │ │ └── demo/
│ │ │ └── MainActivity.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ └── ic_launcher_background.xml
│ │ ├── drawable-v24/
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── layout/
│ │ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── values/
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ └── values-night/
│ │ └── themes.xml
│ └── test/
│ └── java/
│ └── com/
│ └── convert/
│ └── demo/
│ └── ExampleUnitTest.java
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
.idea/
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
================================================
FILE: README.md
================================================
# MyMp3Convert
mp3Convert
一个mp3转换库,基于lame3来实现
模块简介:
================================================
主要实现了wav格式向mp3格式的转投;
只需要关注3个方法就好;
为了项目简单直观实用,节省代码空间,本模块遵循单一职责原则,只做格式转换,把wav格式音频转换成mp3格式
使用场景:
================================================
用于在客户端需要把编辑好的wav转换成mp3格式,这样可以在不过大损失音频效果的同时有效节省空间,通常情况下,10M大小的wav文件通过转换后可以生成1M大小的mp3文件;
比如:用户在客户端录制好pcm音频文件,并由该文件编辑得到了可播放的wav文件,又需要把wav文件上传服务器,或者存在本地,但是wav文件过大,需要占用过大网络,在增加耗电量的同时,也给了服务器带来了压力,这个时候可以把文件转换成mp3格式文件(至于pcm到wav格式的转换,wav文件的编辑、剪切、拼接、混音合成可以使用另一模块来实现 链接:https://github.com/fanyuan/AudioUtil )
使用:
================================================
只需要调用Mp3ConvertUtilHelper里的3个公开方法即可;
使用很简单,只要把本module下载后以Android studio导入工程项目,设为library估其他module依赖就好
对于和native c语言的交互已在Mp3ConvertUtil中封装好,采用了外观模式;
使用时只需要调用Mp3ConvertUtilHelper类的相3个关公开方法
=====================华丽丽的分割线========================
3个相关方法如下:
================================================
/**
* wav转换成mp3
* @param wavInPath 需要转换的wav源文件输入路径
* @param mp3OutPath 转换完成后的mp3目标文件输出路径
*/
public static void convertmp3(String wavInPath, String mp3OutPath)
/**
* wav转换成mp3
* @param wavInPath 需要转换的wav源文件输入路径
* @param mp3OutPath 转换完成后的mp3目标文件输出路径
* @param callback 转换相关的回调
*/
public static void convertmp3(String wavInPath, String mp3OutPath, Mp3ConvertUtil.ConvertListener callback)}
/**
* 获取转换进度
* @param outPath 在多个任务并行时以输出路径为token来查询相关转换文件的转换进度
* @return
*/
public static int getProgress(String outPath)
=====================华丽丽的分割线==========================
使用示例如下:
温馨提示:使用时请在子线程中使用,为了演示方便直观就不过多封装了
不带转换回调的使用示例:
================================================
new Thread(){
@Override
public void run() {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/姑娘我爱你convert.wav";//"temp/test123.wav";
String pathTaret = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/姑娘我爱你out123.mp3";
Mp3ConvertUtilHelper.convertmp3(path,pathTaret);
}
}.start();
不带回调的获取转换进度的方式:
================================================
String pathTaret = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/姑娘我爱你out123.mp3";
int progress = Mp3ConvertUtilHelper.getProgress(pathTaret);
带转换回调的使用示例:
================================================
new Thread(){
@Override
public void run() {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out测试.wav";//"temp/test123.wav";
String pathTaret = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out测试789.mp3";
Mp3ConvertUtilHelper.convertmp3(path, pathTaret, new Mp3ConvertUtil.ConvertListener() {
@Override
public void notifyConvertProgress(int progress) {
Log.d("ddebug","convertByHelper02 --- notifyConvertProgress = " + progress);
}
@Override
public void convertFinish() {
Log.d("ddebug","convertByHelper02 --- convertFinish");
}
@Override
public void convertError(String errorMsg) {
Log.d("ddebug","convertByHelper02 --- convertError --- " + errorMsg);
}
});
}
}.start();
简单实用^_^
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/CMakeLists.txt
================================================
#指定CMake构建本地库时所需的最小版本
cmake_minimum_required(VERSION 3.4.1)
#该变量为真时会创建完整版本的Makefile
set(CMAKE_VERBOSE_MAKEFILE on)
set(LAME_LIBMP3_DIR ${CMAKE_SOURCE_DIR}/src/main/jni/libmp3lame)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLOGTEST")
include_directories(${CMAKE_SOURCE_DIR}/src/main/jni/libmp3lame)
include_directories(${CMAKE_SOURCE_DIR}/src/main/jni)
include_directories(E/work/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include)
add_library( # Sets the name of the library. 将资源文件生成动态链接库(so文件)的库名称(文件名称:“lib" +设置的名称)
hello
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).资源文件(C或C++)的相对位置
src/main/jni/NativeMp3ConvertUtil.cpp
src/main/jni/NativeMyTest.cpp)
# 这里用来添加一个库
add_library(# 这里设置so库的名称为native-lib
libmp3lame
# 这里设置该库为共享
SHARED
#源码文件
${LAME_LIBMP3_DIR}/bitstream.c
${LAME_LIBMP3_DIR}/encoder.c
${LAME_LIBMP3_DIR}/fft.c
${LAME_LIBMP3_DIR}/gain_analysis.c
${LAME_LIBMP3_DIR}/id3tag.c
${LAME_LIBMP3_DIR}/lame.c
${LAME_LIBMP3_DIR}/mpglib_interface.c
${LAME_LIBMP3_DIR}/newmdct.c
${LAME_LIBMP3_DIR}/presets.c
${LAME_LIBMP3_DIR}/psymodel.c
${LAME_LIBMP3_DIR}/quantize.c
${LAME_LIBMP3_DIR}/quantize_pvt.c
${LAME_LIBMP3_DIR}/reservoir.c
${LAME_LIBMP3_DIR}/set_get.c
${LAME_LIBMP3_DIR}/tables.c
${LAME_LIBMP3_DIR}/takehiro.c
${LAME_LIBMP3_DIR}/util.c
${LAME_LIBMP3_DIR}/vbrquantize.c
${LAME_LIBMP3_DIR}/VbrTag.c
${LAME_LIBMP3_DIR}/version.c
)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.将所有的add_library中的库链接起来,有多少个add_library成的库就将其添加到这里
hello #这个和add_library中的指定的so库名称一致
libmp3lame
# Links the target library to the log library
# included in the NDK.
${log-lib} )
================================================
FILE: app/build.gradle
================================================
//plugins {
// id 'com.android.application'
//}
if(isAppLibrary.toBoolean()){
apply plugin: 'com.android.library'
}else {
apply plugin: 'com.android.application'
}
apply plugin: 'kotlin-android'
android {
externalNativeBuild { cmake { version "3.10.2" } }
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
if(!isAppLibrary.toBoolean()){
applicationId "com.convert.mymp3convert"
}
minSdkVersion 18
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
// 指定一些编译选项
cppFlags "-std=c++11 -frtti -fexceptions"
cFlags "-DSTDC_HEADERS"
abiFilters 'armeabi-v7a','arm64-v8a','x86'//'armeabi',
}
}
ndk{
//moduleName"hello" //生成的so文件名字,调用C程序的代码中会用到该名字
abiFilters 'armeabi-v7a','arm64-v8a' , 'x86'//,'arm64-v8a', 'x86_64'//'armeabi',
}
signingConfigs {
release {
storeFile file("key02.keystore")
storePassword "1qazxsw2"
keyAlias "key02"
keyPassword "1qazxsw2"
v1SigningEnabled true
v2SigningEnabled true
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
signingConfigs {
dev {
storeFile file('E:\\work\\keyStore\\demo\\key02.keystore')
storePassword '1qazxsw2'
keyAlias 'key02'
keyPassword '1qazxsw2'
}
}
sourceSets{
main{
if(isAppLibrary.toBoolean()){
manifest.srcFile 'src/main/library/AndroidManifest.xml'
}else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
jniDebuggable true
signingConfig signingConfigs.release
}
dev {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
jniDebuggable true
debuggable true
signingConfig signingConfigs.release
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: app/src/androidTest/java/com/convert/mymp3convert/ExampleInstrumentedTest.java
================================================
package com.convert.mymp3convert;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.convert.mymp3convert", appContext.getPackageName());
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.convert.mymp3convert">
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyMp3Convert">
<activity android:name=".MainActivity2"></activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
================================================
FILE: app/src/main/java/com/convert/mymp3convert/MainActivity.java
================================================
package com.convert.mymp3convert;
import android.Manifest;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.io.File;
public class MainActivity extends AppCompatActivity {
TextView tv;
String [] perms = {Manifest.permission.MODIFY_AUDIO_SETTINGS,Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tv);
String msg = Mp3ConvertUtil.hello("test");
tv.setText(msg);
Log.d("ddebug","hello jni = " + msg);
ActivityCompat.requestPermissions(this, perms, 123);
}
public void test(View v){
String str = MyTest.test();
tv.append("\n"+str);
Log.d("ddebug","test str = " + "str" + "----" + Mp3ConvertUtil.getLameVer());
//Mp3ConvertUtil.convertmp3("test.wav","demo.mp3");
}
public void convert(View v){
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out.wav";//"temp/test123.wav";
String pathTaret = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out123.mp3";
Mp3ConvertUtil.convertmp3(path,pathTaret);
}
public void convertByHelper01(View v){
// String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out.wav";//"temp/test123.wav";
// String pathTaret = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out456.mp3";
// Mp3ConvertUtilHelper.convertmp3(path,pathTaret);
new Thread(){
@Override
public void run() {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/姑娘我爱你convert.wav";//"temp/test123.wav";
String pathTaret = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/姑娘我爱你out123.mp3";
Mp3ConvertUtilHelper.convertmp3(path,pathTaret);
}
}.start();
}
public void convertByHelper02(View v){
new Thread(){
@Override
public void run() {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out测试.wav";//"temp/test123.wav";
String pathTaret = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "temp/out测试789.mp3";
Mp3ConvertUtilHelper.convertmp3(path, pathTaret, new Mp3ConvertUtil.ConvertListener() {
@Override
public void notifyConvertProgress(int progress) {
Log.d("ddebug","convertByHelper02 --- notifyConvertProgress = " + progress);
}
@Override
public void convertFinish() {
Log.d("ddebug","convertByHelper02 --- convertFinish");
}
@Override
public void convertError(String errorMsg) {
Log.d("ddebug","convertByHelper02 --- convertError --- " + errorMsg);
}
});
}
}.start();
}
}
================================================
FILE: app/src/main/java/com/convert/mymp3convert/MainActivity2.kt
================================================
package com.convert.mymp3convert
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
}
}
================================================
FILE: app/src/main/java/com/convert/mymp3convert/Mp3ConvertUtil.java
================================================
package com.convert.mymp3convert;
import android.util.Log;
import java.util.concurrent.ConcurrentHashMap;
public class Mp3ConvertUtil {
static {
System.loadLibrary("hello");
System.loadLibrary("libmp3lame");
}
public static native String hello(String msg);
/**
* 获取LAME的版本信息
*
* @return
*/
public static native String getLameVer();
/**
* wav转换成mp3的本地方法
*
* @param wav
* @param mp3
*/
public static native void convertmp3(String wav, String mp3);
/**
* 转换接口回调
*/
public interface ConvertListener{
public void notifyConvertProgress(int progress);
/**
* 转换完成回调
*/
public void convertFinish();
/**
* 转换完成回调
* @param errorMsg
*/
public void convertError(String errorMsg);
}
/**
* 提供的一个空实现
*/
public static class SimpleConvertListener implements ConvertListener{
@Override
public void notifyConvertProgress(int progress) {
}
@Override
public void convertFinish() {
}
@Override
public void convertError(String errorMsg) {
}
}
/**
* 保存进度的地方
*/
static ConcurrentHashMap<String,ConvertListener> mConvertCallbacks;
/**
* 保存进度的地方
*/
static ConcurrentHashMap<String,Integer> mProgresses;
/**
* 注册转换回调类
* @param mp3TargetPath
* @param callback
*/
protected static void registerCallback(String mp3TargetPath,ConvertListener callback){
if(mConvertCallbacks == null){
mConvertCallbacks = new ConcurrentHashMap<String, ConvertListener>();
}
mConvertCallbacks.put(mp3TargetPath,callback);
}
/**
* 移除转换回调类
* @param mp3TargetPath
*/
private static void removeCallback(String mp3TargetPath){
if(mConvertCallbacks == null){
return;
}
if(mConvertCallbacks.containsKey(mp3TargetPath)){
mConvertCallbacks.remove(mp3TargetPath);
}
}
/**
* 设置进度的方法
* @param outPath
*/
private static void setProgress(String outPath,int progress){
if(mProgresses == null){
mProgresses = new ConcurrentHashMap<String, Integer>();
}
mProgresses.put(outPath,progress);
Log.d("ddebug","---setProgress---" + outPath + "=" + progress);
}
/**
* 获取进度的方法
* @param outPath
* @return
*/
protected static int getProgress(String outPath){
if(mProgresses == null){
return -1;
}
if(!mProgresses.containsKey(outPath)){
return -1;
}
int progress = mProgresses.get(outPath);
Log.d("ddebug","---getProgress---" + outPath + "=" + progress);
return progress;
}
/**
* 移除相关进度条目的方法
*
* @param outPath
*/
private static void removeProgress(String outPath){
if(mProgresses == null){
return;
}
mProgresses.remove(outPath);
Log.d("ddebug","---removeProgress---" + outPath);
}
/**
* 日志打印方法,提供给C语言调用
*
* @param
*/
public static void nativeLog(String logTag,String logMsg) {
Log.d(logTag,"java nativeLog:" + logMsg);
}
/**
* 设置进度条的进度,提供给C语言调用
*
* @param progress
*/
public static void setConvertProgress(int progress,String outPath) {
setProgress(outPath,progress);
if(mConvertCallbacks == null){
mConvertCallbacks = new ConcurrentHashMap<String, ConvertListener>();
}
if(mConvertCallbacks.containsKey(outPath)){
mConvertCallbacks.get(outPath).notifyConvertProgress(progress);
}
Log.d("ddebug","转换进度为:"+ progress);
}
/**
* 转换完成回调,提供给C语言调用
*
* @param outPath
*/
public static void convertFinish(String outPath) {
removeProgress(outPath);
if(mConvertCallbacks == null){
return;
}
if(mConvertCallbacks.containsKey(outPath)){
mConvertCallbacks.get(outPath).convertFinish();
removeCallback(outPath);
}
Log.d("ddebug","转换完成 convertFinish:"+ outPath);
}
/**
* 转换完成回调,提供给C语言调用
*
* @param outPath
*/
public static void convertError(String errorMsg,String outPath) {
removeProgress(outPath);
if(mConvertCallbacks == null){
return;
}
if(mConvertCallbacks.containsKey(outPath)){
mConvertCallbacks.get(outPath).convertError(errorMsg);
removeCallback(outPath);
}
Log.d("ddebug","java convertError:" + errorMsg + " --- " + outPath);
}
}
================================================
FILE: app/src/main/java/com/convert/mymp3convert/Mp3ConvertUtilHelper.java
================================================
package com.convert.mymp3convert;
public class Mp3ConvertUtilHelper {
/**
* 获取版本号
* @return
*/
public static String getVer(){
return Mp3ConvertUtil.getLameVer();
}
/**
* wav转换成mp3
* @param wavInPath 需要转换的wav源文件输入路径
* @param mp3OutPath 转换完成后的mp3目标文件输出路径
*/
public static void convertmp3(String wavInPath, String mp3OutPath){
Mp3ConvertUtil.convertmp3(wavInPath,mp3OutPath);
}
/**
* wav转换成mp3
* @param wavInPath 需要转换的wav源文件输入路径
* @param mp3OutPath 转换完成后的mp3目标文件输出路径
* @param callback 转换相关的回调
*/
public static void convertmp3(String wavInPath, String mp3OutPath, Mp3ConvertUtil.ConvertListener callback){
Mp3ConvertUtil.registerCallback(mp3OutPath,callback);
Mp3ConvertUtil.convertmp3(wavInPath,mp3OutPath);
}
/**
* 获取转换进度
* @param outPath 在多个任务并行时以输出路径为token来查询相关转换文件的转换进度
* @return
*/
public static int getProgress(String outPath){
return Mp3ConvertUtil.getProgress(outPath);
}
}
================================================
FILE: app/src/main/java/com/convert/mymp3convert/MyTest.java
================================================
package com.convert.mymp3convert;
public class MyTest {
public static native String test();
}
================================================
FILE: app/src/main/java/com/convert/mymp3convert/test/Demo.java
================================================
package com.convert.mymp3convert.test;
import com.convert.mymp3convert.Mp3ConvertUtil;
public class Demo {
private void test(){
//Mp3ConvertUtil.registerCallback("",null);
}
}
================================================
FILE: app/src/main/jni/NativeMp3ConvertUtil.cpp
================================================
//
// Created by shaomingfa on 2021/1/14.
//
#include <string>
#include "libmp3lame/lame.h"
#include <jni.h>
#include<stdio.h>
#include<malloc.h>
#include<lame.h>
#include<android/log.h>
#include "libmp3lame/lame.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "NativeMp3ConvertUtil.h"
#include "com_convert_mymp3convert_Mp3ConvertUtil.h"
#define LOG_TAG "System.out.c"
/**
* 日志打印tag
*/
#define CONVERT_LOG_TAG "nativeTag"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#ifndef com_convert_mymp3convert_Mp3ConvertUtil
#define com_convert_mymp3convert_Mp3ConvertUtil
#ifdef __cplusplus
extern "C" {
#endif
/**
* 返回值 char* 这个代表char数组的首地址
* Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串
*/
char* Jstring2CStr(JNIEnv *env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env).FindClass( "java/lang/String"); //String
jstring strencode = (*env).NewStringUTF( "GB2312"); // 得到一个java字符串 "GB2312"
jmethodID mid = (*env).GetMethodID(clsstring, "getBytes",
"(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");
jbyteArray barr = (jbyteArray)(*env).CallObjectMethod(jstr, mid,
strencode); // String .getByte("GB2312");
jsize alen = (*env).GetArrayLength( barr); // byte数组的长度
jbyte* ba = (*env).GetByteArrayElements( barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env).ReleaseByteArrayElements(barr, ba, 0); //
(*env).DeleteLocalRef(strencode);
return rtn;
}
/**==============================================================================================================================================*/
/**
* 调用java代码 更新程序的进度条
*/
void publishJavaProgress(JNIEnv * env, jobject obj, jint progress,jstring outPath) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
LOGI(" convert progress %d" , progress);
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"setConvertProgress","(ILjava/lang/String;)V");//jmethodID methodid = (*env).GetMethodID(clazz, "setConvertProgress","(I)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find methodid");
//3 .调用方法
(*env).CallStaticVoidMethod(clazz, methodid, progress,outPath);//(*env).CallVoidMethod(obj, methodid, progress);
//env -> CallVoidMethod(obj,methodid,progress);
env->DeleteLocalRef(clazz);
//env->DeleteLocalRef(methodid);
}
/**
* 调用java代码 更新程序的进度条
*/
void convertFinish(JNIEnv * env, jstring mp3Path) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
const char *c = env->GetStringUTFChars(mp3Path, JNI_FALSE);
LOGI(" convert finished %s" , c);
env->ReleaseStringUTFChars(mp3Path,c);
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"convertFinish","(Ljava/lang/String;)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find convertFinish methodid");
//3 .调用方法
env -> CallStaticVoidMethod(clazz,methodid,mp3Path);
env->DeleteLocalRef(clazz);
}
/**
* 调用java代码 转换失败时调用
*/
void convertError(JNIEnv * env,jstring msg,jstring mp3Path) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
const char *c = (*env).GetStringUTFChars(mp3Path, JNI_FALSE);
LOGI(" convert error %s" , c);
(*env).ReleaseStringUTFChars(mp3Path,c);
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"convertError",
"(Ljava/lang/String;Ljava/lang/String;)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find methodid");
//3 .调用方法
env -> CallStaticVoidMethod(clazz,methodid,msg,mp3Path);
env->DeleteLocalRef(clazz);
}
/**
* 调用java代码 打印日志时调用
*/
void nativeLog(JNIEnv * env, jstring msg) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"nativeLog",
"(Ljava/lang/String;Ljava/lang/String;)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find methodid");
jstring logTag = env->NewStringUTF(CONVERT_LOG_TAG);
//3 .调用方法
env -> CallStaticVoidMethod(clazz,methodid,logTag,msg);
env->DeleteLocalRef(logTag);
env->DeleteLocalRef(clazz);
}
/**
* 字符串拼接
* @param env
* @param cstr
* @param jstr
* @return
*/
jstring jstrCat(JNIEnv *env,char * cstr,jstring jstr){
char *c =(char *)(*env).GetStringUTFChars(jstr,JNI_FALSE);
char * bf = new char[strlen(cstr) + strlen(c) +1];
memcpy(bf, cstr, strlen(cstr) + 1);
strcat(bf, c);
jstring js = env->NewStringUTF(bf);
delete [] bf;
(*env).ReleaseStringUTFChars(jstr,c);
return js;
}
/**
* 获取文件的大小
* @param filename
* @return
*/
long long file_size(char* filename){
struct stat statbuf;
stat(filename,&statbuf);
return statbuf.st_size;
}
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: hello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_Mp3ConvertUtil_hello
(JNIEnv *env, jclass obj, jstring str){
jstring js = env->NewStringUTF("/sd/mp3");
publishJavaProgress(env,obj,123,js);
env->DeleteLocalRef(js);
jstring jstr = env->NewStringUTF("/sd/m/mp3");
convertFinish(env,jstr);
env->DeleteLocalRef(jstr);
jstring msg = env->NewStringUTF("xxx原因导致了未转换成功");
convertError(env, msg, msg);
env->DeleteLocalRef(msg);
LOGD("lame ver = %s",get_lame_very_short_version());
LOGI("convertmp3 %S === %S","wav","mp3");
LOGD("CONVERT %S","test");
return env->NewStringUTF("Hello From JNI!");//
}
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: getLameVer
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_com_convert_mymp3convert_Mp3ConvertUtil_getLameVer(JNIEnv *env, jclass obj) {
LOGD("CONVERT 123321 测试 S ");
LOGD("CONVERT 123321 测试 S --- %d",123);
LOGD("CONVERT 123321 测试 S --- %s","test");
return (*env).NewStringUTF(get_lame_version());
}
//int flag = 0;
/**
*wav转换mp3
* @param env
* @param obj
* @param wav
* @param mp3
*/
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: convertmp3
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
Java_com_convert_mymp3convert_Mp3ConvertUtil_convertmp3(JNIEnv *env, jclass obj, jstring wav,jstring mp3) {
char* cwav = const_cast<char *>(env->GetStringUTFChars(wav, JNI_FALSE));//Jstring2CStr(env,wav) ;
char* cmp3= const_cast<char *>(env->GetStringUTFChars(mp3, JNI_FALSE));//Jstring2CStr(env,mp3);
LOGI("wav = %s", cwav);
LOGI("mp3 = %s", cmp3);
char buf[2048] = {};
sprintf(buf, "source:%s,target:%s ", cwav,cmp3);
LOGD(buf,NULL);
if(access(cwav,F_OK) == -1){
free(cwav);
free(cmp3);
LOGD("转换源文件不存在");
jstring msg = jstrCat(env,"转换源文件不存在:",mp3);
nativeLog(env, msg);
convertError(env,msg,mp3);
env->DeleteLocalRef(msg);
return;
}
long long fileSize = file_size(cwav);
if (fileSize == 0) {
free(cwav);
free(cmp3);
jstring msg = jstrCat(env,"转换源文件大小为0:",mp3);
nativeLog(env, msg);
convertError(env,msg,mp3);
env->DeleteLocalRef(msg);
return;
}
//1.打开 wav,MP3文件
FILE* fwav = fopen(cwav,"rb");
FILE* fmp3 = fopen(cmp3,"wb");
short int wav_buffer[8192*2]= {};
unsigned char mp3_buffer[8192] = {};
//1.初始化lame的编码器
lame_t lame = lame_init();
//2. 设置lame mp3编码的采样率
lame_set_in_samplerate(lame , 44100);
lame_set_num_channels(lame,2);
// 3. 设置MP3的编码方式
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
LOGI("lame init finish");
int read ; int write; //代表读了多少个次 和写了多少次
long long total=0; // 当前读的wav文件的byte数目
LOGD("FILE SIZE = %d",fileSize);
int progress = 0;
do{
// if(flag==404){
// return;
// }
read = fread(wav_buffer,sizeof(short int)*2, 8192,fwav);
total += read* sizeof(short int)*2;
LOGI("converting ....%d", total);
int tmpProgress = (total*100)/fileSize;
LOGD("converting size = %d",tmpProgress);
if(tmpProgress != progress){
progress = tmpProgress;
publishJavaProgress(env,obj,progress,mp3);
}
// 调用java代码 完成进度条的更新
if(read!=0){
write = lame_encode_buffer_interleaved(lame,wav_buffer,read,mp3_buffer,8192);
//把转化后的mp3数据写到文件里
fwrite(mp3_buffer,sizeof(unsigned char),write,fmp3);
}
if(read==0){
write = lame_encode_flush(lame,mp3_buffer,8192);
fwrite(mp3_buffer,sizeof(unsigned char),write,fmp3);
}
}while(read!=0);
lame_close(lame);
fclose(fwav);
fclose(fmp3);
env->ReleaseStringUTFChars(wav,cwav);
env->ReleaseStringUTFChars(mp3,cmp3);
convertFinish(env,mp3);
LOGI("convert finish");
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: app/src/main/jni/NativeMp3ConvertUtil.cpp.bak
================================================
//
// Created by shaomingfa on 2021/1/14.
//
#include <string>
#include "libmp3lame/lame.h"
#include <jni.h>
#include<stdio.h>
#include<malloc.h>
#include<lame.h>
#include<android/log.h>
#include "libmp3lame/lame.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "NativeMp3ConvertUtil.h"
#include "com_convert_mymp3convert_Mp3ConvertUtil.h"
#define LOG_TAG "System.out.c"
/**
* 日志打印tag
*/
#define CONVERT_LOG_TAG "nativeTag"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#ifndef com_convert_mymp3convert_Mp3ConvertUtil
#define com_convert_mymp3convert_Mp3ConvertUtil
#ifdef __cplusplus
extern "C" {
#endif
/**
* 返回值 char* 这个代表char数组的首地址
* Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串
*/
char* Jstring2CStr(JNIEnv *env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env).FindClass( "java/lang/String"); //String
jstring strencode = (*env).NewStringUTF( "GB2312"); // 得到一个java字符串 "GB2312"
jmethodID mid = (*env).GetMethodID(clsstring, "getBytes",
"(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312");
jbyteArray barr = (jbyteArray)(*env).CallObjectMethod(jstr, mid,
strencode); // String .getByte("GB2312");
jsize alen = (*env).GetArrayLength( barr); // byte数组的长度
jbyte* ba = (*env).GetByteArrayElements( barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env).ReleaseByteArrayElements(barr, ba, 0); //
(*env).DeleteLocalRef(strencode);
return rtn;
}
/**==============================================================================================================================================*/
/**
* 调用java代码 更新程序的进度条
*/
void publishJavaProgress(JNIEnv * env, jobject obj, jint progress,jstring outPath) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
LOGI(" convert progress %d" , progress);
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"setConvertProgress","(ILjava/lang/String;)V");//jmethodID methodid = (*env).GetMethodID(clazz, "setConvertProgress","(I)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find methodid");
//3 .调用方法
(*env).CallStaticVoidMethod(clazz, methodid, progress,outPath);//(*env).CallVoidMethod(obj, methodid, progress);
//env -> CallVoidMethod(obj,methodid,progress);
env->DeleteLocalRef(clazz);
//env->DeleteLocalRef(methodid);
}
/**
* 调用java代码 更新程序的进度条
*/
void convertFinish(JNIEnv * env, jstring mp3Path) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
const char *c = env->GetStringUTFChars(mp3Path, JNI_FALSE);
LOGI(" convert finished %s" , c);
env->ReleaseStringUTFChars(mp3Path,c);
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"convertFinish","(Ljava/lang/String;)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find convertFinish methodid");
//3 .调用方法
env -> CallStaticVoidMethod(clazz,methodid,mp3Path);
env->DeleteLocalRef(clazz);
}
/**
* 调用java代码 转换失败时调用
*/
void convertError(JNIEnv * env,jstring msg,jstring mp3Path) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
const char *c = (*env).GetStringUTFChars(mp3Path, JNI_FALSE);
LOGI(" convert error %s" , c);
(*env).ReleaseStringUTFChars(mp3Path,c);
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"convertError",
"(Ljava/lang/String;Ljava/lang/String;)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find methodid");
//3 .调用方法
env -> CallStaticVoidMethod(clazz,methodid,msg,mp3Path);
env->DeleteLocalRef(clazz);
}
/**
* 调用java代码 打印日志时调用
*/
void nativeLog(JNIEnv * env, jstring msg) {
//1.找到java的LameUtils的class com/example/myjnidemo/
jclass clazz = (*env).FindClass("com/convert/mymp3convert/Mp3ConvertUtil");
if (clazz == 0) {
LOGI("can't find clazz");
return;
}
//2 找到class 里面的方法定义
jmethodID methodid = (*env).GetStaticMethodID(clazz,"nativeLog",
"(Ljava/lang/String;Ljava/lang/String;)V");
if (methodid == 0) {
LOGI("can't find methodid");
return;
}
LOGI(" find methodid");
jstring logTag = env->NewStringUTF(CONVERT_LOG_TAG);
//3 .调用方法
env -> CallStaticVoidMethod(clazz,methodid,logTag,msg);
env->DeleteLocalRef(logTag);
env->DeleteLocalRef(clazz);
}
/**
* 字符串拼接
* @param env
* @param cstr
* @param jstr
* @return
*/
jstring jstrCat(JNIEnv *env,char * cstr,jstring jstr){
char *c =(char *)(*env).GetStringUTFChars(jstr,JNI_FALSE);
char * bf = new char[strlen(cstr) + strlen(c) +1];
memcpy(bf, cstr, strlen(cstr) + 1);
strcat(bf, c);
jstring js = env->NewStringUTF(bf);
delete [] bf;
(*env).ReleaseStringUTFChars(jstr,c);
return js;
}
/**
* 获取文件的大小
* @param filename
* @return
*/
long long file_size(char* filename){
struct stat statbuf;
stat(filename,&statbuf);
return statbuf.st_size;
}
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: hello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_Mp3ConvertUtil_hello
(JNIEnv *env, jclass obj, jstring str){
jstring js = env->NewStringUTF("/sd/mp3");
publishJavaProgress(env,obj,123,js);
env->DeleteLocalRef(js);
jstring jstr = env->NewStringUTF("/sd/m/mp3");
convertFinish(env,jstr);
env->DeleteLocalRef(jstr);
jstring msg = env->NewStringUTF("xxx原因导致了未转换成功");
convertError(env, msg, msg);
env->DeleteLocalRef(msg);
LOGD("lame ver = %s",get_lame_very_short_version());
LOGI("convertmp3 %S === %S","wav","mp3");
LOGD("CONVERT %S","test");
return env->NewStringUTF("Hello From JNI!");//
}
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: getLameVer
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_com_convert_mymp3convert_Mp3ConvertUtil_getLameVer(JNIEnv *env, jclass obj) {
LOGD("CONVERT 123321 测试 S ");
LOGD("CONVERT 123321 测试 S --- %d",123);
LOGD("CONVERT 123321 测试 S --- %s","test");
return (*env).NewStringUTF(get_lame_version());
}
//int flag = 0;
/**
*wav转换mp3
* @param env
* @param obj
* @param wav
* @param mp3
*/
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: convertmp3
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
Java_com_convert_mymp3convert_Mp3ConvertUtil_convertmp3(JNIEnv *env, jclass obj, jstring wav,jstring mp3) {
char* cwav = const_cast<char *>(env->GetStringUTFChars(wav, JNI_FALSE));//Jstring2CStr(env,wav) ;
char* cmp3= const_cast<char *>(env->GetStringUTFChars(mp3, JNI_FALSE));//Jstring2CStr(env,mp3);
LOGI("wav = %s", cwav);
LOGI("mp3 = %s", cmp3);
char buf[2048] = {};
sprintf(buf, "source:%s,target:%s ", cwav,cmp3);
LOGD(buf,NULL);
if(access(cwav,F_OK) == -1){
free(cwav);
free(cmp3);
LOGD("转换源文件不存在");
jstring msg = jstrCat(env,"转换源文件不存在:",mp3);
nativeLog(env, msg);
convertError(env,msg,mp3);
env->DeleteLocalRef(msg);
return;
}
long long fileSize = file_size(cwav);
if (fileSize == 0) {
free(cwav);
free(cmp3);
jstring msg = jstrCat(env,"转换源文件大小为0:",mp3);
nativeLog(env, msg);
convertError(env,msg,mp3);
env->DeleteLocalRef(msg);
return;
}
//1.打开 wav,MP3文件
FILE* fwav = fopen(cwav,"rb");
FILE* fmp3 = fopen(cmp3,"wb");
short int wav_buffer[8192*2]= {};
unsigned char mp3_buffer[8192] = {};
//1.初始化lame的编码器
lame_t lame = lame_init();
//2. 设置lame mp3编码的采样率
lame_set_in_samplerate(lame , 44100);
lame_set_num_channels(lame,2);
// 3. 设置MP3的编码方式
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
LOGI("lame init finish");
int read ; int write; //代表读了多少个次 和写了多少次
long long total=0; // 当前读的wav文件的byte数目
LOGD("FILE SIZE = %d",fileSize);
int progress = 0;
do{
// if(flag==404){
// return;
// }
read = fread(wav_buffer,sizeof(short int)*2, 8192,fwav);
total += read* sizeof(short int)*2;
LOGI("converting ....%d", total);
int tmpProgress = (total*100)/fileSize;
LOGD("converting size = %d",tmpProgress);
if(tmpProgress != progress){
progress = tmpProgress;
publishJavaProgress(env,obj,progress,mp3);
}
// 调用java代码 完成进度条的更新
if(read!=0){
write = lame_encode_buffer_interleaved(lame,wav_buffer,read,mp3_buffer,8192);
//把转化后的mp3数据写到文件里
fwrite(mp3_buffer,sizeof(unsigned char),write,fmp3);
}
if(read==0){
write = lame_encode_flush(lame,mp3_buffer,8192);
fwrite(mp3_buffer,sizeof(unsigned char),write,fmp3);
}
}while(read!=0);
lame_close(lame);
fclose(fwav);
fclose(fmp3);
env->ReleaseStringUTFChars(wav,cwav);
env->ReleaseStringUTFChars(mp3,cmp3);
convertFinish(env,mp3);
LOGI("convert finish");
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: app/src/main/jni/NativeMp3ConvertUtil.h
================================================
//
// Created by shaomingfa on 2021/1/14.
//
#include <jni.h>
#ifndef MYMP3CONVERT_NATIVEMP3CONVERTUTIL_H
#define MYMP3CONVERT_NATIVEMP3CONVERTUTIL_H
class NativeMp3ConvertUtil {
};
#endif //MYMP3CONVERT_NATIVEMP3CONVERTUTIL_H
================================================
FILE: app/src/main/jni/NativeMyTest.cpp
================================================
//
// Created by shaomingfa on 2021/1/14.
//
#include <jni.h>
#include <string>
#include "com_convert_mymp3convert_MyTest.h"
#include "libmp3lame/lame.h"
/**
* 字符串拼接
* @param env
* @param cstr
* @param jstr
* @return
*/
jstring jstrCat(JNIEnv *env,char * cstr,jstring jstr){
char *c =(char *)(*env).GetStringUTFChars(jstr,JNI_FALSE);
char * bf = new char[strlen(cstr) + strlen(c) +1];
memcpy(bf, cstr, strlen(cstr) + 1);
strcat(bf, c);
jstring js = env->NewStringUTF(bf);
delete [] bf;
(*env).ReleaseStringUTFChars(jstr,c);
return js;
}
/*
* Class: com_convert_mymp3convert_MyTest
* Method: test
* Signature: ()Ljava/lang/String;
*/
extern "C" JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_MyTest_test
(JNIEnv *env, jclass clazz){
//1、直接使用GetStringUTFChars方法将传递过来的jstring转为char*
char *c1 = "即将转换:";
jstring mp3 = env->NewStringUTF("mp3");
char *c2 = (char *) (env->GetStringUTFChars(mp3, JNI_FALSE));
env->ReleaseStringUTFChars(mp3,c2);
//2、再使用本地函数strcat 拼接两个char*对象,然后NewStringUTF转为jstring返回去
jstring res = jstrCat(env,c1,mp3);//strcat(c1, c2);
jstring jstr = res;//env->NewStringUTF(res);
//convertLog(env,jstr);
env->DeleteLocalRef(jstr);
return env->NewStringUTF(get_lame_very_short_version());
}
================================================
FILE: app/src/main/jni/com_convert_mymp3convert_Mp3ConvertUtil.h
================================================
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_convert_mymp3convert_Mp3ConvertUtil */
#ifndef _Included_com_convert_mymp3convert_Mp3ConvertUtil
#define _Included_com_convert_mymp3convert_Mp3ConvertUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: hello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_Mp3ConvertUtil_hello
(JNIEnv *, jclass, jstring);
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: getLameVer
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_Mp3ConvertUtil_getLameVer
(JNIEnv *, jclass);
/*
* Class: com_convert_mymp3convert_Mp3ConvertUtil
* Method: convertmp3
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_convert_mymp3convert_Mp3ConvertUtil_convertmp3
(JNIEnv *, jclass, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: app/src/main/jni/com_convert_mymp3convert_MyTest.h
================================================
/* DO NOT EDIT THIS FILE - it is machine generated */
/* Header for class com_convert_mymp3convert_MyTest */
#pragma once
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_convert_mymp3convert_MyTest
* Method: test
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_MyTest_test
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
================================================
FILE: app/src/main/jni/libmp3lame/VbrTag.c
================================================
/*
* Xing VBR tagging for LAME.
*
* Copyright (c) 1999 A.L. Faber
* Copyright (c) 2001 Jonathan Dee
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* $Id: VbrTag.c,v 1.103.2.1 2011/11/18 09:18:28 robert Exp $ */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "lame.h"
#include "machine.h"
#include "encoder.h"
#include "util.h"
#include "bitstream.h"
#include "VbrTag.h"
#include "lame_global_flags.h"
#include "tables.h"
#ifdef __sun__
/* woraround for SunOS 4.x, it has SEEK_* defined here */
#include <unistd.h>
#endif
#ifdef _DEBUG
/* #define DEBUG_VBRTAG */
#endif
/*
* 4 bytes for Header Tag
* 4 bytes for Header Flags
* 100 bytes for entry (NUMTOCENTRIES)
* 4 bytes for FRAME SIZE
* 4 bytes for STREAM_SIZE
* 4 bytes for VBR SCALE. a VBR quality indicator: 0=best 100=worst
* 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)"
* ___________
* 140 bytes
*/
#define VBRHEADERSIZE (NUMTOCENTRIES+4+4+4+4+4)
#define LAMEHEADERSIZE (VBRHEADERSIZE + 9 + 1 + 1 + 8 + 1 + 1 + 3 + 1 + 1 + 2 + 4 + 2 + 2)
/* the size of the Xing header (MPEG1 and MPEG2) in kbps */
#define XING_BITRATE1 128
#define XING_BITRATE2 64
#define XING_BITRATE25 32
extern const char* get_lame_tag_encoder_short_version(void);
static const char VBRTag0[] = { "Xing" };
static const char VBRTag1[] = { "Info" };
/* Lookup table for fast CRC computation
* See 'CRC_update_lookup'
* Uses the polynomial x^16+x^15+x^2+1 */
static const unsigned int crc16_lookup[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
/***********************************************************************
* Robert Hegemann 2001-01-17
***********************************************************************/
static void
addVbr(VBR_seek_info_t * v, int bitrate)
{
int i;
v->nVbrNumFrames++;
v->sum += bitrate;
v->seen++;
if (v->seen < v->want) {
return;
}
if (v->pos < v->size) {
v->bag[v->pos] = v->sum;
v->pos++;
v->seen = 0;
}
if (v->pos == v->size) {
for (i = 1; i < v->size; i += 2) {
v->bag[i / 2] = v->bag[i];
}
v->want *= 2;
v->pos /= 2;
}
}
static void
Xing_seek_table(VBR_seek_info_t const* v, unsigned char *t)
{
int i, indx;
int seek_point;
if (v->pos <= 0)
return;
for (i = 1; i < NUMTOCENTRIES; ++i) {
float j = i / (float) NUMTOCENTRIES, act, sum;
indx = (int) (floor(j * v->pos));
if (indx > v->pos - 1)
indx = v->pos - 1;
act = v->bag[indx];
sum = v->sum;
seek_point = (int) (256. * act / sum);
if (seek_point > 255)
seek_point = 255;
t[i] = seek_point;
}
}
#ifdef DEBUG_VBR_SEEKING_TABLE
static void
print_seeking(unsigned char *t)
{
int i;
printf("seeking table ");
for (i = 0; i < NUMTOCENTRIES; ++i) {
printf(" %d ", t[i]);
}
printf("\n");
}
#endif
/****************************************************************************
* AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries
* Paramters:
* nStreamPos: how many bytes did we write to the bitstream so far
* (in Bytes NOT Bits)
****************************************************************************
*/
void
AddVbrFrame(lame_internal_flags * gfc)
{
int kbps = bitrate_table[gfc->cfg.version][gfc->ov_enc.bitrate_index];
assert(gfc->VBR_seek_table.bag);
addVbr(&gfc->VBR_seek_table, kbps);
}
/*-------------------------------------------------------------*/
static int
ExtractI4(const unsigned char *buf)
{
int x;
/* big endian extract */
x = buf[0];
x <<= 8;
x |= buf[1];
x <<= 8;
x |= buf[2];
x <<= 8;
x |= buf[3];
return x;
}
static void
CreateI4(unsigned char *buf, uint32_t nValue)
{
/* big endian create */
buf[0] = (nValue >> 24) & 0xff;
buf[1] = (nValue >> 16) & 0xff;
buf[2] = (nValue >> 8) & 0xff;
buf[3] = (nValue) & 0xff;
}
static void
CreateI2(unsigned char *buf, int nValue)
{
/* big endian create */
buf[0] = (nValue >> 8) & 0xff;
buf[1] = (nValue) & 0xff;
}
/* check for magic strings*/
static int
IsVbrTag(const unsigned char *buf)
{
int isTag0, isTag1;
isTag0 = ((buf[0] == VBRTag0[0]) && (buf[1] == VBRTag0[1]) && (buf[2] == VBRTag0[2])
&& (buf[3] == VBRTag0[3]));
isTag1 = ((buf[0] == VBRTag1[0]) && (buf[1] == VBRTag1[1]) && (buf[2] == VBRTag1[2])
&& (buf[3] == VBRTag1[3]));
return (isTag0 || isTag1);
}
#define SHIFT_IN_BITS_VALUE(x,n,v) ( x = (x << (n)) | ( (v) & ~(-1 << (n)) ) )
static void
setLameTagFrameHeader(lame_internal_flags const *gfc, unsigned char *buffer)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncResult_t const *const eov = &gfc->ov_enc;
char abyte, bbyte;
SHIFT_IN_BITS_VALUE(buffer[0], 8u, 0xffu);
SHIFT_IN_BITS_VALUE(buffer[1], 3u, 7);
SHIFT_IN_BITS_VALUE(buffer[1], 1u, (cfg->samplerate_out < 16000) ? 0 : 1);
SHIFT_IN_BITS_VALUE(buffer[1], 1u, cfg->version);
SHIFT_IN_BITS_VALUE(buffer[1], 2u, 4 - 3);
SHIFT_IN_BITS_VALUE(buffer[1], 1u, (!cfg->error_protection) ? 1 : 0);
SHIFT_IN_BITS_VALUE(buffer[2], 4u, eov->bitrate_index);
SHIFT_IN_BITS_VALUE(buffer[2], 2u, cfg->samplerate_index);
SHIFT_IN_BITS_VALUE(buffer[2], 1u, 0);
SHIFT_IN_BITS_VALUE(buffer[2], 1u, cfg->extension);
SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->mode);
SHIFT_IN_BITS_VALUE(buffer[3], 2u, eov->mode_ext);
SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->copyright);
SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->original);
SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->emphasis);
/* the default VBR header. 48 kbps layer III, no padding, no crc */
/* but sampling freq, mode andy copyright/copy protection taken */
/* from first valid frame */
buffer[0] = (uint8_t) 0xff;
abyte = (buffer[1] & (unsigned char) 0xf1);
{
int bitrate;
if (1 == cfg->version) {
bitrate = XING_BITRATE1;
}
else {
if (cfg->samplerate_out < 16000)
bitrate = XING_BITRATE25;
else
bitrate = XING_BITRATE2;
}
if (cfg->vbr == vbr_off)
bitrate = cfg->avg_bitrate;
if (cfg->free_format)
bbyte = 0x00;
else
bbyte = 16 * BitrateIndex(bitrate, cfg->version, cfg->samplerate_out);
}
/* Use as much of the info from the real frames in the
* Xing header: samplerate, channels, crc, etc...
*/
if (cfg->version == 1) {
/* MPEG1 */
buffer[1] = abyte | (char) 0x0a; /* was 0x0b; */
abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */
buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG1 frame */
}
else {
/* MPEG2 */
buffer[1] = abyte | (char) 0x02; /* was 0x03; */
abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */
buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG2 frame */
}
}
#if 0
static int CheckVbrTag(unsigned char *buf);
/*-------------------------------------------------------------*/
/* Same as GetVbrTag below, but only checks for the Xing tag.
requires buf to contain only 40 bytes */
/*-------------------------------------------------------------*/
int
CheckVbrTag(unsigned char *buf)
{
int h_id, h_mode;
/* get selected MPEG header data */
h_id = (buf[1] >> 3) & 1;
h_mode = (buf[3] >> 6) & 3;
/* determine offset of header */
if (h_id) {
/* mpeg1 */
if (h_mode != 3)
buf += (32 + 4);
else
buf += (17 + 4);
}
else {
/* mpeg2 */
if (h_mode != 3)
buf += (17 + 4);
else
buf += (9 + 4);
}
return IsVbrTag(buf);
}
#endif
int
GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf)
{
int i, head_flags;
int h_bitrate, h_id, h_mode, h_sr_index, h_layer;
int enc_delay, enc_padding;
/* get Vbr header data */
pTagData->flags = 0;
/* get selected MPEG header data */
h_layer = (buf[1] >> 1) & 3;
if ( h_layer != 0x01 ) {
/* the following code assumes Layer-3, so give up here */
return 0;
}
h_id = (buf[1] >> 3) & 1;
h_sr_index = (buf[2] >> 2) & 3;
h_mode = (buf[3] >> 6) & 3;
h_bitrate = ((buf[2] >> 4) & 0xf);
h_bitrate = bitrate_table[h_id][h_bitrate];
/* check for FFE syncword */
if ((buf[1] >> 4) == 0xE)
pTagData->samprate = samplerate_table[2][h_sr_index];
else
pTagData->samprate = samplerate_table[h_id][h_sr_index];
/* if( h_id == 0 ) */
/* pTagData->samprate >>= 1; */
/* determine offset of header */
if (h_id) {
/* mpeg1 */
if (h_mode != 3)
buf += (32 + 4);
else
buf += (17 + 4);
}
else {
/* mpeg2 */
if (h_mode != 3)
buf += (17 + 4);
else
buf += (9 + 4);
}
if (!IsVbrTag(buf))
return 0;
buf += 4;
pTagData->h_id = h_id;
head_flags = pTagData->flags = ExtractI4(buf);
buf += 4; /* get flags */
if (head_flags & FRAMES_FLAG) {
pTagData->frames = ExtractI4(buf);
buf += 4;
}
if (head_flags & BYTES_FLAG) {
pTagData->bytes = ExtractI4(buf);
buf += 4;
}
if (head_flags & TOC_FLAG) {
if (pTagData->toc != NULL) {
for (i = 0; i < NUMTOCENTRIES; i++)
pTagData->toc[i] = buf[i];
}
buf += NUMTOCENTRIES;
}
pTagData->vbr_scale = -1;
if (head_flags & VBR_SCALE_FLAG) {
pTagData->vbr_scale = ExtractI4(buf);
buf += 4;
}
pTagData->headersize = ((h_id + 1) * 72000 * h_bitrate) / pTagData->samprate;
buf += 21;
enc_delay = buf[0] << 4;
enc_delay += buf[1] >> 4;
enc_padding = (buf[1] & 0x0F) << 8;
enc_padding += buf[2];
/* check for reasonable values (this may be an old Xing header, */
/* not a INFO tag) */
if (enc_delay < 0 || enc_delay > 3000)
enc_delay = -1;
if (enc_padding < 0 || enc_padding > 3000)
enc_padding = -1;
pTagData->enc_delay = enc_delay;
pTagData->enc_padding = enc_padding;
#ifdef DEBUG_VBRTAG
fprintf(stderr, "\n\n********************* VBR TAG INFO *****************\n");
fprintf(stderr, "tag :%s\n", VBRTag);
fprintf(stderr, "head_flags :%d\n", head_flags);
fprintf(stderr, "bytes :%d\n", pTagData->bytes);
fprintf(stderr, "frames :%d\n", pTagData->frames);
fprintf(stderr, "VBR Scale :%d\n", pTagData->vbr_scale);
fprintf(stderr, "enc_delay = %i \n", enc_delay);
fprintf(stderr, "enc_padding= %i \n", enc_padding);
fprintf(stderr, "toc:\n");
if (pTagData->toc != NULL) {
for (i = 0; i < NUMTOCENTRIES; i++) {
if ((i % 10) == 0)
fprintf(stderr, "\n");
fprintf(stderr, " %3d", (int) (pTagData->toc[i]));
}
}
fprintf(stderr, "\n***************** END OF VBR TAG INFO ***************\n");
#endif
return 1; /* success */
}
/****************************************************************************
* InitVbrTag: Initializes the header, and write empty frame to stream
* Paramters:
* fpStream: pointer to output file stream
* nMode : Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO
****************************************************************************
*/
int
InitVbrTag(lame_global_flags * gfp)
{
lame_internal_flags *gfc = gfp->internal_flags;
SessionConfig_t const *const cfg = &gfc->cfg;
int kbps_header;
#define MAXFRAMESIZE 2880 /* or 0xB40, the max freeformat 640 32kHz framesize */
/*
* Xing VBR pretends to be a 48kbs layer III frame. (at 44.1kHz).
* (at 48kHz they use 56kbs since 48kbs frame not big enough for
* table of contents)
* let's always embed Xing header inside a 64kbs layer III frame.
* this gives us enough room for a LAME version string too.
* size determined by sampling frequency (MPEG1)
* 32kHz: 216 bytes@48kbs 288bytes@ 64kbs
* 44.1kHz: 156 bytes 208bytes@64kbs (+1 if padding = 1)
* 48kHz: 144 bytes 192
*
* MPEG 2 values are the same since the framesize and samplerate
* are each reduced by a factor of 2.
*/
if (1 == cfg->version) {
kbps_header = XING_BITRATE1;
}
else {
if (cfg->samplerate_out < 16000)
kbps_header = XING_BITRATE25;
else
kbps_header = XING_BITRATE2;
}
if (cfg->vbr == vbr_off)
kbps_header = cfg->avg_bitrate;
/** make sure LAME Header fits into Frame
*/
{
int total_frame_size = ((cfg->version + 1) * 72000 * kbps_header) / cfg->samplerate_out;
int header_size = (cfg->sideinfo_len + LAMEHEADERSIZE);
gfc->VBR_seek_table.TotalFrameSize = total_frame_size;
if (total_frame_size < header_size || total_frame_size > MAXFRAMESIZE) {
/* disable tag, it wont fit */
gfc->cfg.write_lame_tag = 0;
return 0;
}
}
gfc->VBR_seek_table.nVbrNumFrames = 0;
gfc->VBR_seek_table.nBytesWritten = 0;
gfc->VBR_seek_table.sum = 0;
gfc->VBR_seek_table.seen = 0;
gfc->VBR_seek_table.want = 1;
gfc->VBR_seek_table.pos = 0;
if (gfc->VBR_seek_table.bag == NULL) {
gfc->VBR_seek_table.bag = malloc(400 * sizeof(int));
if (gfc->VBR_seek_table.bag != NULL) {
gfc->VBR_seek_table.size = 400;
}
else {
gfc->VBR_seek_table.size = 0;
ERRORF(gfc, "Error: can't allocate VbrFrames buffer\n");
gfc->cfg.write_lame_tag = 0;
return -1;
}
}
/* write dummy VBR tag of all 0's into bitstream */
{
uint8_t buffer[MAXFRAMESIZE];
size_t i, n;
memset(buffer, 0, sizeof(buffer));
setLameTagFrameHeader(gfc, buffer);
n = gfc->VBR_seek_table.TotalFrameSize;
for (i = 0; i < n; ++i) {
add_dummy_byte(gfc, buffer[i], 1);
}
}
/* Success */
return 0;
}
/* fast CRC-16 computation - uses table crc16_lookup 8*/
static uint16_t
CRC_update_lookup(uint16_t value, uint16_t crc)
{
uint16_t tmp;
tmp = crc ^ value;
crc = (crc >> 8) ^ crc16_lookup[tmp & 0xff];
return crc;
}
void
UpdateMusicCRC(uint16_t * crc, unsigned char const *buffer, int size)
{
int i;
for (i = 0; i < size; ++i)
*crc = CRC_update_lookup(buffer[i], *crc);
}
/****************************************************************************
* Jonathan Dee 2001/08/31
*
* PutLameVBR: Write LAME info: mini version + info on various switches used
* Paramters:
* pbtStreamBuffer : pointer to output buffer
* id3v2size : size of id3v2 tag in bytes
* crc : computation of crc-16 of Lame Tag so far (starting at frame sync)
*
****************************************************************************
*/
static int
PutLameVBR(lame_global_flags const *gfp, size_t nMusicLength, uint8_t * pbtStreamBuffer, uint16_t crc)
{
lame_internal_flags const *gfc = gfp->internal_flags;
SessionConfig_t const *const cfg = &gfc->cfg;
int nBytesWritten = 0;
int i;
int enc_delay = gfc->ov_enc.encoder_delay; /* encoder delay */
int enc_padding = gfc->ov_enc.encoder_padding; /* encoder padding */
/*recall: cfg->vbr_q is for example set by the switch -V */
/* gfp->quality by -q, -h, -f, etc */
int nQuality = (100 - 10 * gfp->VBR_q - gfp->quality);
/*
NOTE:
Even though the specification for the LAME VBR tag
did explicitly mention other encoders than LAME,
many SW/HW decoder seem to be able to make use of
this tag only, if the encoder version starts with LAME.
To be compatible with such decoders, ANY encoder will
be forced to write a fake LAME version string!
As a result, the encoder version info becomes worthless.
*/
const char *szVersion = get_lame_tag_encoder_short_version();
uint8_t nVBR;
uint8_t nRevision = 0x00;
uint8_t nRevMethod;
uint8_t vbr_type_translator[] = { 1, 5, 3, 2, 4, 0, 3 }; /*numbering different in vbr_mode vs. Lame tag */
uint8_t nLowpass =
(((cfg->lowpassfreq / 100.0) + .5) > 255 ? 255 : (cfg->lowpassfreq / 100.0) + .5);
uint32_t nPeakSignalAmplitude = 0;
uint16_t nRadioReplayGain = 0;
uint16_t nAudiophileReplayGain = 0;
uint8_t nNoiseShaping = cfg->noise_shaping;
uint8_t nStereoMode = 0;
int bNonOptimal = 0;
uint8_t nSourceFreq = 0;
uint8_t nMisc = 0;
uint16_t nMusicCRC = 0;
/*psy model type: Gpsycho or NsPsytune */
unsigned char bExpNPsyTune = 1; /* only NsPsytune */
unsigned char bSafeJoint = (cfg->use_safe_joint_stereo) != 0;
unsigned char bNoGapMore = 0;
unsigned char bNoGapPrevious = 0;
int nNoGapCount = gfp->nogap_total;
int nNoGapCurr = gfp->nogap_current;
uint8_t nAthType = cfg->ATHtype; /*4 bits. */
uint8_t nFlags = 0;
/* if ABR, {store bitrate <=255} else { store "-b"} */
int nABRBitrate;
switch (cfg->vbr) {
case vbr_abr:{
nABRBitrate = cfg->vbr_avg_bitrate_kbps;
break;
}
case vbr_off:{
nABRBitrate = cfg->avg_bitrate;
break;
}
default:{ /*vbr modes */
nABRBitrate = bitrate_table[cfg->version][cfg->vbr_min_bitrate_index];;
}
}
/*revision and vbr method */
if (cfg->vbr < sizeof(vbr_type_translator))
nVBR = vbr_type_translator[cfg->vbr];
else
nVBR = 0x00; /*unknown. */
nRevMethod = 0x10 * nRevision + nVBR;
/* ReplayGain */
if (cfg->findReplayGain) {
int RadioGain = gfc->ov_rpg.RadioGain;
if (RadioGain > 0x1FE)
RadioGain = 0x1FE;
if (RadioGain < -0x1FE)
RadioGain = -0x1FE;
nRadioReplayGain = 0x2000; /* set name code */
nRadioReplayGain |= 0xC00; /* set originator code to `determined automatically' */
if (RadioGain >= 0)
nRadioReplayGain |= RadioGain; /* set gain adjustment */
else {
nRadioReplayGain |= 0x200; /* set the sign bit */
nRadioReplayGain |= -RadioGain; /* set gain adjustment */
}
}
/* peak sample */
if (cfg->findPeakSample)
nPeakSignalAmplitude =
abs((int) ((((FLOAT) gfc->ov_rpg.PeakSample) / 32767.0) * pow(2, 23) + .5));
/*nogap */
if (nNoGapCount != -1) {
if (nNoGapCurr > 0)
bNoGapPrevious = 1;
if (nNoGapCurr < nNoGapCount - 1)
bNoGapMore = 1;
}
/*flags */
nFlags = nAthType + (bExpNPsyTune << 4)
+ (bSafeJoint << 5)
+ (bNoGapMore << 6)
+ (bNoGapPrevious << 7);
if (nQuality < 0)
nQuality = 0;
/*stereo mode field... a bit ugly. */
switch (cfg->mode) {
case MONO:
nStereoMode = 0;
break;
case STEREO:
nStereoMode = 1;
break;
case DUAL_CHANNEL:
nStereoMode = 2;
break;
case JOINT_STEREO:
if (cfg->force_ms)
nStereoMode = 4;
else
nStereoMode = 3;
break;
case NOT_SET:
/* FALLTHROUGH */
default:
nStereoMode = 7;
break;
}
/*Intensity stereo : nStereoMode = 6. IS is not implemented */
if (cfg->samplerate_in <= 32000)
nSourceFreq = 0x00;
else if (cfg->samplerate_in == 48000)
nSourceFreq = 0x02;
else if (cfg->samplerate_in > 48000)
nSourceFreq = 0x03;
else
nSourceFreq = 0x01; /*default is 44100Hz. */
/*Check if the user overrided the default LAME behaviour with some nasty options */
if (cfg->short_blocks == short_block_forced || cfg->short_blocks == short_block_dispensed || ((cfg->lowpassfreq == -1) && (cfg->highpassfreq == -1)) || /* "-k" */
(cfg->disable_reservoir && cfg->avg_bitrate < 320) ||
cfg->noATH || cfg->ATHonly || (nAthType == 0) || cfg->samplerate_in <= 32000)
bNonOptimal = 1;
nMisc = nNoiseShaping + (nStereoMode << 2)
+ (bNonOptimal << 5)
+ (nSourceFreq << 6);
nMusicCRC = gfc->nMusicCRC;
/*Write all this information into the stream */
CreateI4(&pbtStreamBuffer[nBytesWritten], nQuality);
nBytesWritten += 4;
strncpy((char *) &pbtStreamBuffer[nBytesWritten], szVersion, 9);
nBytesWritten += 9;
pbtStreamBuffer[nBytesWritten] = nRevMethod;
nBytesWritten++;
pbtStreamBuffer[nBytesWritten] = nLowpass;
nBytesWritten++;
CreateI4(&pbtStreamBuffer[nBytesWritten], nPeakSignalAmplitude);
nBytesWritten += 4;
CreateI2(&pbtStreamBuffer[nBytesWritten], nRadioReplayGain);
nBytesWritten += 2;
CreateI2(&pbtStreamBuffer[nBytesWritten], nAudiophileReplayGain);
nBytesWritten += 2;
pbtStreamBuffer[nBytesWritten] = nFlags;
nBytesWritten++;
if (nABRBitrate >= 255)
pbtStreamBuffer[nBytesWritten] = 0xFF;
else
pbtStreamBuffer[nBytesWritten] = nABRBitrate;
nBytesWritten++;
pbtStreamBuffer[nBytesWritten] = enc_delay >> 4; /* works for win32, does it for unix? */
pbtStreamBuffer[nBytesWritten + 1] = (enc_delay << 4) + (enc_padding >> 8);
pbtStreamBuffer[nBytesWritten + 2] = enc_padding;
nBytesWritten += 3;
pbtStreamBuffer[nBytesWritten] = nMisc;
nBytesWritten++;
pbtStreamBuffer[nBytesWritten++] = 0; /*unused in rev0 */
CreateI2(&pbtStreamBuffer[nBytesWritten], cfg->preset);
nBytesWritten += 2;
CreateI4(&pbtStreamBuffer[nBytesWritten], (int) nMusicLength);
nBytesWritten += 4;
CreateI2(&pbtStreamBuffer[nBytesWritten], nMusicCRC);
nBytesWritten += 2;
/*Calculate tag CRC.... must be done here, since it includes
*previous information*/
for (i = 0; i < nBytesWritten; i++)
crc = CRC_update_lookup(pbtStreamBuffer[i], crc);
CreateI2(&pbtStreamBuffer[nBytesWritten], crc);
nBytesWritten += 2;
return nBytesWritten;
}
static long
skipId3v2(FILE * fpStream)
{
size_t nbytes;
long id3v2TagSize;
unsigned char id3v2Header[10];
/* seek to the beginning of the stream */
if (fseek(fpStream, 0, SEEK_SET) != 0) {
return -2; /* not seekable, abort */
}
/* read 10 bytes in case there's an ID3 version 2 header here */
nbytes = fread(id3v2Header, 1, sizeof(id3v2Header), fpStream);
if (nbytes != sizeof(id3v2Header)) {
return -3; /* not readable, maybe opened Write-Only */
}
/* does the stream begin with the ID3 version 2 file identifier? */
if (!strncmp((char *) id3v2Header, "ID3", 3)) {
/* the tag size (minus the 10-byte header) is encoded into four
* bytes where the most significant bit is clear in each byte */
id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21)
| ((id3v2Header[7] & 0x7f) << 14)
| ((id3v2Header[8] & 0x7f) << 7)
| (id3v2Header[9] & 0x7f))
+ sizeof id3v2Header;
}
else {
/* no ID3 version 2 tag in this stream */
id3v2TagSize = 0;
}
return id3v2TagSize;
}
size_t
lame_get_lametag_frame(lame_global_flags const *gfp, unsigned char *buffer, size_t size)
{
lame_internal_flags *gfc;
SessionConfig_t const *cfg;
unsigned long stream_size;
unsigned int nStreamIndex;
uint8_t btToc[NUMTOCENTRIES];
if (gfp == 0) {
return 0;
}
gfc = gfp->internal_flags;
if (gfc == 0) {
return 0;
}
if (gfc->class_id != LAME_ID) {
return 0;
}
cfg = &gfc->cfg;
if (cfg->write_lame_tag == 0) {
return 0;
}
if (gfc->VBR_seek_table.pos <= 0) {
return 0;
}
if (size < gfc->VBR_seek_table.TotalFrameSize) {
return gfc->VBR_seek_table.TotalFrameSize;
}
if (buffer == 0) {
return 0;
}
memset(buffer, 0, gfc->VBR_seek_table.TotalFrameSize);
/* 4 bytes frame header */
setLameTagFrameHeader(gfc, buffer);
/* Clear all TOC entries */
memset(btToc, 0, sizeof(btToc));
if (cfg->free_format) {
int i;
for (i = 1; i < NUMTOCENTRIES; ++i)
btToc[i] = 255 * i / 100;
}
else {
Xing_seek_table(&gfc->VBR_seek_table, btToc);
}
#ifdef DEBUG_VBR_SEEKING_TABLE
print_seeking(btToc);
#endif
/* Start writing the tag after the zero frame */
nStreamIndex = cfg->sideinfo_len;
/* note! Xing header specifies that Xing data goes in the
* ancillary data with NO ERROR PROTECTION. If error protecton
* in enabled, the Xing data still starts at the same offset,
* and now it is in sideinfo data block, and thus will not
* decode correctly by non-Xing tag aware players */
if (cfg->error_protection)
nStreamIndex -= 2;
/* Put Vbr tag */
if (cfg->vbr == vbr_off) {
buffer[nStreamIndex++] = VBRTag1[0];
buffer[nStreamIndex++] = VBRTag1[1];
buffer[nStreamIndex++] = VBRTag1[2];
buffer[nStreamIndex++] = VBRTag1[3];
}
else {
buffer[nStreamIndex++] = VBRTag0[0];
buffer[nStreamIndex++] = VBRTag0[1];
buffer[nStreamIndex++] = VBRTag0[2];
buffer[nStreamIndex++] = VBRTag0[3];
}
/* Put header flags */
CreateI4(&buffer[nStreamIndex], FRAMES_FLAG + BYTES_FLAG + TOC_FLAG + VBR_SCALE_FLAG);
nStreamIndex += 4;
/* Put Total Number of frames */
CreateI4(&buffer[nStreamIndex], gfc->VBR_seek_table.nVbrNumFrames);
nStreamIndex += 4;
/* Put total audio stream size, including Xing/LAME Header */
stream_size = gfc->VBR_seek_table.nBytesWritten + gfc->VBR_seek_table.TotalFrameSize;
CreateI4(&buffer[nStreamIndex], stream_size);
nStreamIndex += 4;
/* Put TOC */
memcpy(&buffer[nStreamIndex], btToc, sizeof(btToc));
nStreamIndex += sizeof(btToc);
if (cfg->error_protection) {
/* (jo) error_protection: add crc16 information to header */
CRC_writeheader(gfc, (char *) buffer);
}
{
/*work out CRC so far: initially crc = 0 */
uint16_t crc = 0x00;
unsigned int i;
for (i = 0; i < nStreamIndex; i++)
crc = CRC_update_lookup(buffer[i], crc);
/*Put LAME VBR info */
nStreamIndex += PutLameVBR(gfp, stream_size, buffer + nStreamIndex, crc);
}
#ifdef DEBUG_VBRTAG
{
VBRTAGDATA TestHeader;
GetVbrTag(&TestHeader, buffer);
}
#endif
return gfc->VBR_seek_table.TotalFrameSize;
}
/***********************************************************************
*
* PutVbrTag: Write final VBR tag to the file
* Paramters:
* lpszFileName: filename of MP3 bit stream
* nVbrScale : encoder quality indicator (0..100)
****************************************************************************
*/
int
PutVbrTag(lame_global_flags const *gfp, FILE * fpStream)
{
lame_internal_flags *gfc = gfp->internal_flags;
long lFileSize;
long id3v2TagSize;
size_t nbytes;
uint8_t buffer[MAXFRAMESIZE];
if (gfc->VBR_seek_table.pos <= 0)
return -1;
/* Seek to end of file */
fseek(fpStream, 0, SEEK_END);
/* Get file size */
lFileSize = ftell(fpStream);
/* Abort if file has zero length. Yes, it can happen :) */
if (lFileSize == 0)
return -1;
/*
* The VBR tag may NOT be located at the beginning of the stream.
* If an ID3 version 2 tag was added, then it must be skipped to write
* the VBR tag data.
*/
id3v2TagSize = skipId3v2(fpStream);
if (id3v2TagSize < 0) {
return id3v2TagSize;
}
/*Seek to the beginning of the stream */
fseek(fpStream, id3v2TagSize, SEEK_SET);
nbytes = lame_get_lametag_frame(gfp, buffer, sizeof(buffer));
if (nbytes > sizeof(buffer)) {
return -1;
}
if (nbytes < 1) {
return 0;
}
/* Put it all to disk again */
if (fwrite(buffer, nbytes, 1, fpStream) != 1) {
return -1;
}
return 0; /* success */
}
================================================
FILE: app/src/main/jni/libmp3lame/VbrTag.h
================================================
/*
* Xing VBR tagging for LAME.
*
* Copyright (c) 1999 A.L. Faber
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef LAME_VRBTAG_H
#define LAME_VRBTAG_H
/* -----------------------------------------------------------
* A Vbr header may be present in the ancillary
* data field of the first frame of an mp3 bitstream
* The Vbr header (optionally) contains
* frames total number of audio frames in the bitstream
* bytes total number of bytes in the bitstream
* toc table of contents
* toc (table of contents) gives seek points
* for random access
* the ith entry determines the seek point for
* i-percent duration
* seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes
* e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes
*/
#define FRAMES_FLAG 0x0001
#define BYTES_FLAG 0x0002
#define TOC_FLAG 0x0004
#define VBR_SCALE_FLAG 0x0008
#define NUMTOCENTRIES 100
#ifndef lame_internal_flags_defined
#define lame_internal_flags_defined
struct lame_internal_flags;
typedef struct lame_internal_flags lame_internal_flags;
#endif
/*structure to receive extracted header */
/* toc may be NULL*/
typedef struct {
int h_id; /* from MPEG header, 0=MPEG2, 1=MPEG1 */
int samprate; /* determined from MPEG header */
int flags; /* from Vbr header data */
int frames; /* total bit stream frames from Vbr header data */
int bytes; /* total bit stream bytes from Vbr header data */
int vbr_scale; /* encoded vbr scale from Vbr header data */
unsigned char toc[NUMTOCENTRIES]; /* may be NULL if toc not desired */
int headersize; /* size of VBR header, in bytes */
int enc_delay; /* encoder delay */
int enc_padding; /* encoder paddign added at end of stream */
} VBRTAGDATA;
int GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf);
int InitVbrTag(lame_global_flags * gfp);
int PutVbrTag(lame_global_flags const *gfp, FILE * fid);
void AddVbrFrame(lame_internal_flags * gfc);
void UpdateMusicCRC(uint16_t * crc, const unsigned char *buffer, int size);
#endif
================================================
FILE: app/src/main/jni/libmp3lame/bitstream.c
================================================
/*
* MP3 bitstream Output interface for LAME
*
* Copyright (c) 1999-2000 Mark Taylor
* Copyright (c) 1999-2002 Takehiro Tominaga
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* $Id: bitstream.c,v 1.97 2011/05/07 16:05:17 rbrito Exp $
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include "lame.h"
#include "machine.h"
#include "encoder.h"
#include "util.h"
#include "tables.h"
#include "quantize_pvt.h"
#include "lame_global_flags.h"
#include "gain_analysis.h"
#include "VbrTag.h"
#include "bitstream.h"
#include "tables.h"
/* unsigned int is at least this large: */
/* we work with ints, so when doing bit manipulation, we limit
* ourselves to MAX_LENGTH-2 just to be on the safe side */
#define MAX_LENGTH 32
#ifdef DEBUG
static int hogege;
#endif
static int
calcFrameLength(SessionConfig_t const *const cfg, int kbps, int pad)
{
return 8 * ((cfg->version + 1) * 72000 * kbps / cfg->samplerate_out + pad);
}
/***********************************************************************
* compute bitsperframe and mean_bits for a layer III frame
**********************************************************************/
int
getframebits(const lame_internal_flags * gfc)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncResult_t const *const eov = &gfc->ov_enc;
int bit_rate;
/* get bitrate in kbps [?] */
if (eov->bitrate_index)
bit_rate = bitrate_table[cfg->version][eov->bitrate_index];
else
bit_rate = cfg->avg_bitrate;
/*assert(bit_rate <= 550); */
assert(8 <= bit_rate && bit_rate <= 640);
/* main encoding routine toggles padding on and off */
/* one Layer3 Slot consists of 8 bits */
return calcFrameLength(cfg, bit_rate, eov->padding);
}
int
get_max_frame_buffer_size_by_constraint(SessionConfig_t const * cfg, int constraint)
{
int maxmp3buf = 0;
if (cfg->avg_bitrate > 320) {
/* in freeformat the buffer is constant */
if (constraint == MDB_STRICT_ISO) {
maxmp3buf = calcFrameLength(cfg, cfg->avg_bitrate, 0);
}
else {
/* maximum allowed bits per granule are 7680 */
maxmp3buf = 7680 * (cfg->version + 1);
}
}
else {
int max_kbps;
if (cfg->samplerate_out < 16000) {
max_kbps = bitrate_table[cfg->version][8]; /* default: allow 64 kbps (MPEG-2.5) */
}
else {
max_kbps = bitrate_table[cfg->version][14];
}
switch (constraint)
{
default:
case MDB_DEFAULT:
/* Bouvigne suggests this more lax interpretation of the ISO doc instead of using 8*960. */
/* All mp3 decoders should have enough buffer to handle this value: size of a 320kbps 32kHz frame */
maxmp3buf = 8 * 1440;
break;
case MDB_STRICT_ISO:
maxmp3buf = calcFrameLength(cfg, max_kbps, 0);
break;
case MDB_MAXIMUM:
maxmp3buf = 7680 * (cfg->version + 1);
break;
}
}
return maxmp3buf;
}
static void
putheader_bits(lame_internal_flags * gfc)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncStateVar_t *const esv = &gfc->sv_enc;
Bit_stream_struc *bs = &gfc->bs;
#ifdef DEBUG
hogege += cfg->sideinfo_len * 8;
#endif
memcpy(&bs->buf[bs->buf_byte_idx], esv->header[esv->w_ptr].buf, cfg->sideinfo_len);
bs->buf_byte_idx += cfg->sideinfo_len;
bs->totbit += cfg->sideinfo_len * 8;
esv->w_ptr = (esv->w_ptr + 1) & (MAX_HEADER_BUF - 1);
}
/*write j bits into the bit stream */
inline static void
putbits2(lame_internal_flags * gfc, int val, int j)
{
EncStateVar_t const *const esv = &gfc->sv_enc;
Bit_stream_struc *bs;
bs = &gfc->bs;
assert(j < MAX_LENGTH - 2);
while (j > 0) {
int k;
if (bs->buf_bit_idx == 0) {
bs->buf_bit_idx = 8;
bs->buf_byte_idx++;
assert(bs->buf_byte_idx < BUFFER_SIZE);
assert(esv->header[esv->w_ptr].write_timing >= bs->totbit);
if (esv->header[esv->w_ptr].write_timing == bs->totbit) {
putheader_bits(gfc);
}
bs->buf[bs->buf_byte_idx] = 0;
}
k = Min(j, bs->buf_bit_idx);
j -= k;
bs->buf_bit_idx -= k;
assert(j < MAX_LENGTH); /* 32 too large on 32 bit machines */
assert(bs->buf_bit_idx < MAX_LENGTH);
bs->buf[bs->buf_byte_idx] |= ((val >> j) << bs->buf_bit_idx);
bs->totbit += k;
}
}
/*write j bits into the bit stream, ignoring frame headers */
inline static void
putbits_noheaders(lame_internal_flags * gfc, int val, int j)
{
Bit_stream_struc *bs;
bs = &gfc->bs;
assert(j < MAX_LENGTH - 2);
while (j > 0) {
int k;
if (bs->buf_bit_idx == 0) {
bs->buf_bit_idx = 8;
bs->buf_byte_idx++;
assert(bs->buf_byte_idx < BUFFER_SIZE);
bs->buf[bs->buf_byte_idx] = 0;
}
k = Min(j, bs->buf_bit_idx);
j -= k;
bs->buf_bit_idx -= k;
assert(j < MAX_LENGTH); /* 32 too large on 32 bit machines */
assert(bs->buf_bit_idx < MAX_LENGTH);
bs->buf[bs->buf_byte_idx] |= ((val >> j) << bs->buf_bit_idx);
bs->totbit += k;
}
}
/*
Some combinations of bitrate, Fs, and stereo make it impossible to stuff
out a frame using just main_data, due to the limited number of bits to
indicate main_data_length. In these situations, we put stuffing bits into
the ancillary data...
*/
inline static void
drain_into_ancillary(lame_internal_flags * gfc, int remainingBits)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncStateVar_t *const esv = &gfc->sv_enc;
int i;
assert(remainingBits >= 0);
if (remainingBits >= 8) {
putbits2(gfc, 0x4c, 8);
remainingBits -= 8;
}
if (remainingBits >= 8) {
putbits2(gfc, 0x41, 8);
remainingBits -= 8;
}
if (remainingBits >= 8) {
putbits2(gfc, 0x4d, 8);
remainingBits -= 8;
}
if (remainingBits >= 8) {
putbits2(gfc, 0x45, 8);
remainingBits -= 8;
}
if (remainingBits >= 32) {
const char *const version = get_lame_short_version();
if (remainingBits >= 32)
for (i = 0; i < (int) strlen(version) && remainingBits >= 8; ++i) {
remainingBits -= 8;
putbits2(gfc, version[i], 8);
}
}
for (; remainingBits >= 1; remainingBits -= 1) {
putbits2(gfc, esv->ancillary_flag, 1);
esv->ancillary_flag ^= !cfg->disable_reservoir;
}
assert(remainingBits == 0);
}
/*write N bits into the header */
inline static void
writeheader(lame_internal_flags * gfc, int val, int j)
{
EncStateVar_t *const esv = &gfc->sv_enc;
int ptr = esv->header[esv->h_ptr].ptr;
while (j > 0) {
int const k = Min(j, 8 - (ptr & 7));
j -= k;
assert(j < MAX_LENGTH); /* >> 32 too large for 32 bit machines */
esv->header[esv->h_ptr].buf[ptr >> 3]
|= ((val >> j)) << (8 - (ptr & 7) - k);
ptr += k;
}
esv->header[esv->h_ptr].ptr = ptr;
}
static int
CRC_update(int value, int crc)
{
int i;
value <<= 8;
for (i = 0; i < 8; i++) {
value <<= 1;
crc <<= 1;
if (((crc ^ value) & 0x10000))
crc ^= CRC16_POLYNOMIAL;
}
return crc;
}
void
CRC_writeheader(lame_internal_flags const *gfc, char *header)
{
SessionConfig_t const *const cfg = &gfc->cfg;
int crc = 0xffff; /* (jo) init crc16 for error_protection */
int i;
crc = CRC_update(((unsigned char *) header)[2], crc);
crc = CRC_update(((unsigned char *) header)[3], crc);
for (i = 6; i < cfg->sideinfo_len; i++) {
crc = CRC_update(((unsigned char *) header)[i], crc);
}
header[4] = crc >> 8;
header[5] = crc & 255;
}
inline static void
encodeSideInfo2(lame_internal_flags * gfc, int bitsPerFrame)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncResult_t const *const eov = &gfc->ov_enc;
EncStateVar_t *const esv = &gfc->sv_enc;
III_side_info_t *l3_side;
int gr, ch;
l3_side = &gfc->l3_side;
esv->header[esv->h_ptr].ptr = 0;
memset(esv->header[esv->h_ptr].buf, 0, cfg->sideinfo_len);
if (cfg->samplerate_out < 16000)
writeheader(gfc, 0xffe, 12);
else
writeheader(gfc, 0xfff, 12);
writeheader(gfc, (cfg->version), 1);
writeheader(gfc, 4 - 3, 2);
writeheader(gfc, (!cfg->error_protection), 1);
writeheader(gfc, (eov->bitrate_index), 4);
writeheader(gfc, (cfg->samplerate_index), 2);
writeheader(gfc, (eov->padding), 1);
writeheader(gfc, (cfg->extension), 1);
writeheader(gfc, (cfg->mode), 2);
writeheader(gfc, (eov->mode_ext), 2);
writeheader(gfc, (cfg->copyright), 1);
writeheader(gfc, (cfg->original), 1);
writeheader(gfc, (cfg->emphasis), 2);
if (cfg->error_protection) {
writeheader(gfc, 0, 16); /* dummy */
}
if (cfg->version == 1) {
/* MPEG1 */
assert(l3_side->main_data_begin >= 0);
writeheader(gfc, (l3_side->main_data_begin), 9);
if (cfg->channels_out == 2)
writeheader(gfc, l3_side->private_bits, 3);
else
writeheader(gfc, l3_side->private_bits, 5);
for (ch = 0; ch < cfg->channels_out; ch++) {
int band;
for (band = 0; band < 4; band++) {
writeheader(gfc, l3_side->scfsi[ch][band], 1);
}
}
for (gr = 0; gr < 2; gr++) {
for (ch = 0; ch < cfg->channels_out; ch++) {
gr_info *const gi = &l3_side->tt[gr][ch];
writeheader(gfc, gi->part2_3_length + gi->part2_length, 12);
writeheader(gfc, gi->big_values / 2, 9);
writeheader(gfc, gi->global_gain, 8);
writeheader(gfc, gi->scalefac_compress, 4);
if (gi->block_type != NORM_TYPE) {
writeheader(gfc, 1, 1); /* window_switching_flag */
writeheader(gfc, gi->block_type, 2);
writeheader(gfc, gi->mixed_block_flag, 1);
if (gi->table_select[0] == 14)
gi->table_select[0] = 16;
writeheader(gfc, gi->table_select[0], 5);
if (gi->table_select[1] == 14)
gi->table_select[1] = 16;
writeheader(gfc, gi->table_select[1], 5);
writeheader(gfc, gi->subblock_gain[0], 3);
writeheader(gfc, gi->subblock_gain[1], 3);
writeheader(gfc, gi->subblock_gain[2], 3);
}
else {
writeheader(gfc, 0, 1); /* window_switching_flag */
if (gi->table_select[0] == 14)
gi->table_select[0] = 16;
writeheader(gfc, gi->table_select[0], 5);
if (gi->table_select[1] == 14)
gi->table_select[1] = 16;
writeheader(gfc, gi->table_select[1], 5);
if (gi->table_select[2] == 14)
gi->table_select[2] = 16;
writeheader(gfc, gi->table_select[2], 5);
assert(0 <= gi->region0_count && gi->region0_count < 16);
assert(0 <= gi->region1_count && gi->region1_count < 8);
writeheader(gfc, gi->region0_count, 4);
writeheader(gfc, gi->region1_count, 3);
}
writeheader(gfc, gi->preflag, 1);
writeheader(gfc, gi->scalefac_scale, 1);
writeheader(gfc, gi->count1table_select, 1);
}
}
}
else {
/* MPEG2 */
assert(l3_side->main_data_begin >= 0);
writeheader(gfc, (l3_side->main_data_begin), 8);
writeheader(gfc, l3_side->private_bits, cfg->channels_out);
gr = 0;
for (ch = 0; ch < cfg->channels_out; ch++) {
gr_info *const gi = &l3_side->tt[gr][ch];
writeheader(gfc, gi->part2_3_length + gi->part2_length, 12);
writeheader(gfc, gi->big_values / 2, 9);
writeheader(gfc, gi->global_gain, 8);
writeheader(gfc, gi->scalefac_compress, 9);
if (gi->block_type != NORM_TYPE) {
writeheader(gfc, 1, 1); /* window_switching_flag */
writeheader(gfc, gi->block_type, 2);
writeheader(gfc, gi->mixed_block_flag, 1);
if (gi->table_select[0] == 14)
gi->table_select[0] = 16;
writeheader(gfc, gi->table_select[0], 5);
if (gi->table_select[1] == 14)
gi->table_select[1] = 16;
writeheader(gfc, gi->table_select[1], 5);
writeheader(gfc, gi->subblock_gain[0], 3);
writeheader(gfc, gi->subblock_gain[1], 3);
writeheader(gfc, gi->subblock_gain[2], 3);
}
else {
writeheader(gfc, 0, 1); /* window_switching_flag */
if (gi->table_select[0] == 14)
gi->table_select[0] = 16;
writeheader(gfc, gi->table_select[0], 5);
if (gi->table_select[1] == 14)
gi->table_select[1] = 16;
writeheader(gfc, gi->table_select[1], 5);
if (gi->table_select[2] == 14)
gi->table_select[2] = 16;
writeheader(gfc, gi->table_select[2], 5);
assert(0 <= gi->region0_count && gi->region0_count < 16);
assert(0 <= gi->region1_count && gi->region1_count < 8);
writeheader(gfc, gi->region0_count, 4);
writeheader(gfc, gi->region1_count, 3);
}
writeheader(gfc, gi->scalefac_scale, 1);
writeheader(gfc, gi->count1table_select, 1);
}
}
if (cfg->error_protection) {
/* (jo) error_protection: add crc16 information to header */
CRC_writeheader(gfc, esv->header[esv->h_ptr].buf);
}
{
int const old = esv->h_ptr;
assert(esv->header[old].ptr == cfg->sideinfo_len * 8);
esv->h_ptr = (old + 1) & (MAX_HEADER_BUF - 1);
esv->header[esv->h_ptr].write_timing = esv->header[old].write_timing + bitsPerFrame;
if (esv->h_ptr == esv->w_ptr) {
/* yikes! we are out of header buffer space */
ERRORF(gfc, "Error: MAX_HEADER_BUF too small in bitstream.c \n");
}
}
}
inline static int
huffman_coder_count1(lame_internal_flags * gfc, gr_info const *gi)
{
/* Write count1 area */
struct huffcodetab const *const h = &ht[gi->count1table_select + 32];
int i, bits = 0;
#ifdef DEBUG
int gegebo = gfc->bs.totbit;
#endif
int const *ix = &gi->l3_enc[gi->big_values];
FLOAT const *xr = &gi->xr[gi->big_values];
assert(gi->count1table_select < 2);
for (i = (gi->count1 - gi->big_values) / 4; i > 0; --i) {
int huffbits = 0;
int p = 0, v;
v = ix[0];
if (v) {
p += 8;
if (xr[0] < 0.0f)
huffbits++;
assert(v <= 1);
}
v = ix[1];
if (v) {
p += 4;
huffbits *= 2;
if (xr[1] < 0.0f)
huffbits++;
assert(v <= 1);
}
v = ix[2];
if (v) {
p += 2;
huffbits *= 2;
if (xr[2] < 0.0f)
huffbits++;
assert(v <= 1);
}
v = ix[3];
if (v) {
p++;
huffbits *= 2;
if (xr[3] < 0.0f)
huffbits++;
assert(v <= 1);
}
ix += 4;
xr += 4;
putbits2(gfc, huffbits + h->table[p], h->hlen[p]);
bits += h->hlen[p];
}
#ifdef DEBUG
DEBUGF(gfc, "count1: real: %ld counted:%d (bigv %d count1len %d)\n",
gfc->bs.totbit - gegebo, gi->count1bits, gi->big_values, gi->count1);
#endif
return bits;
}
/*
Implements the pseudocode of page 98 of the IS
*/
inline static int
Huffmancode(lame_internal_flags * const gfc, const unsigned int tableindex,
int start, int end, gr_info const *gi)
{
struct huffcodetab const *const h = &ht[tableindex];
unsigned int const linbits = h->xlen;
int i, bits = 0;
assert(tableindex < 32u);
if (!tableindex)
return bits;
for (i = start; i < end; i += 2) {
int16_t cbits = 0;
uint16_t xbits = 0;
unsigned int xlen = h->xlen;
unsigned int ext = 0;
unsigned int x1 = gi->l3_enc[i];
unsigned int x2 = gi->l3_enc[i + 1];
assert(gi->l3_enc[i] >= 0);
assert(gi->l3_enc[i+1] >= 0);
if (x1 != 0u) {
if (gi->xr[i] < 0.0f)
ext++;
cbits--;
}
if (tableindex > 15u) {
/* use ESC-words */
if (x1 >= 15u) {
uint16_t const linbits_x1 = x1 - 15u;
assert(linbits_x1 <= h->linmax);
ext |= linbits_x1 << 1u;
xbits = linbits;
x1 = 15u;
}
if (x2 >= 15u) {
uint16_t const linbits_x2 = x2 - 15u;
assert(linbits_x2 <= h->linmax);
ext <<= linbits;
ext |= linbits_x2;
xbits += linbits;
x2 = 15u;
}
xlen = 16;
}
if (x2 != 0u) {
ext <<= 1;
if (gi->xr[i + 1] < 0.0f)
ext++;
cbits--;
}
assert((x1 | x2) < 16u);
x1 = x1 * xlen + x2;
xbits -= cbits;
cbits += h->hlen[x1];
assert(cbits <= MAX_LENGTH);
assert(xbits <= MAX_LENGTH);
putbits2(gfc, h->table[x1], cbits);
putbits2(gfc, (int)ext, xbits);
bits += cbits + xbits;
}
return bits;
}
/*
Note the discussion of huffmancodebits() on pages 28
and 29 of the IS, as well as the definitions of the side
information on pages 26 and 27.
*/
static int
ShortHuffmancodebits(lame_internal_flags * gfc, gr_info const *gi)
{
int bits;
int region1Start;
region1Start = 3 * gfc->scalefac_band.s[3];
if (region1Start > gi->big_values)
region1Start = gi->big_values;
/* short blocks do not have a region2 */
bits = Huffmancode(gfc, gi->table_select[0], 0, region1Start, gi);
bits += Huffmancode(gfc, gi->table_select[1], region1Start, gi->big_values, gi);
return bits;
}
static int
LongHuffmancodebits(lame_internal_flags * gfc, gr_info const *gi)
{
unsigned int i;
int bigvalues, bits;
int region1Start, region2Start;
bigvalues = gi->big_values;
assert(0 <= bigvalues && bigvalues <= 576);
assert(gi->region0_count >= -1);
assert(gi->region1_count >= -1);
i = gi->region0_count + 1;
assert((size_t) i < dimension_of(gfc->scalefac_band.l));
region1Start = gfc->scalefac_band.l[i];
i += gi->region1_count + 1;
assert((size_t) i < dimension_of(gfc->scalefac_band.l));
region2Start = gfc->scalefac_band.l[i];
if (region1Start > bigvalues)
region1Start = bigvalues;
if (region2Start > bigvalues)
region2Start = bigvalues;
bits = Huffmancode(gfc, gi->table_select[0], 0, region1Start, gi);
bits += Huffmancode(gfc, gi->table_select[1], region1Start, region2Start, gi);
bits += Huffmancode(gfc, gi->table_select[2], region2Start, bigvalues, gi);
return bits;
}
inline static int
writeMainData(lame_internal_flags * const gfc)
{
SessionConfig_t const *const cfg = &gfc->cfg;
III_side_info_t const *const l3_side = &gfc->l3_side;
int gr, ch, sfb, data_bits, tot_bits = 0;
if (cfg->version == 1) {
/* MPEG 1 */
for (gr = 0; gr < 2; gr++) {
for (ch = 0; ch < cfg->channels_out; ch++) {
gr_info const *const gi = &l3_side->tt[gr][ch];
int const slen1 = slen1_tab[gi->scalefac_compress];
int const slen2 = slen2_tab[gi->scalefac_compress];
data_bits = 0;
#ifdef DEBUG
hogege = gfc->bs.totbit;
#endif
for (sfb = 0; sfb < gi->sfbdivide; sfb++) {
if (gi->scalefac[sfb] == -1)
continue; /* scfsi is used */
putbits2(gfc, gi->scalefac[sfb], slen1);
data_bits += slen1;
}
for (; sfb < gi->sfbmax; sfb++) {
if (gi->scalefac[sfb] == -1)
continue; /* scfsi is used */
putbits2(gfc, gi->scalefac[sfb], slen2);
data_bits += slen2;
}
assert(data_bits == gi->part2_length);
if (gi->block_type == SHORT_TYPE) {
data_bits += ShortHuffmancodebits(gfc, gi);
}
else {
data_bits += LongHuffmancodebits(gfc, gi);
}
data_bits += huffman_coder_count1(gfc, gi);
#ifdef DEBUG
DEBUGF(gfc, "<%ld> ", gfc->bs.totbit - hogege);
#endif
/* does bitcount in quantize.c agree with actual bit count? */
assert(data_bits == gi->part2_3_length + gi->part2_length);
tot_bits += data_bits;
} /* for ch */
} /* for gr */
}
else {
/* MPEG 2 */
gr = 0;
for (ch = 0; ch < cfg->channels_out; ch++) {
gr_info const *const gi = &l3_side->tt[gr][ch];
int i, sfb_partition, scale_bits = 0;
assert(gi->sfb_partition_table);
data_bits = 0;
#ifdef DEBUG
hogege = gfc->bs.totbit;
#endif
sfb = 0;
sfb_partition = 0;
if (gi->block_type == SHORT_TYPE) {
for (; sfb_partition < 4; sfb_partition++) {
int const sfbs = gi->sfb_partition_table[sfb_partition] / 3;
int const slen = gi->slen[sfb_partition];
for (i = 0; i < sfbs; i++, sfb++) {
putbits2(gfc, Max(gi->scalefac[sfb * 3 + 0], 0), slen);
putbits2(gfc, Max(gi->scalefac[sfb * 3 + 1], 0), slen);
putbits2(gfc, Max(gi->scalefac[sfb * 3 + 2], 0), slen);
scale_bits += 3 * slen;
}
}
data_bits += ShortHuffmancodebits(gfc, gi);
}
else {
for (; sfb_partition < 4; sfb_partition++) {
int const sfbs = gi->sfb_partition_table[sfb_partition];
int const slen = gi->slen[sfb_partition];
for (i = 0; i < sfbs; i++, sfb++) {
putbits2(gfc, Max(gi->scalefac[sfb], 0), slen);
scale_bits += slen;
}
}
data_bits += LongHuffmancodebits(gfc, gi);
}
data_bits += huffman_coder_count1(gfc, gi);
#ifdef DEBUG
DEBUGF(gfc, "<%ld> ", gfc->bs.totbit - hogege);
#endif
/* does bitcount in quantize.c agree with actual bit count? */
assert(data_bits == gi->part2_3_length);
assert(scale_bits == gi->part2_length);
tot_bits += scale_bits + data_bits;
} /* for ch */
} /* for gf */
return tot_bits;
} /* main_data */
/* compute the number of bits required to flush all mp3 frames
currently in the buffer. This should be the same as the
reservoir size. Only call this routine between frames - i.e.
only after all headers and data have been added to the buffer
by format_bitstream().
Also compute total_bits_output =
size of mp3 buffer (including frame headers which may not
have yet been send to the mp3 buffer) +
number of bits needed to flush all mp3 frames.
total_bytes_output is the size of the mp3 output buffer if
lame_encode_flush_nogap() was called right now.
*/
int
compute_flushbits(const lame_internal_flags * gfc, int *total_bytes_output)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncStateVar_t const *const esv = &gfc->sv_enc;
int flushbits, remaining_headers;
int bitsPerFrame;
int last_ptr, first_ptr;
first_ptr = esv->w_ptr; /* first header to add to bitstream */
last_ptr = esv->h_ptr - 1; /* last header to add to bitstream */
if (last_ptr == -1)
last_ptr = MAX_HEADER_BUF - 1;
/* add this many bits to bitstream so we can flush all headers */
flushbits = esv->header[last_ptr].write_timing - gfc->bs.totbit;
*total_bytes_output = flushbits;
if (flushbits >= 0) {
/* if flushbits >= 0, some headers have not yet been written */
/* reduce flushbits by the size of the headers */
remaining_headers = 1 + last_ptr - first_ptr;
if (last_ptr < first_ptr)
remaining_headers = 1 + last_ptr - first_ptr + MAX_HEADER_BUF;
flushbits -= remaining_headers * 8 * cfg->sideinfo_len;
}
/* finally, add some bits so that the last frame is complete
* these bits are not necessary to decode the last frame, but
* some decoders will ignore last frame if these bits are missing
*/
bitsPerFrame = getframebits(gfc);
flushbits += bitsPerFrame;
*total_bytes_output += bitsPerFrame;
/* round up: */
if (*total_bytes_output % 8)
*total_bytes_output = 1 + (*total_bytes_output / 8);
else
*total_bytes_output = (*total_bytes_output / 8);
*total_bytes_output += gfc->bs.buf_byte_idx + 1;
if (flushbits < 0) {
#if 0
/* if flushbits < 0, this would mean that the buffer looks like:
* (data...) last_header (data...) (extra data that should not be here...)
*/
DEBUGF(gfc, "last header write_timing = %i \n", esv->header[last_ptr].write_timing);
DEBUGF(gfc, "first header write_timing = %i \n", esv->header[first_ptr].write_timing);
DEBUGF(gfc, "bs.totbit: %i \n", gfc->bs.totbit);
DEBUGF(gfc, "first_ptr, last_ptr %i %i \n", first_ptr, last_ptr);
DEBUGF(gfc, "remaining_headers = %i \n", remaining_headers);
DEBUGF(gfc, "bitsperframe: %i \n", bitsPerFrame);
DEBUGF(gfc, "sidelen: %i \n", cfg->sideinfo_len);
#endif
ERRORF(gfc, "strange error flushing buffer ... \n");
}
return flushbits;
}
void
flush_bitstream(lame_internal_flags * gfc)
{
EncStateVar_t *const esv = &gfc->sv_enc;
III_side_info_t *l3_side;
int nbytes;
int flushbits;
int last_ptr = esv->h_ptr - 1; /* last header to add to bitstream */
if (last_ptr == -1)
last_ptr = MAX_HEADER_BUF - 1;
l3_side = &gfc->l3_side;
if ((flushbits = compute_flushbits(gfc, &nbytes)) < 0)
return;
drain_into_ancillary(gfc, flushbits);
/* check that the 100% of the last frame has been written to bitstream */
assert(esv->header[last_ptr].write_timing + getframebits(gfc)
== gfc->bs.totbit);
/* we have padded out all frames with ancillary data, which is the
same as filling the bitreservoir with ancillary data, so : */
esv->ResvSize = 0;
l3_side->main_data_begin = 0;
}
void
add_dummy_byte(lame_internal_flags * gfc, unsigned char val, unsigned int n)
{
EncStateVar_t *const esv = &gfc->sv_enc;
int i;
while (n-- > 0u) {
putbits_noheaders(gfc, val, 8);
for (i = 0; i < MAX_HEADER_BUF; ++i)
esv->header[i].write_timing += 8;
}
}
/*
format_bitstream()
This is called after a frame of audio has been quantized and coded.
It will write the encoded audio to the bitstream. Note that
from a layer3 encoder's perspective the bit stream is primarily
a series of main_data() blocks, with header and side information
inserted at the proper locations to maintain framing. (See Figure A.7
in the IS).
*/
int
format_bitstream(lame_internal_flags * gfc)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncStateVar_t *const esv = &gfc->sv_enc;
int bits, nbytes;
III_side_info_t *l3_side;
int bitsPerFrame;
l3_side = &gfc->l3_side;
bitsPerFrame = getframebits(gfc);
drain_into_ancillary(gfc, l3_side->resvDrain_pre);
encodeSideInfo2(gfc, bitsPerFrame);
bits = 8 * cfg->sideinfo_len;
bits += writeMainData(gfc);
drain_into_ancillary(gfc, l3_side->resvDrain_post);
bits += l3_side->resvDrain_post;
l3_side->main_data_begin += (bitsPerFrame - bits) / 8;
/* compare number of bits needed to clear all buffered mp3 frames
* with what we think the resvsize is: */
if (compute_flushbits(gfc, &nbytes) != esv->ResvSize) {
ERRORF(gfc, "Internal buffer inconsistency. flushbits <> ResvSize");
}
/* compare main_data_begin for the next frame with what we
* think the resvsize is: */
if ((l3_side->main_data_begin * 8) != esv->ResvSize) {
ERRORF(gfc, "bit reservoir error: \n"
"l3_side->main_data_begin: %i \n"
"Resvoir size: %i \n"
"resv drain (post) %i \n"
"resv drain (pre) %i \n"
"header and sideinfo: %i \n"
"data bits: %i \n"
"total bits: %i (remainder: %i) \n"
"bitsperframe: %i \n",
8 * l3_side->main_data_begin,
esv->ResvSize,
l3_side->resvDrain_post,
l3_side->resvDrain_pre,
8 * cfg->sideinfo_len,
bits - l3_side->resvDrain_post - 8 * cfg->sideinfo_len,
bits, bits % 8, bitsPerFrame);
ERRORF(gfc, "This is a fatal error. It has several possible causes:");
ERRORF(gfc, "90%% LAME compiled with buggy version of gcc using advanced optimizations");
ERRORF(gfc, " 9%% Your system is overclocked");
ERRORF(gfc, " 1%% bug in LAME encoding library");
esv->ResvSize = l3_side->main_data_begin * 8;
};
assert(gfc->bs.totbit % 8 == 0);
if (gfc->bs.totbit > 1000000000) {
/* to avoid totbit overflow, (at 8h encoding at 128kbs) lets reset bit counter */
int i;
for (i = 0; i < MAX_HEADER_BUF; ++i)
esv->header[i].write_timing -= gfc->bs.totbit;
gfc->bs.totbit = 0;
}
return 0;
}
static int
do_gain_analysis(lame_internal_flags * gfc, unsigned char* buffer, int minimum)
{
SessionConfig_t const *const cfg = &gfc->cfg;
RpgStateVar_t const *const rsv = &gfc->sv_rpg;
RpgResult_t *const rov = &gfc->ov_rpg;
#ifdef DECODE_ON_THE_FLY
if (cfg->decode_on_the_fly) { /* decode the frame */
sample_t pcm_buf[2][1152];
int mp3_in = minimum;
int samples_out = -1;
/* re-synthesis to pcm. Repeat until we get a samples_out=0 */
while (samples_out != 0) {
samples_out = hip_decode1_unclipped(gfc->hip, buffer, mp3_in, pcm_buf[0], pcm_buf[1]);
/* samples_out = 0: need more data to decode
* samples_out = -1: error. Lets assume 0 pcm output
* samples_out = number of samples output */
/* set the lenght of the mp3 input buffer to zero, so that in the
* next iteration of the loop we will be querying mpglib about
* buffered data */
mp3_in = 0;
if (samples_out == -1) {
/* error decoding. Not fatal, but might screw up
* the ReplayGain tag. What should we do? Ignore for now */
samples_out = 0;
}
if (samples_out > 0) {
/* process the PCM data */
/* this should not be possible, and indicates we have
* overflown the pcm_buf buffer */
assert(samples_out <= 1152);
if (cfg->findPeakSample) {
int i;
/* FIXME: is this correct? maybe Max(fabs(pcm),PeakSample) */
for (i = 0; i < samples_out; i++) {
if (pcm_buf[0][i] > rov->PeakSample)
rov->PeakSample = pcm_buf[0][i];
else if (-pcm_buf[0][i] > rov->PeakSample)
rov->PeakSample = -pcm_buf[0][i];
}
if (cfg->channels_out > 1)
for (i = 0; i < samples_out; i++) {
if (pcm_buf[1][i] > rov->PeakSample)
rov->PeakSample = pcm_buf[1][i];
else if (-pcm_buf[1][i] > rov->PeakSample)
rov->PeakSample = -pcm_buf[1][i];
}
}
if (cfg->findReplayGain)
if (AnalyzeSamples
(rsv->rgdata, pcm_buf[0], pcm_buf[1], samples_out,
cfg->channels_out) == GAIN_ANALYSIS_ERROR)
return -6;
} /* if (samples_out>0) */
} /* while (samples_out!=0) */
} /* if (gfc->decode_on_the_fly) */
#endif
return minimum;
}
static int
do_copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int size)
{
Bit_stream_struc *const bs = &gfc->bs;
int const minimum = bs->buf_byte_idx + 1;
if (minimum <= 0)
return 0;
if (size != 0 && minimum > size)
return -1; /* buffer is too small */
memcpy(buffer, bs->buf, minimum);
bs->buf_byte_idx = -1;
bs->buf_bit_idx = 0;
return minimum;
}
/* copy data out of the internal MP3 bit buffer into a user supplied
unsigned char buffer.
mp3data=0 indicates data in buffer is an id3tags and VBR tags
mp3data=1 data is real mp3 frame data.
*/
int
copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int size, int mp3data)
{
int const minimum = do_copy_buffer(gfc, buffer, size);
if (minimum > 0 && mp3data) {
UpdateMusicCRC(&gfc->nMusicCRC, buffer, minimum);
/** sum number of bytes belonging to the mp3 stream
* this info will be written into the Xing/LAME header for seeking
*/
gfc->VBR_seek_table.nBytesWritten += minimum;
return do_gain_analysis(gfc, buffer, minimum);
} /* if (mp3data) */
return minimum;
}
void
init_bit_stream_w(lame_internal_flags * gfc)
{
EncStateVar_t *const esv = &gfc->sv_enc;
esv->h_ptr = esv->w_ptr = 0;
esv->header[esv->h_ptr].write_timing = 0;
gfc->bs.buf = (unsigned char *) malloc(BUFFER_SIZE);
gfc->bs.buf_size = BUFFER_SIZE;
gfc->bs.buf_byte_idx = -1;
gfc->bs.buf_bit_idx = 0;
gfc->bs.totbit = 0;
}
/* end of bitstream.c */
================================================
FILE: app/src/main/jni/libmp3lame/bitstream.h
================================================
/*
* MP3 bitstream Output interface for LAME
*
* Copyright (c) 1999 Takehiro TOMINAGA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef LAME_BITSTREAM_H
#define LAME_BITSTREAM_H
int getframebits(const lame_internal_flags * gfc);
int format_bitstream(lame_internal_flags * gfc);
void flush_bitstream(lame_internal_flags * gfc);
void add_dummy_byte(lame_internal_flags * gfc, unsigned char val, unsigned int n);
int copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int buffer_size,
int update_crc);
void init_bit_stream_w(lame_internal_flags * gfc);
void CRC_writeheader(lame_internal_flags const *gfc, char *buffer);
int compute_flushbits(const lame_internal_flags * gfp, int *nbytes);
int get_max_frame_buffer_size_by_constraint(SessionConfig_t const * cfg, int constraint);
#endif
================================================
FILE: app/src/main/jni/libmp3lame/encoder.c
================================================
/*
* LAME MP3 encoding engine
*
* Copyright (c) 1999 Mark Taylor
* Copyright (c) 2000-2002 Takehiro Tominaga
* Copyright (c) 2000-2011 Robert Hegemann
* Copyright (c) 2001 Gabriel Bouvigne
* Copyright (c) 2001 John Dahlstrom
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* $Id: encoder.c,v 1.111 2011/05/07 16:05:17 rbrito Exp $ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "lame.h"
#include "machine.h"
#include "encoder.h"
#include "util.h"
#include "lame_global_flags.h"
#include "newmdct.h"
#include "psymodel.h"
#include "lame-analysis.h"
#include "bitstream.h"
#include "VbrTag.h"
#include "quantize_pvt.h"
/*
* auto-adjust of ATH, useful for low volume
* Gabriel Bouvigne 3 feb 2001
*
* modifies some values in
* gfp->internal_flags->ATH
* (gfc->ATH)
*/
static void
adjust_ATH(lame_internal_flags const *const gfc)
{
SessionConfig_t const *const cfg = &gfc->cfg;
FLOAT gr2_max, max_pow;
if (gfc->ATH->use_adjust == 0) {
gfc->ATH->adjust_factor = 1.0; /* no adjustment */
return;
}
/* jd - 2001 mar 12, 27, jun 30 */
/* loudness based on equal loudness curve; */
/* use granule with maximum combined loudness */
max_pow = gfc->ov_psy.loudness_sq[0][0];
gr2_max = gfc->ov_psy.loudness_sq[1][0];
if (cfg->channels_out == 2) {
max_pow += gfc->ov_psy.loudness_sq[0][1];
gr2_max += gfc->ov_psy.loudness_sq[1][1];
}
else {
max_pow += max_pow;
gr2_max += gr2_max;
}
if (cfg->mode_gr == 2) {
max_pow = Max(max_pow, gr2_max);
}
max_pow *= 0.5; /* max_pow approaches 1.0 for full band noise */
/* jd - 2001 mar 31, jun 30 */
/* user tuning of ATH adjustment region */
max_pow *= gfc->ATH->aa_sensitivity_p;
/* adjust ATH depending on range of maximum value
*/
/* jd - 2001 feb27, mar12,20, jun30, jul22 */
/* continuous curves based on approximation */
/* to GB's original values. */
/* For an increase in approximate loudness, */
/* set ATH adjust to adjust_limit immediately */
/* after a delay of one frame. */
/* For a loudness decrease, reduce ATH adjust */
/* towards adjust_limit gradually. */
/* max_pow is a loudness squared or a power. */
if (max_pow > 0.03125) { /* ((1 - 0.000625)/ 31.98) from curve below */
if (gfc->ATH->adjust_factor >= 1.0) {
gfc->ATH->adjust_factor = 1.0;
}
else {
/* preceding frame has lower ATH adjust; */
/* ascend only to the preceding adjust_limit */
/* in case there is leading low volume */
if (gfc->ATH->adjust_factor < gfc->ATH->adjust_limit) {
gfc->ATH->adjust_factor = gfc->ATH->adjust_limit;
}
}
gfc->ATH->adjust_limit = 1.0;
}
else { /* adjustment curve */
/* about 32 dB maximum adjust (0.000625) */
FLOAT const adj_lim_new = 31.98 * max_pow + 0.000625;
if (gfc->ATH->adjust_factor >= adj_lim_new) { /* descend gradually */
gfc->ATH->adjust_factor *= adj_lim_new * 0.075 + 0.925;
if (gfc->ATH->adjust_factor < adj_lim_new) { /* stop descent */
gfc->ATH->adjust_factor = adj_lim_new;
}
}
else { /* ascend */
if (gfc->ATH->adjust_limit >= adj_lim_new) {
gfc->ATH->adjust_factor = adj_lim_new;
}
else { /* preceding frame has lower ATH adjust; */
/* ascend only to the preceding adjust_limit */
if (gfc->ATH->adjust_factor < gfc->ATH->adjust_limit) {
gfc->ATH->adjust_factor = gfc->ATH->adjust_limit;
}
}
}
gfc->ATH->adjust_limit = adj_lim_new;
}
}
/***********************************************************************
*
* some simple statistics
*
* bitrate index 0: free bitrate -> not allowed in VBR mode
* : bitrates, kbps depending on MPEG version
* bitrate index 15: forbidden
*
* mode_ext:
* 0: LR
* 1: LR-i
* 2: MS
* 3: MS-i
*
***********************************************************************/
static void
updateStats(lame_internal_flags * const gfc)
{
SessionConfig_t const *const cfg = &gfc->cfg;
EncResult_t *eov = &gfc->ov_enc;
int gr, ch;
assert(0 <= eov->bitrate_index && eov->bitrate_index < 16);
assert(0 <= eov->mode_ext && eov->mode_ext < 4);
/* count bitrate indices */
eov->bitrate_channelmode_hist[eov->bitrate_index][4]++;
eov->bitrate_channelmode_hist[15][4]++;
/* count 'em for every mode extension in case of 2 channel encoding */
if (cfg->channels_out == 2) {
eov->bitrate_channelmode_hist[eov->bitrate_index][eov->mode_ext]++;
eov->bitrate_channelmode_hist[15][eov->mode_ext]++;
}
for (gr = 0; gr < cfg->mode_gr; ++gr) {
for (ch = 0; ch < cfg->channels_out; ++ch) {
int bt = gfc->l3_side.tt[gr][ch].block_type;
if (gfc->l3_side.tt[gr][ch].mixed_block_flag)
bt = 4;
eov->bitrate_blocktype_hist[eov->bitrate_index][bt]++;
eov->bitrate_blocktype_hist[eov->bitrate_index][5]++;
eov->bitrate_blocktype_hist[15][bt]++;
eov->bitrate_blocktype_hist[15][5]++;
}
}
}
static void
lame_encode_frame_init(lame_internal_flags * gfc, const sample_t *const inbuf[2])
{
SessionConfig_t const *const cfg = &gfc->cfg;
int ch, gr;
if (gfc->lame_encode_frame_init == 0) {
sample_t primebuff0[286 + 1152 + 576];
sample_t primebuff1[286 + 1152 + 576];
int const framesize = 576 * cfg->mode_gr;
/* prime the MDCT/polyphase filterbank with a short block */
int i, j;
gfc->lame_encode_frame_init = 1;
memset(primebuff0, 0, sizeof(primebuff0));
memset(primebuff1, 0, sizeof(primebuff1));
for (i = 0, j = 0; i < 286 + 576 * (1 + cfg->mode_gr); ++i) {
if (i < framesize) {
primebuff0[i] = 0;
if (cfg->channels_out == 2)
primebuff1[i] = 0;
}
else {
primebuff0[i] = inbuf[0][j];
if (cfg->channels_out == 2)
primebuff1[i] = inbuf[1][j];
++j;
}
}
/* polyphase filtering / mdct */
for (gr = 0; gr < cfg->mode_gr; gr++) {
for (ch = 0; ch < cfg->channels_out; ch++) {
gfc->l3_side.tt[gr][ch].block_type = SHORT_TYPE;
}
}
mdct_sub48(gfc, primebuff0, primebuff1);
/* check FFT will not use a negative starting offset */
#if 576 < FFTOFFSET
# error FFTOFFSET greater than 576: FFT uses a negative offset
#endif
/* check if we have enough data for FFT */
assert(gfc->sv_enc.mf_size >= (BLKSIZE + framesize - FFTOFFSET));
/* check if we have enough data for polyphase filterbank */
assert(gfc->sv_enc.mf_size >= (512 + framesize - 32));
}
}
/************************************************************************
*
* encodeframe() Layer 3
*
* encode a single frame
*
************************************************************************
lame_encode_frame()
gr 0 gr 1
inbuf: |--------------|--------------|--------------|
Polyphase (18 windows, each shifted 32)
gr 0:
window1 <----512---->
window18 <----512---->
gr 1:
window1 <----512---->
window18 <----512---->
MDCT output: |--------------|--------------|--------------|
FFT's <---------1024---------->
<---------1024-------->
inbuf = buffer of PCM data size=MP3 framesize
encoder acts on inbuf[ch][0], but output is delayed by MDCTDELAY
so the MDCT coefficints are from inbuf[ch][-MDCTDELAY]
psy-model FFT has a 1 granule delay, so we feed it data for the
next granule.
FFT is centered over granule: 224+576+224
So FFT starts at: 576-224-MDCTDELAY
MPEG2: FFT ends at: BLKSIZE+576-224-MDCTDELAY (1328)
MPEG1: FFT ends at: BLKSIZE+2*576-224-MDCTDELAY (1904)
MPEG2: polyphase first window: [0..511]
18th window: [544..1055] (1056)
MPEG1: 36th window: [1120..1631] (1632)
data needed: 512+framesize-32
A close look newmdct.c shows that the polyphase filterbank
only uses data from [0..510] for each window. Perhaps because the window
used by the filterbank is zero for the last point, so Takehiro's
code doesn't bother to compute with it.
FFT starts at 576-224-MDCTDELAY (304) = 576-FFTOFFSET
*/
typedef FLOAT chgrdata[2][2];
int
lame_encode_mp3_frame( /* Output */
lame_internal_flags * gfc, /* Context */
sample_t const *inbuf_l, /* Input */
sample_t const *inbuf_r, /* Input */
unsigned char *mp3buf, /* Output */
int mp3buf_size)
{ /* Output */
SessionConfig_t const *const cfg = &gfc->cfg;
int mp3count;
III_psy_ratio masking_LR[2][2]; /*LR masking & energy */
III_psy_ratio masking_MS[2][2]; /*MS masking & energy */
const III_psy_ratio (*masking)[2]; /*pointer to selected maskings */
const sample_t *inbuf[2];
FLOAT tot_ener[2][4];
FLOAT ms_ener_ratio[2] = { .5, .5 };
FLOAT pe[2][2] = { {0., 0.}, {0., 0.} }, pe_MS[2][2] = { {
0., 0.}, {
0., 0.}};
FLOAT (*pe_use)[2];
int ch, gr;
inbuf[0] = inbuf_l;
inbuf[1] = inbuf_r;
if (gfc->lame_encode_frame_init == 0) {
/*first run? */
lame_encode_frame_init(gfc, inbuf);
}
/********************** padding *****************************/
/* padding method as described in
* "MPEG-Layer3 / Bitstream Syntax and Decoding"
* by Martin Sieler, Ralph Sperschneider
*
* note: there is no padding for the very first frame
*
* Robert Hegemann 2000-06-22
*/
gfc->ov_enc.padding = FALSE;
if ((gfc->sv_enc.slot_lag -= gfc->sv_enc.frac_SpF) < 0) {
gfc->sv_enc.slot_lag += cfg->samplerate_out;
gfc->ov_enc.padding = TRUE;
}
/****************************************
* Stage 1: psychoacoustic model *
****************************************/
{
/* psychoacoustic model
* psy model has a 1 granule (576) delay that we must compensate for
* (mt 6/99).
*/
int ret;
const sample_t *bufp[2] = {0, 0}; /* address of beginning of left & right granule */
int blocktype[2];
for (gr = 0; gr < cfg->mode_gr; gr++) {
for (ch = 0; ch < cfg->channels_out; ch++) {
bufp[ch] = &inbuf[ch][576 + gr * 576 - FFTOFFSET];
}
ret = L3psycho_anal_vbr(gfc, bufp, gr,
masking_LR, masking_MS,
pe[gr], pe_MS[gr], tot_ener[gr], blocktype);
if (ret != 0)
return -4;
if (cfg->mode == JOINT_STEREO) {
ms_ener_ratio[gr] = tot_ener[gr][2] + tot_ener[gr][3];
if (ms_ener_ratio[gr] > 0)
ms_ener_ratio[gr] = tot_ener[gr][3] / ms_ener_ratio[gr];
}
/* block type flags */
for (ch = 0; ch < cfg->channels_out; ch++) {
gr_info *const cod_info = &gfc->l3_side.tt[gr][ch];
cod_info->block_type = blocktype[ch];
cod_info->mixed_block_flag = 0;
}
}
}
/* auto-adjust of ATH, useful for low volume */
adjust_ATH(gfc);
/****************************************
* Stage 2: MDCT *
****************************************/
/* polyphase filtering / mdct */
mdct_sub48(gfc, inbuf[0], inbuf[1]);
/****************************************
* Stage 3: MS/LR decision *
****************************************/
/* Here will be selected MS or LR coding of the 2 stereo channels */
gfc->ov_enc.mode_ext = MPG_MD_LR_LR;
if (cfg->force_ms) {
gfc->ov_enc.mode_ext = MPG_MD_MS_LR;
}
else if (cfg->mode == JOINT_STEREO) {
/* ms_ratio = is scaled, for historical reasons, to look like
a ratio of side_channel / total.
0 = signal is 100% mono
.5 = L & R uncorrelated
*/
/* [0] and [1] are the results for the two granules in MPEG-1,
* in MPEG-2 it's only a faked averaging of the same value
* _prev is the value of the last granule of the previous frame
* _next is the value of the first granule of the next frame
*/
FLOAT sum_pe_MS = 0;
FLOAT sum_pe_LR = 0;
for (gr = 0; gr < cfg->mode_gr; gr++) {
for (ch = 0; ch < cfg->channels_out; ch++) {
sum_pe_MS += pe_MS[gr][ch];
sum_pe_LR += pe[gr][ch];
}
}
/* based on PE: M/S coding would not use much more bits than L/R */
if (sum_pe_MS <= 1.00 * sum_pe_LR) {
gr_info const *const gi0 = &gfc->l3_side.tt[0][0];
gr_info const *const gi1 = &gfc->l3_side.tt[cfg->mode_gr - 1][0];
if (gi0[0].block_type == gi0[1].block_type && gi1[0].block_type == gi1[1].block_type) {
gfc->ov_enc.mode_ext = MPG_MD_MS_LR;
}
}
}
/* bit and noise allocation */
if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) {
masking = (const III_psy_ratio (*)[2])masking_MS; /* use MS masking */
pe_use = pe_MS;
}
else {
masking = (const III_psy_ratio (*)[2])masking_LR; /* use LR masking */
pe_use = pe;
}
/* copy data for MP3 frame analyzer */
if (cfg->analysis && gfc->pinfo != NULL) {
for (gr = 0; gr < cfg->mode_gr; gr++) {
for (ch = 0; ch < cfg->channels_out; ch++) {
gfc->pinfo->ms_ratio[gr] = 0;
gfc->pinfo->ms_ener_ratio[gr] = ms_ener_ratio[gr];
gfc->pinfo->blocktype[gr][ch] = gfc->l3_side.tt[gr][ch].block_type;
gfc->pinfo->pe[gr][ch] = pe_use[gr][ch];
memcpy(gfc->pinfo->xr[gr][ch], &gfc->l3_side.tt[gr][ch].xr[0], sizeof(FLOAT) * 576);
/* in psymodel, LR and MS data was stored in pinfo.
switch to MS data: */
if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) {
gfc->pinfo->ers[gr][ch] = gfc->pinfo->ers[gr][ch + 2];
memcpy(gfc->pinfo->energy[gr][ch], gfc->pinfo->energy[gr][ch + 2],
sizeof(gfc->pinfo->energy[gr][ch]));
}
}
}
}
/****************************************
* Stage 4: quantization loop *
****************************************/
if (cfg->vbr == vbr_off || cfg->vbr == vbr_abr) {
static FLOAT const fircoef[9] = {
-0.0207887 * 5, -0.0378413 * 5, -0.0432472 * 5, -0.031183 * 5,
7.79609e-18 * 5, 0.0467745 * 5, 0.10091 * 5, 0.151365 * 5,
0.187098 * 5
};
int i;
FLOAT f;
for (i = 0; i < 18; i++)
gfc->sv_enc.pefirbuf[i] = gfc->sv_enc.pefirbuf[i + 1];
f = 0.0;
for (gr = 0; gr < cfg->mode_gr; gr++)
for (ch = 0; ch < cfg->channels_out; ch++)
f += pe_use[gr][ch];
gfc->sv_enc.pefirbuf[18] = f;
f = gfc->sv_enc.pefirbuf[9];
for (i = 0; i < 9; i++)
f += (gfc->sv_enc.pefirbuf[i] + gfc->sv_enc.pefirbuf[18 - i]) * fircoef[i];
f = (670 * 5 * cfg->mode_gr * cfg->channels_out) / f;
for (gr = 0; gr < cfg->mode_gr; gr++) {
for (ch = 0; ch < cfg->channels_out; ch++) {
pe_use[gr][ch] *= f;
}
}
}
gfc->iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking);
/****************************************
* Stage 5: bitstream formatting *
****************************************/
/* write the frame to the bitstream */
(void) format_bitstream(gfc);
/* copy mp3 bit buffer into array */
mp3count = copy_buffer(gfc, mp3buf, mp3buf_size, 1);
if (cfg->write_lame_tag) {
AddVbrFrame(gfc);
}
if (cfg->analysis && gfc->pinfo != NULL) {
int framesize = 576 * cfg->mode_gr;
for (ch = 0; ch < cfg->channels_out; ch++) {
int j;
for (j = 0; j < FFTOFFSET; j++)
gfc->pinfo->pcmdata[ch][j] = gfc->pinfo->pcmdata[ch][j + framesize];
for (j = FFTOFFSET; j < 1600; j++) {
gfc->pinfo->pcmdata[ch][j] = inbuf[ch][j - FFTOFFSET];
}
}
gfc->sv_qnt.masking_lower = 1.0;
set_frame_pinfo(gfc, masking);
}
++gfc->ov_enc.frame_number;
updateStats(gfc);
return mp3count;
}
================================================
FILE: app/src/main/jni/libmp3lame/encoder.h
================================================
/*
* encoder.h include file
*
* Copyright (c) 2000 Mark Taylor
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef LAME_ENCODER_H
#define LAME_ENCODER_H
/***********************************************************************
*
* encoder and decoder delays
*
***********************************************************************/
/*
* layer III enc->dec delay: 1056 (1057?) (observed)
* layer II enc->dec delay: 480 (481?) (observed)
*
* polyphase 256-16 (dec or enc) = 240
* mdct 256+32 (9*32) (dec or enc) = 288
* total: 512+16
*
* My guess is that delay of polyphase filterbank is actualy 240.5
* (there are technical reasons for this, see postings in mp3encoder).
* So total Encode+Decode delay = ENCDELAY + 528 + 1
*/
/*
* ENCDELAY The encoder delay.
*
* Minimum allowed is MDCTDELAY (see below)
*
* The first 96 samples will be attenuated, so using a value less than 96
* will result in corrupt data for the first 96-ENCDELAY samples.
*
* suggested: 576
* set to 1160 to sync with FhG.
*/
#define ENCDELAY 576
/*
* make sure there is at least one complete frame after the
* last frame containing real data
*
* Using a value of 288 would be sufficient for a
* a very sophisticated decoder that can decode granule-by-granule instead
* of frame by frame. But lets not assume this, and assume the decoder
* will not decode frame N unless it also has data for frame N+1
*
*/
/*#define POSTDELAY 288*/
#define POSTDELAY 1152
/*
* delay of the MDCT used in mdct.c
* original ISO routines had a delay of 528!
* Takehiro's routines:
*/
#define MDCTDELAY 48
#define FFTOFFSET (224+MDCTDELAY)
/*
* Most decoders, including the one we use, have a delay of 528 samples.
*/
#define DECDELAY 528
/* number of subbands */
#define SBLIMIT 32
/* parition bands bands */
#define CBANDS 64
/* number of critical bands/scale factor bands where masking is computed*/
#define SBPSY_l 21
#define SBPSY_s 12
/* total number of scalefactor bands encoded */
#define SBMAX_l 22
#define SBMAX_s 13
#define PSFB21 6
#define PSFB12 6
/* FFT sizes */
#define BLKSIZE 1024
#define HBLKSIZE (BLKSIZE/2 + 1)
#define BLKSIZE_s 256
#define HBLKSIZE_s (BLKSIZE_s/2 + 1)
/* #define switch_pe 1800 */
#define NORM_TYPE 0
#define START_TYPE 1
#define SHORT_TYPE 2
#define STOP_TYPE 3
/*
* Mode Extention:
* When we are in stereo mode, there are 4 possible methods to store these
* two channels. The stereo modes -m? are using a subset of them.
*
* -ms: MPG_MD_LR_LR
* -mj: MPG_MD_LR_LR and MPG_MD_MS_LR
* -mf: MPG_MD_MS_LR
* -mi: all
*/
#if 0
#define MPG_MD_LR_LR 0
#define MPG_MD_LR_I 1
#define MPG_MD_MS_LR 2
#define MPG_MD_MS_I 3
#endif
enum MPEGChannelMode
{ MPG_MD_LR_LR = 0
, MPG_MD_LR_I = 1
, MPG_MD_MS_LR = 2
, MPG_MD_MS_I = 3
};
#ifndef lame_internal_flags_defined
#define lame_internal_flags_defined
struct lame_internal_flags;
typedef struct lame_internal_flags lame_internal_flags;
#endif
int lame_encode_mp3_frame(lame_internal_flags * gfc,
sample_t const *inbuf_l,
sample_t const *inbuf_r, unsigned char *mp3buf, int mp3buf_size);
#endif /* LAME_ENCODER_H */
================================================
FILE: app/src/main/jni/libmp3lame/fft.c
================================================
/*
** FFT and FHT routines
** Copyright 1988, 1993; Ron Mayer
** Copyright (c) 1999-2000 Takehiro Tominaga
**
** fht(fz,n);
** Does a hartley transform of "n" points in the array "fz".
**
** NOTE: This routine uses at least 2 patented algorithms, and may be
** under the restrictions of a bunch of different organizations.
** Although I wrote it completely myself; it is kind of a derivative
** of a routine I once authored and released under the GPL, so it
** may fall under the free software foundation's restrictions;
** it was worked on as a Stanford Univ project, so they claim
** some rights to it; it was further optimized at work here, so
** I think this company claims parts of it. The patents are
** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
** trig generator), both at Stanford Univ.
** If it were up to me, I'd say go do whatever you want with it;
** but it would be polite to give credit to the following people
** if you use this anywhere:
** Euler - probable inventor of the fourier transform.
** Gauss - probable inventor of the FFT.
** Hartley - probable inventor of the hartley transform.
** Buneman - for a really cool trig generator
** Mayer(me) - for authoring this particular version and
** including all the optimizations in one package.
** Thanks,
** Ron Mayer; mayer@acuson.com
** and added some optimization by
** Mather - idea of using lookup table
** Takehiro - some dirty hack for speed up
*/
/* $Id: fft.c,v 1.38 2009/04/20 21:48:00 robert Exp $ */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "lame.h"
#include "machine.h"
#include "encoder.h"
#include "util.h"
#include "fft.h"
//#include "vector/lame_intrin.h"
#define TRI_SIZE (5-1) /* 1024 = 4**5 */
/* fft.c */
static FLOAT window[BLKSIZE], window_s[BLKSIZE_s / 2];
static const FLOAT costab[TRI_SIZE * 2] = {
9.238795325112867e-01, 3.826834323650898e-01,
9.951847266721969e-01, 9.801714032956060e-02,
9.996988186962042e-01, 2.454122852291229e-02,
9.999811752826011e-01, 6.135884649154475e-03
};
static void
fht(FLOAT * fz, int n)
{
const FLOAT *tri = costab;
int k4;
FLOAT *fi, *gi;
FLOAT const *fn;
n <<= 1; /* to get BLKSIZE, because of 3DNow! ASM routine */
fn = fz + n;
k4 = 4;
do {
FLOAT s1, c1;
int i, k1, k2, k3, kx;
kx = k4 >> 1;
k1 = k4;
k2 = k4 << 1;
k3 = k2 + k1;
k4 = k2 << 1;
fi = fz;
gi = fi + kx;
do {
FLOAT f0, f1, f2, f3;
f1 = fi[0] - fi[k1];
f0 = fi[0] + fi[k1];
f3 = fi[k2] - fi[k3];
f2 = fi[k2] + fi[k3];
fi[k2] = f0 - f2;
fi[0] = f0 + f2;
fi[k3] = f1 - f3;
fi[k1] = f1 + f3;
f1 = gi[0] - gi[k1];
f0 = gi[0] + gi[k1];
f3 = SQRT2 * gi[k3];
f2 = SQRT2 * gi[k2];
gi[k2] = f0 - f2;
gi[0] = f0 + f2;
gi[k3] = f1 - f3;
gi[k1] = f1 + f3;
gi += k4;
fi += k4;
} while (fi < fn);
c1 = tri[0];
s1 = tri[1];
for (i = 1; i < kx; i++) {
FLOAT c2, s2;
c2 = 1 - (2 * s1) * s1;
s2 = (2 * s1) * c1;
fi = fz + i;
gi = fz + k1 - i;
do {
FLOAT a, b, g0, f0, f1, g1, f2, g2, f3, g3;
b = s2 * fi[k1] - c2 * gi[k1];
a = c2 * fi[k1] + s2 * gi[k1];
f1 = fi[0] - a;
f0 = fi[0] + a;
g1 = gi[0] - b;
g0 = gi[0] + b;
b = s2 * fi[k3] - c2 * gi[k3];
a = c2 * fi[k3] + s2 * gi[k3];
f3 = fi[k2] - a;
f2 = fi[k2] + a;
g3 = gi[k2] - b;
g2 = gi[k2] + b;
b = s1 * f2 - c1 * g3;
a = c1 * f2 + s1 * g3;
fi[k2] = f0 - a;
fi[0] = f0 + a;
gi[k3] = g1 - b;
gi[k1] = g1 + b;
b = c1 * g2 - s1 * f3;
a = s1 * g2 + c1 * f3;
gi[k2] = g0 - a;
gi[0] = g0 + a;
fi[k3] = f1 - b;
fi[k1] = f1 + b;
gi += k4;
fi += k4;
} while (fi < fn);
c2 = c1;
c1 = c2 * tri[0] - s1 * tri[1];
s1 = c2 * tri[1] + s1 * tri[0];
}
tri += 2;
} while (k4 < n);
}
static const unsigned char rv_tbl[] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe
};
#define ch01(index) (buffer[chn][index])
#define ml00(f) (window[i ] * f(i))
#define ml10(f) (window[i + 0x200] * f(i + 0x200))
#define ml20(f) (window[i + 0x100] * f(i + 0x100))
#define ml30(f) (window[i + 0x300] * f(i + 0x300))
#define ml01(f) (window[i + 0x001] * f(i + 0x001))
#define ml11(f) (window[i + 0x201] * f(i + 0x201))
#define ml21(f) (window[i + 0x101] * f(i + 0x101))
#define ml31(f) (window[i + 0x301] * f(i + 0x301))
#define ms00(f) (window_s[i ] * f(i + k))
#define ms10(f) (window_s[0x7f - i] * f(i + k + 0x80))
#define ms20(f) (window_s[i + 0x40] * f(i + k + 0x40))
#define ms30(f) (window_s[0x3f - i] * f(i + k + 0xc0))
#define ms01(f) (window_s[i + 0x01] * f(i + k + 0x01))
#define ms11(f) (window_s[0x7e - i] * f(i + k + 0x81))
#define ms21(f) (window_s[i + 0x41] * f(i + k + 0x41))
#define ms31(f) (window_s[0x3e - i] * f(i + k + 0xc1))
void
fft_short(lame_internal_flags const *const gfc,
FLOAT x_real[3][BLKSIZE_s], int chn, const sample_t *const buffer[2])
{
int i;
int j;
int b;
for (b = 0; b < 3; b++) {
FLOAT *x = &x_real[b][BLKSIZE_s / 2];
short const k = (576 / 3) * (b + 1);
j = BLKSIZE_s / 8 - 1;
do {
FLOAT f0, f1, f2, f3, w;
i = rv_tbl[j << 2];
f0 = ms00(ch01);
w = ms10(ch01);
f1 = f0 - w;
f0 = f0 + w;
f2 = ms20(ch01);
w = ms30(ch01);
f3 = f2 - w;
f2 = f2 + w;
x -= 4;
x[0] = f0 + f2;
x[2] = f0 - f2;
x[1] = f1 + f3;
x[3] = f1 - f3;
f0 = ms01(ch01);
w = ms11(ch01);
f1 = f0 - w;
f0 = f0 + w;
f2 = ms21(ch01);
w = ms31(ch01);
f3 = f2 - w;
f2 = f2 + w;
x[BLKSIZE_s / 2 + 0] = f0 + f2;
x[BLKSIZE_s / 2 + 2] = f0 - f2;
x[BLKSIZE_s / 2 + 1] = f1 + f3;
x[BLKSIZE_s / 2 + 3] = f1 - f3;
} while (--j >= 0);
gfc->fft_fht(x, BLKSIZE_s / 2);
/* BLKSIZE_s/2 because of 3DNow! ASM routine */
}
}
void
fft_long(lame_internal_flags const *const gfc,
FLOAT x[BLKSIZE], int chn, const sample_t *const buffer[2])
{
int i;
int jj = BLKSIZE / 8 - 1;
x += BLKSIZE / 2;
do {
FLOAT f0, f1, f2, f3, w;
i = rv_tbl[jj];
f0 = ml00(ch01);
w = ml10(ch01);
f1 = f0 - w;
f0 = f0 + w;
f2 = ml20(ch01);
w = ml30(ch01);
f3 = f2 - w;
f2 = f2 + w;
x -= 4;
x[0] = f0 + f2;
x[2] = f0 - f2;
x[1] = f1 + f3;
x[3] = f1 - f3;
f0 = ml01(ch01);
w = ml11(ch01);
f1 = f0 - w;
f0 = f0 + w;
f2 = ml21(ch01);
w = ml31(ch01);
f3 = f2 - w;
f2 = f2 + w;
x[BLKSIZE / 2 + 0] = f0 + f2;
x[BLKSIZE / 2 + 2] = f0 - f2;
x[BLKSIZE / 2 + 1] = f1 + f3;
x[BLKSIZE / 2 + 3] = f1 - f3;
} while (--jj >= 0);
gfc->fft_fht(x, BLKSIZE / 2);
/* BLKSIZE/2 because of 3DNow! ASM routine */
}
#ifdef HAVE_NASM
extern void fht_3DN(FLOAT * fz, int n);
extern void fht_SSE(FLOAT * fz, int n);
#endif
void
init_fft(lame_internal_flags * const gfc)
{
int i;
/* The type of window used here will make no real difference, but */
/* in the interest of merging nspsytune stuff - switch to blackman window */
for (i = 0; i < BLKSIZE; i++)
/* blackman window */
window[i] = 0.42 - 0.5 * cos(2 * PI * (i + .5) / BLKSIZE) +
0.08 * cos(4 * PI * (i + .5) / BLKSIZE);
for (i = 0; i < BLKSIZE_s / 2; i++)
window_s[i] = 0.5 * (1.0 - cos(2.0 * PI * (i + 0.5) / BLKSIZE_s));
gfc->fft_fht = fht;
#ifdef HAVE_NASM
if (gfc->CPU_features.AMD_3DNow) {
gfc->fft_fht = fht_3DN;
}
else if (gfc->CPU_features.SSE) {
gfc->fft_fht = fht_SSE;
}
else {
gfc->fft_fht = fht;
}
#else
#ifdef HAVE_XMMINTRIN_H
#ifdef MIN_ARCH_SSE
gfc->fft_fht = fht_SSE2;
#endif
#endif
#endif
}
================================================
FILE: app/src/main/jni/libmp3lame/fft.h
================================================
/*
* Fast Fourier Transform include file
*
* Copyright (c) 2000 Mark Taylor
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef LAME_FFT_H
#define LAME_FFT_H
void fft_long(lame_internal_flags const *const gfc, FLOAT x_real[BLKSIZE],
int chn, const sample_t *const data[2]);
void fft_short(lame_internal_flags const *const gfc, FLOAT x_real[3][BLKSIZE_s],
int chn, const sample_t *const data[2]);
void init_fft(lame_internal_flags * const gfc);
#endif
/* End of fft.h */
================================================
FILE: app/src/main/jni/libmp3lame/gain_analysis.c
================================================
/*
* ReplayGainAnalysis - analyzes input samples and give the recommended dB change
* Copyright (C) 2001 David Robinson and Glen Sawyer
* Improvements and optimizations added by Frank Klemm, and by Marcel Muller
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* concept and filter values by David Robinson (David@Robinson.org)
* -- blame him if you think the idea is flawed
* original coding by Glen Sawyer (mp3gain@hotmail.com)
* -- blame him if you think this runs too slowly, or the coding is otherwise flawed
*
* lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ )
* -- credit him for all the _good_ programming ;)
*
*
* For an explanation of the concepts and the basic algorithms involved, go to:
* http://www.replaygain.org/
*/
/*
* Here's the deal. Call
*
* InitGainAnalysis ( long samplefreq );
*
* to initialize everything. Call
*
* AnalyzeSamples ( const Float_t* left_samples,
* const Float_t* right_samples,
* size_t num_samples,
* int num_channels );
*
* as many times as you want, with as many or as few samples as you want.
* If mono, pass the sample buffer in through left_samples, leave
* right_samples NULL, and make sure num_channels = 1.
*
* GetTitleGain()
*
* will return the recommended dB level change for all samples analyzed
* SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis().
*
* GetAlbumGain()
*
* will return the recommended dB level change for all samples analyzed
* since InitGainAnalysis() was called and finalized with GetTitleGain().
*
* Pseudo-code to process an album:
*
* Float_t l_samples [4096];
* Float_t r_samples [4096];
* size_t num_samples;
* unsigned int num_songs;
* unsigned int i;
*
* InitGainAnalysis ( 44100 );
* for ( i = 1; i <= num_songs; i++ ) {
* while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 )
* AnalyzeSamples ( left_samples, right_samples, num_samples, 2 );
* fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() );
* }
* fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() );
*/
/*
* So here's the main source of potential code confusion:
*
* The filters applied to the incoming samples are IIR filters,
* meaning they rely on up to <filter order> number of previous samples
* AND up to <filter order> number of previous filtered samples.
*
* I set up the AnalyzeSamples routine to minimize memory usage and interface
* complexity. The speed isn't compromised too much (I don't think), but the
* internal complexity is higher than it should be for such a relatively
* simple routine.
*
* Optimization/clarity suggestions are welcome.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lame.h"
#include "machine.h"
#include "gain_analysis.h"
/* for each filter: */
/* [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */
#ifdef WIN32
#pragma warning ( disable : 4305 )
#endif
/*lint -save -e736 loss of precision */
static const Float_t ABYule[9][2 * YULE_ORDER + 1] = {
{0.03857599435200, -3.84664617118067, -0.02160367184185, 7.81501653005538, -0.00123395316851,
-11.34170355132042, -0.00009291677959, 13.05504219327545, -0.01655260341619,
-12.28759895145294, 0.02161526843274, 9.48293806319790, -0.02074045215285, -5.87257861775999,
0.00594298065125, 2.75465861874613, 0.00306428023191, -0.86984376593551, 0.00012025322027,
0.13919314567432, 0.00288463683916},
{0.05418656406430, -3.47845948550071, -0.02911007808948, 6.36317777566148, -0.00848709379851,
-8.54751527471874, -0.00851165645469, 9.47693607801280, -0.00834990904936, -8.81498681370155,
0.02245293253339, 6.85401540936998, -0.02596338512915, -4.39470996079559, 0.01624864962975,
2.19611684890774, -0.00240879051584, -0.75104302451432, 0.00674613682247, 0.13149317958808,
-0.00187763777362},
{0.15457299681924, -2.37898834973084, -0.09331049056315, 2.84868151156327, -0.06247880153653,
-2.64577170229825, 0.02163541888798, 2.23697657451713, -0.05588393329856, -1.67148153367602,
0.04781476674921, 1.00595954808547, 0.00222312597743, -0.45953458054983, 0.03174092540049,
0.16378164858596, -0.01390589421898, -0.05032077717131, 0.00651420667831, 0.02347897407020,
-0.00881362733839},
{0.30296907319327, -1.61273165137247, -0.22613988682123, 1.07977492259970, -0.08587323730772,
-0.25656257754070, 0.03282930172664, -0.16276719120440, -0.00915702933434, -0.22638893773906,
-0.02364141202522, 0.39120800788284, -0.00584456039913, -0.22138138954925, 0.06276101321749,
0.04500235387352, -0.00000828086748, 0.02005851806501, 0.00205861885564, 0.00302439095741,
-0.02950134983287},
{0.33642304856132, -1.49858979367799, -0.25572241425570, 0.87350271418188, -0.11828570177555,
0.12205022308084, 0.11921148675203, -0.80774944671438, -0.07834489609479, 0.47854794562326,
-0.00469977914380, -0.12453458140019, -0.00589500224440, -0.04067510197014, 0.05724228140351,
0.08333755284107, 0.00832043980773, -0.04237348025746, -0.01635381384540, 0.02977207319925,
-0.01760176568150},
{0.44915256608450, -0.62820619233671, -0.14351757464547, 0.29661783706366, -0.22784394429749,
-0.37256372942400, -0.01419140100551, 0.00213767857124, 0.04078262797139, -0.42029820170918,
-0.12398163381748, 0.22199650564824, 0.04097565135648, 0.00613424350682, 0.10478503600251,
0.06747620744683, -0.01863887810927, 0.05784820375801, -0.03193428438915, 0.03222754072173,
0.00541907748707},
{0.56619470757641, -1.04800335126349, -0.75464456939302, 0.29156311971249, 0.16242137742230,
-0.26806001042947, 0.16744243493672, 0.00819999645858, -0.18901604199609, 0.45054734505008,
0.30931782841830, -0.33032403314006, -0.27562961986224, 0.06739368333110, 0.00647310677246,
-0.04784254229033, 0.08647503780351, 0.01639907836189, -0.03788984554840, 0.01807364323573,
-0.00588215443421},
{0.58100494960553, -0.51035327095184, -0.53174909058578, -0.31863563325245, -0.14289799034253,
-0.20256413484477, 0.17520704835522, 0.14728154134330, 0.02377945217615, 0.38952639978999,
0.15558449135573, -0.23313271880868, -0.25344790059353, -0.05246019024463, 0.01628462406333,
-0.02505961724053, 0.06920467763959, 0.02442357316099, -0.03721611395801, 0.01818801111503,
-0.00749618797172},
{0.53648789255105, -0.25049871956020, -0.42163034350696, -0.43193942311114, -0.00275953611929,
-0.03424681017675, 0.04267842219415, -0.04678328784242, -0.10214864179676, 0.26408300200955,
0.14590772289388, 0.15113130533216, -0.02459864859345, -0.17556493366449, -0.11202315195388,
-0.18823009262115, -0.04060034127000, 0.05477720428674, 0.04788665548180, 0.04704409688120,
-0.02217936801134}
};
static const Float_t ABButter[9][2 * BUTTER_ORDER + 1] = {
{0.98621192462708, -1.97223372919527, -1.97242384925416, 0.97261396931306, 0.98621192462708},
{0.98500175787242, -1.96977855582618, -1.97000351574484, 0.97022847566350, 0.98500175787242},
{0.97938932735214, -1.95835380975398, -1.95877865470428, 0.95920349965459, 0.97938932735214},
{0.97531843204928, -1.95002759149878, -1.95063686409857, 0.95124613669835, 0.97531843204928},
{0.97316523498161, -1.94561023566527, -1.94633046996323, 0.94705070426118, 0.97316523498161},
{0.96454515552826, -1.92783286977036, -1.92909031105652, 0.93034775234268, 0.96454515552826},
{0.96009142950541, -1.91858953033784, -1.92018285901082, 0.92177618768381, 0.96009142950541},
{0.95856916599601, -1.91542108074780, -1.91713833199203, 0.91885558323625, 0.95856916599601},
{0.94597685600279, -1.88903307939452, -1.89195371200558, 0.89487434461664, 0.94597685600279}
};
/*lint -restore */
#ifdef WIN32
#pragma warning ( default : 4305 )
#endif
/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */
static void
filterYule(const Float_t * input, Float_t * output, size_t nSamples, const Float_t * const kernel)
{
/*register double y; */
while (nSamples--) {
*output = 1e-10 /* 1e-10 is a hack to avoid slowdown because of denormals */
+ input[0] * kernel[0]
- output[-1] * kernel[1]
+ input[-1] * kernel[2]
- output[-2] * kernel[3]
+ input[-2] * kernel[4]
- output[-3] * kernel[5]
+ input[-3] * kernel[6]
- output[-4] * kernel[7]
+ input[-4] * kernel[8]
- output[-5] * kernel[9]
+ input[-5] * kernel[10]
- output[-6] * kernel[11]
+ input[-6] * kernel[12]
- output[-7] * kernel[13]
+ input[-7] * kernel[14]
- output[-8] * kernel[15]
+ input[-8] * kernel[16]
- output[-9] * kernel[17]
+ input[-9] * kernel[18]
- output[-10] * kernel[19]
+ input[-10] * kernel[20];
++output;
++input;
/* *output++ = (Float_t)y; */
}
}
static void
filterButter(const Float_t * input, Float_t * output, size_t nSamples, const Float_t * const kernel)
{ /*register double y; */
while (nSamples--) {
*output = input[0] * kernel[0]
- output[-1] * kernel[1]
+ input[-1] * kernel[2]
- output[-2] * kernel[3]
+ input[-2] * kernel[4];
++output;
++input;
/* *output++ = (Float_t)y; */
}
}
static int ResetSampleFrequency(replaygain_t * rgData, long samplefreq);
/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */
int
ResetSampleFrequency(replaygain_t * rgData, long samplefreq)
{
int i;
/* zero out initial values */
for (i = 0; i < MAX_ORDER; i++)
rgData->linprebuf[i] = rgData->lstepbuf[i]
= rgData->loutbuf[i]
= rgData->rinprebuf[i]
= rgData->rstepbuf[i]
= rgData->routbuf[i] = 0.;
switch ((int) (samplefreq)) {
case 48000:
rgData->freqindex = 0;
break;
case 44100:
rgData->freqindex = 1;
break;
case 32000:
rgData->freqindex = 2;
break;
case 24000:
rgData->freqindex = 3;
break;
case 22050:
rgData->freqindex = 4;
break;
case 16000:
rgData->freqindex = 5;
break;
case 12000:
rgData->freqindex = 6;
break;
case 11025:
rgData->freqindex = 7;
break;
case 8000:
rgData->freqindex = 8;
break;
default:
return INIT_GAIN_ANALYSIS_ERROR;
}
rgData->sampleWindow =
(samplefreq * RMS_WINDOW_TIME_NUMERATOR + RMS_WINDOW_TIME_DENOMINATOR -
1) / RMS_WINDOW_TIME_DENOMINATOR;
rgData->lsum = 0.;
rgData->rsum = 0.;
rgData->totsamp = 0;
memset(rgData->A, 0, sizeof(rgData->A));
return INIT_GAIN_ANALYSIS_OK;
}
int
InitGainAnalysis(replaygain_t * rgData, long samplefreq)
{
if (ResetSampleFrequency(rgData, samplefreq) != INIT_GAIN_ANALYSIS_OK) {
return INIT_GAIN_ANALYSIS_ERROR;
}
rgData->linpre = rgData->linprebuf + MAX_ORDER;
rgData->rinpre = rgData->rinprebuf + MAX_ORDER;
rgData->lstep = rgData->lstepbuf + MAX_ORDER;
rgData->rstep = rgData->rstepbuf + MAX_ORDER;
rgData->lout = rgData->loutbuf + MAX_ORDER;
rgData->rout = rgData->routbuf + MAX_ORDER;
memset(rgData->B, 0, sizeof(rgData->B));
return INIT_GAIN_ANALYSIS_OK;
}
/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */
static inline double
fsqr(const double d)
{
return d * d;
}
int
AnalyzeSamples(replaygain_t * rgData, const Float_t * left_samples, const Float_t * right_samples,
size_t num_samples, int num_channels)
{
const Float_t *curleft;
const Float_t *curright;
long batchsamples;
long cursamples;
long cursamplepos;
int i;
if (num_samples == 0)
return GAIN_ANALYSIS_OK;
cursamplepos = 0;
batchsamples = (long) num_samples;
switch (num_channels) {
case 1:
right_samples = left_samples;
break;
case 2:
break;
default:
return GAIN_ANALYSIS_ERROR;
}
if (num_samples < MAX_ORDER) {
memcpy(rgData->linprebuf + MAX_ORDER, left_samples, num_samples * sizeof(Float_t));
memcpy(rgData->rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t));
}
else {
memcpy(rgData->linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t));
memcpy(rgData->rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t));
}
while (batchsamples > 0) {
cursamples = batchsamples > rgData->sampleWindow - rgData->totsamp ?
rgData->sampleWindow - rgData->totsamp : batchsamples;
if (cursamplepos < MAX_ORDER) {
curleft = rgData->linpre + cursamplepos;
curright = rgData->rinpre + cursamplepos;
if (cursamples > MAX_ORDER - cursamplepos)
cursamples = MAX_ORDER - cursamplepos;
}
else {
curleft = left_samples + cursamplepos;
curright = right_samples + cursamplepos;
}
YULE_FILTER(curleft, rgData->lstep + rgData->totsamp, cursamples,
ABYule[rgData->freqindex]);
YULE_FILTER(curright, rgData->rstep + rgData->totsamp, cursamples,
ABYule[rgData->freqindex]);
BUTTER_FILTER(rgData->lstep + rgData->totsamp, rgData->lout + rgData->totsamp, cursamples,
ABButter[rgData->freqindex]);
BUTTER_FILTER(rgData->rstep + rgData->totsamp, rgData->rout + rgData->totsamp, cursamples,
ABButter[rgData->freqindex]);
curleft = rgData->lout + rgData->totsamp; /* Get the squared values */
curright = rgData->rout + rgData->totsamp;
i = cursamples % 8;
while (i--) {
rgData->lsum += fsqr(*curleft++);
rgData->rsum += fsqr(*curright++);
}
i = cursamples / 8;
while (i--) {
rgData->lsum += fsqr(curleft[0])
+ fsqr(curleft[1])
+ fsqr(curleft[2])
+ fsqr(curleft[3])
+ fsqr(curleft[4])
+ fsqr(curleft[5])
+ fsqr(curleft[6])
+ fsqr(curleft[7]);
curleft += 8;
rgData->rsum += fsqr(curright[0])
+ fsqr(curright[1])
+ fsqr(curright[2])
+ fsqr(curright[3])
+ fsqr(curright[4])
+ fsqr(curright[5])
+ fsqr(curright[6])
+ fsqr(curright[7]);
curright += 8;
}
batchsamples -= cursamples;
cursamplepos += cursamples;
rgData->totsamp += cursamples;
if (rgData->totsamp == rgData->sampleWindow) { /* Get the Root Mean Square (RMS) for this set of samples */
double const val =
STEPS_per_dB * 10. * log10((rgData->lsum + rgData->rsum) / rgData->totsamp * 0.5 +
1.e-37);
size_t ival = (val <= 0) ? 0 : (size_t) val;
if (ival >= sizeof(rgData->A) / sizeof(*(rgData->A)))
ival = sizeof(rgData->A) / sizeof(*(rgData->A)) - 1;
rgData->A[ival]++;
rgData->lsum = rgData->rsum = 0.;
memmove(rgData->loutbuf, rgData->loutbuf + rgData->totsamp,
MAX_ORDER * sizeof(Float_t));
memmove(rgData->routbuf, rgData->routbuf + rgData->totsamp,
MAX_ORDER * sizeof(Float_t));
memmove(rgData->lstepbuf, rgData->lstepbuf + rgData->totsamp,
MAX_ORDER * sizeof(Float_t));
memmove(rgData->rstepbuf, rgData->rstepbuf + rgData->totsamp,
MAX_ORDER * sizeof(Float_t));
rgData->totsamp = 0;
}
if (rgData->totsamp > rgData->sampleWindow) /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */
return GAIN_ANALYSIS_ERROR;
}
if (num_samples < MAX_ORDER) {
memmove(rgData->linprebuf, rgData->linprebuf + num_samples,
(MAX_ORDER - num_samples) * sizeof(Float_t));
memmove(rgData->rinprebuf, rgData->rinprebuf + num_samples,
(MAX_ORDER - num_samples) * sizeof(Float_t));
memcpy(rgData->linprebuf + MAX_ORDER - num_samples, left_samples,
num_samples * sizeof(Float_t));
memcpy(rgData->rinprebuf + MAX_ORDER - num_samples, right_samples,
num_samples * sizeof(Float_t));
}
else {
memcpy(rgData->linprebuf, left_samples + num_samples - MAX_ORDER,
MAX_ORDER * sizeof(Float_t));
memcpy(rgData->rinprebuf, right_samples + num_samples - MAX_ORDER,
MAX_ORDER * sizeof(Float_t));
}
return GAIN_ANALYSIS_OK;
}
static Float_t
analyzeResult(uint32_t const *Array, size_t len)
{
uint32_t elems;
uint32_t upper;
uint32_t sum;
size_t i;
elems = 0;
for (i = 0; i < len; i++)
elems += Array[i];
if (elems == 0)
return GAIN_NOT_ENOUGH_SAMPLES;
upper = (uint32_t) ceil(elems * (1. - RMS_PERCENTILE));
sum = 0;
for (i = len; i-- > 0;) {
sum += Array[i];
if (sum >= upper) {
break;
}
}
return (Float_t) ((Float_t) PINK_REF - (Float_t) i / (Float_t) STEPS_per_dB);
}
Float_t
GetTitleGain(replaygain_t * rgData)
{
Float_t retval;
unsigned int i;
retval = analyzeResult(rgData->A, sizeof(rgData->A) / sizeof(*(rgData->A)));
for (i = 0; i < sizeof(rgData->A) / sizeof(*(rgData->A)); i++) {
rgData->B[i] += rgData->A[i];
rgData->A[i] = 0;
}
for (i = 0; i < MAX_ORDER; i++)
rgData->linprebuf[i] = rgData->lstepbuf[i]
= rgData->loutbuf[i]
= rgData->rinprebuf[i]
= rgData->rstepbuf[i]
= rgData->routbuf[i] = 0.f;
rgData->totsamp = 0;
rgData->lsum = rgData->rsum = 0.;
return retval;
}
#if 0
static Float_t GetAlbumGain(replaygain_t const* rgData);
Float_t
GetAlbumGain(replaygain_t const* rgData)
{
return analyzeResult(rgData->B, sizeof(rgData->B) / sizeof(*(rgData->B)));
}
#endif
/* end of gain_analysis.c */
================================================
FILE: app/src/main/jni/libmp3lame/gain_analysis.h
================================================
/*
* ReplayGainAnalysis - analyzes input samples and give the recommended dB change
* Copyright (C) 2001 David Robinson and Glen Sawyer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* concept and filter values by David Robinson (David@Robinson.org)
* -- blame him if you think the idea is flawed
* coding by Glen Sawyer (mp3gain@hotmail.com) 735 W 255 N, Orem, UT 84057-4505 USA
* -- blame him if you think this runs too slowly, or the coding is otherwise flawed
*
* For an explanation of the concepts and the basic algorithms involved, go to:
* http://www.replaygain.org/
*/
#ifndef GAIN_ANALYSIS_H
#define GAIN_ANALYSIS_H
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#else
# ifdef HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef sample_t Float_t; /* Type used for filtering */
#define PINK_REF 64.82 /* 298640883795 */ /* calibration value for 89dB */
#define YULE_ORDER 10
#define BUTTER_ORDER 2
#define YULE_FILTER filterYule
#define BUTTER_FILTER filterButter
#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */
#define MAX_SAMP_FREQ 48000L /* maximum allowed sample frequency [Hz] */
#define RMS_WINDOW_TIME_NUMERATOR 1L
#define RMS_WINDOW_TIME_DENOMINATOR 20L /* numerator / denominator = time slice size [s] */
#define STEPS_per_dB 100 /* Table entries per dB */
#define MAX_dB 120 /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */
enum { GAIN_NOT_ENOUGH_SAMPLES = -24601, GAIN_ANALYSIS_ERROR = 0, GAIN_ANALYSIS_OK =
1, INIT_GAIN_ANALYSIS_ERROR = 0, INIT_GAIN_ANALYSIS_OK = 1
};
enum { MAX_ORDER = (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER)
, MAX_SAMPLES_PER_WINDOW = ((MAX_SAMP_FREQ * RMS_WINDOW_TIME_NUMERATOR) / RMS_WINDOW_TIME_DENOMINATOR + 1) /* max. Samples per Time slice */
};
struct replaygain_data {
Float_t linprebuf[MAX_ORDER * 2];
Float_t *linpre; /* left input samples, with pre-buffer */
Float_t lstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
Float_t *lstep; /* left "first step" (i.e. post first filter) samples */
Float_t loutbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
Float_t *lout; /* left "out" (i.e. post second filter) samples */
Float_t rinprebuf[MAX_ORDER * 2];
Float_t *rinpre; /* right input samples ... */
Float_t rstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
Float_t *rstep;
Float_t routbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
Float_t *rout;
long sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */
long totsamp;
double lsum;
double rsum;
int freqindex;
int first;
uint32_t A[STEPS_per_dB * MAX_dB];
uint32_t B[STEPS_per_dB * MAX_dB];
};
#ifndef replaygain_data_defined
#define replaygain_data_defined
typedef struct replaygain_data replaygain_t;
#endif
int InitGainAnalysis(replaygain_t * rgData, long samplefreq);
int AnalyzeSamples(replaygain_t * rgData, const Float_t * left_samples,
const Float_t * right_samples, size_t num_samples, int num_channels);
Float_t GetTitleGain(replaygain_t * rgData);
#ifdef __cplusplus
}
#endif
#endif /* GAIN_ANALYSIS_H */
================================================
FILE: app/src/main/jni/libmp3lame/id3tag.c
================================================
/*
* id3tag.c -- Write ID3 version 1 and 2 tags.
*
* Copyright (C) 2000 Don Melton
* Copyright (C) 2011-2012 Robert Hegemann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* HISTORY: This source file is part of LAME (see http://www.mp3dev.org)
* and was originally adapted by Conrad Sanderson <c.sanderson@me.gu.edu.au>
* from mp3info by Ricardo Cerqueira <rmc@rccn.net> to write only ID3 version 1
* tags. Don Melton <don@blivet.com> COMPLETELY rewrote it to support version
* 2 tags and be more conformant to other standards while remaining flexible.
*
* NOTE: See http://id3.org/ for more information about ID3 tag formats.
*/
/* $Id: id3tag.c,v 1.75.2.2 2012/01/08 23:49:58 robert Exp $ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef STDC_HEADERS
# include <stddef.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
#else
# ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
# endif
char *strchr(), *strrchr();
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
#include "lame.h"
#include "machine.h"
#include "encoder.h"
#include "id3tag.h"
#include "lame_global_flags.h"
#include "util.h"
#include "bitstream.h"
#define lame_calloc(TYPE, COUNT) ((TYPE*)calloc(COUNT, sizeof(TYPE)))
static const char *const genre_names[] = {
/*
* NOTE: The spelling of these genre names is identical to those found in
* Winamp and mp3info.
*/
"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
"Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
"Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
"Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
"Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
"Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock",
"Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
"Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
"Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
"Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
"Native US", "Cabaret", "New Wave", "Psychedelic", "Rave",
"Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
"Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
"Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin",
"Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
"Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
"Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
"Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
"Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
"Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
"Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall",
"Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
"BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta",
"Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
"Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
"SynthPop"
};
#define GENRE_NAME_COUNT \
((int)(sizeof genre_names / sizeof (const char *const)))
static const int genre_alpha_map[] = {
123, 34, 74, 73, 99, 20, 40, 26, 145, 90, 116, 41, 135, 85, 96, 138, 89, 0,
107, 132, 65, 88, 104, 102, 97, 136, 61, 141, 32, 1, 112, 128, 57, 140, 2,
139, 58, 3, 125, 50, 22, 4, 55, 127, 122, 120, 98, 52, 48, 54, 124, 25, 84,
80, 115, 81, 119, 5, 30, 36, 59, 126, 38, 49, 91, 6, 129, 79, 137, 7, 35,
100, 131, 19, 33, 46, 47, 8, 29, 146, 63, 86, 71, 45, 142, 9, 77, 82, 64,
133, 10, 66, 39, 11, 103, 12, 75, 134, 13, 53, 62, 109, 117, 23, 108, 92,
67, 93, 43, 121, 15, 68, 14, 16, 76, 87, 118, 17, 78, 143, 114, 110, 69, 21,
111, 95, 105, 42, 37, 24, 56, 44, 101, 83, 94, 106, 147, 113, 18, 51, 130,
144, 60, 70, 31, 72, 27, 28
};
#define GENRE_ALPHA_COUNT ((int)(sizeof genre_alpha_map / sizeof (int)))
#define GENRE_INDEX_OTHER 12
#define FRAME_ID(a, b, c, d) \
( ((unsigned long)(a) << 24) \
| ((unsigned long)(b) << 16) \
| ((unsigned long)(c) << 8) \
| ((unsigned long)(d) << 0) )
typedef enum UsualStringIDs { ID_TITLE = FRAME_ID('T', 'I', 'T', '2')
, ID_ARTIST = FRAME_ID('T', 'P', 'E', '1')
, ID_ALBUM = FRAME_ID('T', 'A', 'L', 'B')
, ID_GENRE = FRAME_ID('T', 'C', 'O', 'N')
, ID_ENCODER = FRAME_ID('T', 'S', 'S', 'E')
, ID_PLAYLENGTH = FRAME_ID('T', 'L', 'E', 'N')
, ID_COMMENT = FRAME_ID('C', 'O', 'M', 'M') /* full text string */
} UsualStringIDs;
typedef enum NumericStringIDs { ID_DATE = FRAME_ID('T', 'D', 'A', 'T') /* "ddMM" */
, ID_TIME = FRAME_ID('T', 'I', 'M', 'E') /* "hhmm" */
, ID_TPOS = FRAME_ID('T', 'P', 'O', 'S') /* '0'-'9' and '/' allowed */
, ID_TRACK = FRAME_ID('T', 'R', 'C', 'K') /* '0'-'9' and '/' allowed */
, ID_YEAR = FRAME_ID('T', 'Y', 'E', 'R') /* "yyyy" */
} NumericStringIDs;
typedef enum MiscIDs { ID_TXXX = FRAME_ID('T', 'X', 'X', 'X')
, ID_WXXX = FRAME_ID('W', 'X', 'X', 'X')
, ID_SYLT = FRAME_ID('S', 'Y', 'L', 'T')
, ID_APIC = FRAME_ID('A', 'P', 'I', 'C')
, ID_GEOB = FRAME_ID('G', 'E', 'O', 'B')
, ID_PCNT = FRAME_ID('P', 'C', 'N', 'T')
, ID_AENC = FRAME_ID('A', 'E', 'N', 'C')
, ID_LINK = FRAME_ID('L', 'I', 'N', 'K')
, ID_ENCR = FRAME_ID('E', 'N', 'C', 'R')
, ID_GRID = FRAME_ID('G', 'R', 'I', 'D')
, ID_PRIV = FRAME_ID('P', 'R', 'I', 'V')
, ID_VSLT = FRAME_ID('V', 'S', 'L', 'T') /* full text string */
, ID_USER = FRAME_ID('U', 'S', 'E', 'R') /* full text string */
, ID_PCST = FRAME_ID('P', 'C', 'S', 'T') /* iTunes Podcast indicator, only presence important */
, ID_WFED = FRAME_ID('W', 'F', 'E', 'D') /* iTunes Podcast URL as TEXT FRAME !!! violates standard */
} MiscIDs;
static int
frame_id_matches(int id, int mask)
{
int result = 0, i, window = 0xff;
for (i = 0; i < 4; ++i, window <<= 8) {
int const mw = (mask & window);
int const iw = (id & window);
if (mw != 0 && mw != iw) {
result |= iw;
}
}
return result;
}
static int
isFrameIdMatching(int id, int mask)
{
return frame_id_matches(id, mask) == 0 ? 1 : 0;
}
static int
test_tag_spec_flags(lame_internal_flags const *gfc, unsigned int tst)
{
return (gfc->tag_spec.flags & tst) != 0u ? 1 : 0;
}
#if 0
static void
debug_tag_spec_flags(lame_internal_flags * gfc, const char* info)
{
MSGF(gfc, "%s\n", info);
MSGF(gfc, "CHANGED_FLAG : %d\n", test_tag_spec_flags(gfc, CHANGED_FLAG ));
MSGF(gfc, "ADD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, ADD_V2_FLAG ));
MSGF(gfc, "V1_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V1_ONLY_FLAG ));
MSGF(gfc, "V2_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V2_ONLY_FLAG ));
MSGF(gfc, "SPACE_V1_FLAG : %d\n", test_tag_spec_flags(gfc, SPACE_V1_FLAG));
MSGF(gfc, "PAD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, PAD_V2_FLAG ));
}
#endif
static int
id3v2_add_ucs2(lame_t gfp, uint32_t frame_id, char const *lang, unsigned short const *desc, unsigned short const *text);
static int
id3v2_add_latin1(lame_t gfp, uint32_t frame_id, char const *lang, char const *desc, char const *text);
static void
copyV1ToV2(lame_t gfp, int frame_id, char const *s)
{
lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
if (gfc != 0) {
unsigned int flags = gfc->tag_spec.flags;
id3v2_add_latin1(gfp, frame_id, "XXX", 0, s);
gfc->tag_spec.flags = flags;
#if 0
debug_tag_spec_flags(gfc, "copyV1ToV2");
#endif
}
}
static void
id3v2AddLameVersion(lame_t gfp)
{
char buffer[1024];
const char *b = get_lame_os_bitness();
const char *v = get_lame_version();
const char *u = get_lame_url();
const size_t lenb = strlen(b);
if (lenb > 0) {
sprintf(buffer, "LAME %s version %s (%s)", b, v, u);
}
else {
sprintf(buffer, "LAME version %s (%s)", v, u);
}
copyV1ToV2(gfp, ID_ENCODER, buffer);
}
static void
id3v2AddAudioDuration(lame_t gfp, double ms)
{
lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0;
SessionConfig_t const *const cfg = &gfc->cfg;
char buffer[1024];
double const max_ulong = MAX_U_32_NUM;
unsigned long playlength_ms;
ms *= 1000;
ms /= cfg->samplerate_in;
if (ms > max_ulong) {
playlength_ms = max_ulong;
}
else if (ms < 0) {
playlength_ms = 0;
}
else {
playlength_ms = ms;
}
sprintf(buffer, "%lu", playlength_ms);
copyV1ToV2(gfp, ID_PLAYLENGTH, buffer);
}
void
id3tag_genre_list(void (*handler) (int, const char *, void *), void *cookie)
{
if (handler) {
int i;
for (i = 0; i < GENRE_NAME_COUNT; ++i) {
if (i < GENRE_ALPHA_COUNT) {
int j = genre_alpha_map[i];
handler(j, genre_names[j], cookie);
}
}
}
}
#define GENRE_NUM_UNKNOWN 255
void
id3tag_init(lame_t gfp)
{
lame_internal_flags *gfc = gfp->internal_flags;
free_id3tag(gfc);
memset(&gfc->tag_spec, 0, sizeof gfc->tag_spec);
gfc->tag_spec.genre_id3v1 = GENRE_NUM_UNKNOWN;
gfc->tag_spec.padding_size = 128;
id3v2AddLameVersion(gfp);
}
void
id3tag_add_v2(lame_t gfp)
{
lame_internal_flags *gfc = gfp->internal_flags;
gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
gfc->tag_spec.flags |= ADD_V2_FLAG;
}
void
id3tag_v1_only(lame_t gfp)
{
lame_internal_flags *gfc = gfp->internal_flags;
gfc->tag_spec.flags &= ~(ADD_V2_FLAG | V2_ONLY_FLAG);
gfc->tag_spec.flags |= V1_ONLY_FLAG;
}
void
id3tag_v2_only(lame_t gfp)
{
lame_internal_flags *gfc = gfp->internal_flags;
gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
gfc->tag_spec.flags |= V2_ONLY_FLAG;
}
void
id3tag_space_v1(lame_t gfp)
{
lame_internal_flags *gfc = gfp->internal_flags;
gfc->tag_spec.flags &= ~V2_ONLY_FLAG;
gfc->tag_spec.flags |= SPACE_V1_FLAG;
}
void
id3tag_pad_v2(lame_t gfp)
{
id3tag_set_pad(gfp, 128);
}
void
id3tag_set_pad(lame_t gfp, size_t n)
{
lame_internal_flags *gfc = gfp->internal_flags;
gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
gfc->tag_spec.flags |= PAD_V2_FLAG;
gfc->tag_spec.flags |= ADD_V2_FLAG;
gfc->tag_spec.padding_size = (unsigned int)n;
}
static int
hasUcs2ByteOrderMarker(unsigned short bom)
{
if (bom == 0xFFFEu || bom == 0xFEFFu) {
return 1;
}
return 0;
}
static unsigned short
swap_bytes(unsigned short w)
{
return (0xff00u & (w << 8)) | (0x00ffu & (w >> 8));
}
static unsigned short
toLittleEndian(unsigned short bom, unsigned short c)
{
if (bom == 0xFFFEu) {
return swap_bytes(c);
}
return c;
}
static unsigned short
fromLatin1Char(const unsigned short* s, unsigned short c)
{
if (s[0] == 0xFFFEu) {
return swap_bytes(c);
}
return c;
}
static size_t
local_strdup(char **dst, const char *src)
{
if (dst == 0) {
return 0;
}
free(*dst);
*dst = 0;
if (src != 0) {
size_t n;
for (n = 0; src[n] != 0; ++n) { /* calc src string length */
}
if (n > 0) { /* string length without zero termination */
assert(sizeof(*src) == sizeof(**dst));
*dst = lame_calloc(char, n + 1);
if (*dst != 0) {
memcpy(*dst, src, n * sizeof(**dst));
(*dst)[n] = 0;
return n;
}
}
}
return 0;
}
static size_t
local_ucs2_strdup(unsigned short **dst, unsigned short const *src)
{
if (dst == 0) {
return 0;
}
free(*dst); /* free old string pointer */
*dst = 0;
if (src != 0) {
size_t n;
for (n = 0; src[n] != 0; ++n) { /* calc src string length */
}
if (n > 0) { /* string length without zero termination */
assert(sizeof(*src) >= 2);
assert(sizeof(*src) == sizeof(**dst));
*dst = lame_calloc(unsigned short, n + 1);
if (*dst != 0) {
memcpy(*dst, src, n * sizeof(**dst));
(*dst)[n] = 0;
return n;
}
}
}
return 0;
}
static size_t
local_ucs2_strlen(unsigned short const *s)
{
size_t n = 0;
if (s != 0) {
while (*s++) {
++n;
}
}
return n;
}
static size_t
local_ucs2_substr(unsigned short** dst, unsigned short const* src, size_t start, size_t end)
{
size_t const len = 1 + 1 + ((start < end) ? (end - start) : 0);
size_t n = 0;
unsigned short *ptr = lame_calloc(unsigned short, len);
*dst = ptr;
if (ptr == 0 || src == 0) {
return 0;
}
if (hasUcs2ByteOrderMarker(src[0])) {
ptr[n++] = src[0];
if (start == 0) {
++start;
}
}
while (start < end) {
ptr[n++] = src[start++];
}
ptr[n] = 0;
return n;
}
static int
local_ucs2_pos(unsigned short const* str, unsigned short c)
{
int i;
for (i = 0; str != 0 && str[i] != 0; ++i) {
if (str[i] == c) {
return i;
}
}
return -1;
}
static int
local_char_pos(char const* str, char c)
{
int i;
for (i = 0; str != 0 && str[i] != 0; ++i) {
if (str[i] == c) {
return i;
}
}
return -1;
}
static int
maybeLatin1(unsigned short const* text)
{
if (text) {
unsigned short bom = *text++;
while (*text) {
unsigned short c = toLittleEndian(bom, *text++);
if (c > 0x00fe) return 0;
}
}
return 1;
}
static int searchGenre(char const* genre);
static int sloppySearchGenre(char const* genre);
static int
lookupGenre(char const* genre)
{
char *str;
int num = strtol(genre, &str, 10);
/* is the input a string or a valid number? */
if (*str) {
num = searchGenre(genre);
if (num == GENRE_NAME_COUNT) {
num = sloppySearchGenre(genre);
}
if (num == GENRE_NAME_COUNT) {
return -2; /* no common genre text found */
}
}
else {
if ((num < 0) || (num >= GENRE_NAME_COUNT)) {
return -1; /* number unknown */
}
}
return num;
}
static unsigned char *
writeLoBytes(unsigned char *frame, unsigned short const *str, size_t n);
static char*
local_strdup_utf16_to_latin1(unsigned short const* utf16)
{
size_t len = local_ucs2_strlen(utf16);
unsigned char* latin1 = lame_calloc(unsigned char, len+1);
writeLoBytes(latin1, utf16, len);
return (char*)latin1;
}
static int
id3tag_set_genre_utf16(lame_t gfp, unsigned short const* text)
{
lame_internal_flags* gfc = gfp->internal_flags;
int ret;
if (text == 0) {
return -3;
}
if (!hasUcs2ByteOrderMarker(text[0])) {
return -3;
}
if (maybeLatin1(text)) {
char* latin1 = local_strdup_utf16_to_latin1(text);
int num = lookupGenre(latin1);
free(latin1);
if (num == -1) return -1; /* number out of range */
if (num >= 0) { /* common genre found */
gfc->tag_spec.flags |= CHANGED_FLAG;
gfc->tag_spec.genre_id3v1 = num;
copyV1ToV2(gfp, ID_GENRE, genre_names[num]);
return 0;
}
}
ret = id3v2_add_ucs2(gfp, ID_GENRE, 0, 0, text);
if (ret == 0) {
gfc->tag_spec.flags |= CHANGED_FLAG;
gfc->tag_spec.genre_id3v1 = GENRE_INDEX_OTHER;
}
return ret;
}
/*
Some existing options for ID3 tag can be specified by --tv option
as follows.
--tt <value>, --tv TIT2=value
--ta <value>, --tv TPE1=value
--tl <value>, --tv TALB=value
--ty <value>, --tv TYER=value
--tn <value>, --tv TRCK=value
--tg <value>, --tv TCON=value
(although some are not exactly same)*/
int
id3tag_set_albumart(lame_t gfp, const char *image, size_t size)
{
int mimetype = 0;
unsigned char const *data = (unsigned char const *) image;
lame_internal_flags *gfc = gfp->internal_flags;
/* determine MIME type from the actual image data */
if (2 < size && data[0] == 0xFF && data[1] == 0xD8) {
mimetype = MIMETYPE_JPEG;
}
else if (4 < size && data[0] == 0x89 && strncmp((const char *) &data[1], "PNG", 3) == 0) {
mimetype = MIMETYPE_PNG;
}
else if (4 < size && strncmp((const char *) data, "GIF8", 4) == 0) {
mimetype = MIMETYPE_GIF;
}
else {
return -1;
}
if (gfc->tag_spec.albumart != 0) {
free(gfc->tag_spec.albumart);
gfc->tag_spec.albumart = 0;
gfc->tag_spec.albumart_size = 0;
gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE;
}
if (size < 1) {
return 0;
}
gfc->tag_spec.albumart = lame_calloc(unsigned char, size);
if (gfc->tag_spec.albumart != 0) {
memcpy(gfc->tag_spec.albumart, image, size);
gfc->tag_spec.albumart_size = (unsigned int)size;
gfc->tag_spec.albumart_mimetype = mimetype;
gfc->tag_spec.flags |= CHANGED_FLAG;
id3tag_add_v2(gfp);
}
return 0;
}
static unsigned char *
set_4_byte_value(unsigned char *bytes, uint32_t value)
{
int i;
for (i = 3; i >= 0; --i) {
bytes[i] = value & 0xffUL;
value >>= 8;
}
return bytes + 4;
}
static uint32_t
toID3v2TagId(char const *s)
{
unsigned int i, x = 0;
if (s == 0) {
return 0;
}
for (i = 0; i < 4 && s[i] != 0; ++i) {
char const c = s[i];
unsigned int const u = 0x0ff & c;
x <<= 8;
x |= u;
if (c < 'A' || 'Z' < c) {
if (c < '0' || '9' < c) {
return 0;
}
}
}
return x;
}
static uint32_t
toID3v2TagId_ucs2(unsigned short const *s)
{
unsigned int i, x = 0;
unsigned short bom = 0;
if (s == 0) {
return 0;
}
bom = s[0];
if (hasUcs2ByteOrderMarker(bom)) {
++s;
}
for (i = 0; i < 4 && s[i] != 0; ++i) {
unsigned short const c = toLittleEndian(bom, s[i]);
if (c < 'A' || 'Z' < c) {
if (c < '0' || '9' < c) {
return 0;
}
}
x <<= 8;
x |= c;
}
return x;
}
#if 0
static int
isNumericString(uint32_t frame_id)
{
switch (frame_id) {
case ID_DATE:
case ID_TIME:
case ID_TPOS:
case ID_TRACK:
case ID_YEAR:
return 1;
}
return 0;
}
#endif
static int
isMultiFrame(uint32_t frame_id)
{
switch (frame_id) {
case ID_TXXX:
case ID_WXXX:
case ID_COMMENT:
case ID_SYLT:
case ID_APIC:
case ID_GEOB:
case ID_PCNT:
case ID_AENC:
case ID_LINK:
case ID_ENCR:
case ID_GRID:
case ID_PRIV:
return 1;
}
return 0;
}
#if 0
static int
isFullTextString(int frame_id)
{
switch (frame_id) {
case ID_VSLT:
case ID_COMMENT:
return 1;
}
return 0;
}
#endif
static FrameDataNode *
findNode(id3tag_spec const *tag, uint32_t frame_id, FrameDataNode const *last)
{
FrameDataNode *node = last ? last->nxt : tag->v2_head;
while (node != 0) {
if (node->fid == frame_id) {
return node;
}
node = node->nxt;
}
return 0;
}
static void
appendNode(id3tag_spec * tag, FrameDataNode * node)
{
if (tag->v2_tail == 0 || tag->v2_head == 0) {
tag->v2_head = node;
tag->v2_tail = node;
}
else {
tag->v2_tail->nxt = node;
tag->v2_tail = node;
}
}
static void
setLang(char *dst, char const *src)
{
int i;
if (src == 0 || src[0] == 0) {
dst[0] = 'X';
dst[1] = 'X';
dst[2] = 'X';
}
else {
for (i = 0; i < 3 && src && *src; ++i) {
dst[i] = src[i];
}
for (; i < 3; ++i) {
dst[i] = ' ';
}
}
}
static int
isSameLang(char const *l1, char const *l2)
{
char d[3];
int i;
setLang(d, l2);
for (i = 0; i < 3; ++i) {
char a = tolower(l1[i]);
char b = tolower(d[i]);
if (a < ' ')
a = ' ';
if (b < ' ')
b = ' ';
if (a != b) {
return 0;
}
}
return 1;
}
static int
isSameDescriptor(FrameDataNode const *node, char const *dsc)
{
size_t i;
if (node->dsc.enc == 1 && node->dsc.dim > 0) {
return 0;
}
for (i = 0; i < node->dsc.dim; ++i) {
if (!dsc || node->dsc.ptr.l[i] != dsc[
gitextract_rnfvjqig/ ├── .gitignore ├── README.md ├── app/ │ ├── .gitignore │ ├── CMakeLists.txt │ ├── build.gradle │ ├── key02.keystore │ ├── proguard-rules.pro │ ├── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── convert/ │ │ │ └── mymp3convert/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── convert/ │ │ │ │ └── mymp3convert/ │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MainActivity2.kt │ │ │ │ ├── Mp3ConvertUtil.java │ │ │ │ ├── Mp3ConvertUtilHelper.java │ │ │ │ ├── MyTest.java │ │ │ │ └── test/ │ │ │ │ └── Demo.java │ │ │ ├── jni/ │ │ │ │ ├── NativeMp3ConvertUtil.cpp │ │ │ │ ├── NativeMp3ConvertUtil.cpp.bak │ │ │ │ ├── NativeMp3ConvertUtil.h │ │ │ │ ├── NativeMyTest.cpp │ │ │ │ ├── com_convert_mymp3convert_Mp3ConvertUtil.h │ │ │ │ ├── com_convert_mymp3convert_MyTest.h │ │ │ │ └── libmp3lame/ │ │ │ │ ├── VbrTag.c │ │ │ │ ├── VbrTag.h │ │ │ │ ├── bitstream.c │ │ │ │ ├── bitstream.h │ │ │ │ ├── encoder.c │ │ │ │ ├── encoder.h │ │ │ │ ├── fft.c │ │ │ │ ├── fft.h │ │ │ │ ├── gain_analysis.c │ │ │ │ ├── gain_analysis.h │ │ │ │ ├── id3tag.c │ │ │ │ ├── id3tag.h │ │ │ │ ├── l3side.h │ │ │ │ ├── lame-analysis.h │ │ │ │ ├── lame.c │ │ │ │ ├── lame.h │ │ │ │ ├── lame_global_flags.h │ │ │ │ ├── lameerror.h │ │ │ │ ├── machine.h │ │ │ │ ├── mpglib_interface.c │ │ │ │ ├── newmdct.c │ │ │ │ ├── newmdct.h │ │ │ │ ├── presets.c │ │ │ │ ├── psymodel.c │ │ │ │ ├── psymodel.h │ │ │ │ ├── quantize.c │ │ │ │ ├── quantize.h │ │ │ │ ├── quantize_pvt.c │ │ │ │ ├── quantize_pvt.h │ │ │ │ ├── reservoir.c │ │ │ │ ├── reservoir.h │ │ │ │ ├── set_get.c │ │ │ │ ├── set_get.h │ │ │ │ ├── tables.c │ │ │ │ ├── tables.h │ │ │ │ ├── takehiro.c │ │ │ │ ├── util.c │ │ │ │ ├── util.h │ │ │ │ ├── vbrquantize.c │ │ │ │ ├── vbrquantize.h │ │ │ │ ├── version.c │ │ │ │ └── version.h │ │ │ ├── library/ │ │ │ │ └── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── drawable-v24/ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── layout/ │ │ │ │ ├── activity_main.xml │ │ │ │ └── activity_main2.xml │ │ │ ├── mipmap-anydpi-v26/ │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ └── values-night/ │ │ │ └── themes.xml │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── convert/ │ │ └── mymp3convert/ │ │ └── ExampleUnitTest.java │ └── 说明 .txt ├── build.gradle ├── demo/ │ ├── .gitignore │ ├── build.gradle │ ├── libs/ │ │ └── app-release.aar │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── convert/ │ │ └── demo/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── convert/ │ │ │ └── demo/ │ │ │ └── MainActivity.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ └── values-night/ │ │ └── themes.xml │ └── test/ │ └── java/ │ └── com/ │ └── convert/ │ └── demo/ │ └── ExampleUnitTest.java ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle
SYMBOL INDEX (678 symbols across 46 files)
FILE: app/src/androidTest/java/com/convert/mymp3convert/ExampleInstrumentedTest.java
class ExampleInstrumentedTest (line 18) | @RunWith(AndroidJUnit4.class)
method useAppContext (line 20) | @Test
FILE: app/src/main/java/com/convert/mymp3convert/MainActivity.java
class MainActivity (line 15) | public class MainActivity extends AppCompatActivity {
method onCreate (line 20) | @Override
method test (line 31) | public void test(View v){
method convert (line 37) | public void convert(View v){
method convertByHelper01 (line 42) | public void convertByHelper01(View v){
method convertByHelper02 (line 58) | public void convertByHelper02(View v){
FILE: app/src/main/java/com/convert/mymp3convert/Mp3ConvertUtil.java
class Mp3ConvertUtil (line 7) | public class Mp3ConvertUtil {
method hello (line 13) | public static native String hello(String msg);
method getLameVer (line 19) | public static native String getLameVer();
method convertmp3 (line 26) | public static native void convertmp3(String wav, String mp3);
type ConvertListener (line 31) | public interface ConvertListener{
method notifyConvertProgress (line 32) | public void notifyConvertProgress(int progress);
method convertFinish (line 36) | public void convertFinish();
method convertError (line 42) | public void convertError(String errorMsg);
class SimpleConvertListener (line 48) | public static class SimpleConvertListener implements ConvertListener{
method notifyConvertProgress (line 50) | @Override
method convertFinish (line 55) | @Override
method convertError (line 60) | @Override
method registerCallback (line 80) | protected static void registerCallback(String mp3TargetPath,ConvertLis...
method removeCallback (line 91) | private static void removeCallback(String mp3TargetPath){
method setProgress (line 103) | private static void setProgress(String outPath,int progress){
method getProgress (line 115) | protected static int getProgress(String outPath){
method removeProgress (line 132) | private static void removeProgress(String outPath){
method nativeLog (line 144) | public static void nativeLog(String logTag,String logMsg) {
method setConvertProgress (line 152) | public static void setConvertProgress(int progress,String outPath) {
method convertFinish (line 167) | public static void convertFinish(String outPath) {
method convertError (line 183) | public static void convertError(String errorMsg,String outPath) {
FILE: app/src/main/java/com/convert/mymp3convert/Mp3ConvertUtilHelper.java
class Mp3ConvertUtilHelper (line 3) | public class Mp3ConvertUtilHelper {
method getVer (line 8) | public static String getVer(){
method convertmp3 (line 17) | public static void convertmp3(String wavInPath, String mp3OutPath){
method convertmp3 (line 27) | public static void convertmp3(String wavInPath, String mp3OutPath, Mp3...
method getProgress (line 36) | public static int getProgress(String outPath){
FILE: app/src/main/java/com/convert/mymp3convert/MyTest.java
class MyTest (line 3) | public class MyTest {
method test (line 4) | public static native String test();
FILE: app/src/main/java/com/convert/mymp3convert/test/Demo.java
class Demo (line 5) | public class Demo {
method test (line 6) | private void test(){
FILE: app/src/main/jni/NativeMp3ConvertUtil.cpp
function publishJavaProgress (line 65) | void publishJavaProgress(JNIEnv * env, jobject obj, jint progress,jstrin...
function convertFinish (line 92) | void convertFinish(JNIEnv * env, jstring mp3Path) {
function convertError (line 118) | void convertError(JNIEnv * env,jstring msg,jstring mp3Path) {
function nativeLog (line 147) | void nativeLog(JNIEnv * env, jstring msg) {
function jstring (line 175) | jstring jstrCat(JNIEnv *env,char * cstr,jstring jstr){
function file_size (line 190) | long long file_size(char* filename){
function JNIEXPORT (line 200) | JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_Mp3ConvertUtil_h...
function JNIEXPORT (line 225) | JNIEXPORT jstring JNICALL
function JNIEXPORT (line 245) | JNIEXPORT void JNICALL
FILE: app/src/main/jni/NativeMp3ConvertUtil.h
function class (line 9) | class NativeMp3ConvertUtil {
FILE: app/src/main/jni/NativeMyTest.cpp
function jstring (line 15) | jstring jstrCat(JNIEnv *env,char * cstr,jstring jstr){
function JNIEXPORT (line 30) | JNIEXPORT jstring JNICALL Java_com_convert_mymp3convert_MyTest_test
FILE: app/src/main/jni/libmp3lame/VbrTag.c
function addVbr (line 123) | static void
function Xing_seek_table (line 150) | static void
function print_seeking (line 174) | static void
function AddVbrFrame (line 195) | void
function ExtractI4 (line 205) | static int
function CreateI4 (line 220) | static void
function CreateI2 (line 232) | static void
function IsVbrTag (line 241) | static int
function setLameTagFrameHeader (line 256) | static void
function CheckVbrTag (line 332) | int
function GetVbrTag (line 361) | int
function InitVbrTag (line 491) | int
function CRC_update_lookup (line 582) | static uint16_t
function UpdateMusicCRC (line 591) | void
function PutLameVBR (line 614) | static int
function skipId3v2 (line 864) | static long
function lame_get_lametag_frame (line 899) | size_t
function PutVbrTag (line 1029) | int
FILE: app/src/main/jni/libmp3lame/VbrTag.h
type lame_internal_flags (line 52) | struct lame_internal_flags
type lame_internal_flags (line 53) | typedef struct lame_internal_flags lame_internal_flags;
type VBRTAGDATA (line 59) | typedef struct {
FILE: app/src/main/jni/libmp3lame/bitstream.c
function calcFrameLength (line 60) | static int
function getframebits (line 70) | int
function get_max_frame_buffer_size_by_constraint (line 90) | int
function putheader_bits (line 132) | static void
function putbits2 (line 151) | inline static void
function putbits_noheaders (line 187) | inline static void
function drain_into_ancillary (line 225) | inline static void
function writeheader (line 269) | inline static void
function CRC_update (line 287) | static int
function CRC_writeheader (line 303) | void
function encodeSideInfo2 (line 320) | inline static void
function huffman_coder_count1 (line 490) | inline static int
function Huffmancode (line 560) | inline static int
function ShortHuffmancodebits (line 638) | static int
function LongHuffmancodebits (line 654) | static int
function writeMainData (line 685) | inline static int
function compute_flushbits (line 801) | int
function flush_bitstream (line 862) | void
function add_dummy_byte (line 892) | void
function format_bitstream (line 917) | int
function do_gain_analysis (line 987) | static int
function do_copy_buffer (line 1055) | static int
function copy_buffer (line 1078) | int
function init_bit_stream_w (line 1096) | void
FILE: app/src/main/jni/libmp3lame/encoder.c
function adjust_ATH (line 55) | static void
function updateStats (line 154) | static void
function lame_encode_frame_init (line 188) | static void
type FLOAT (line 301) | typedef FLOAT chgrdata[2][2];
function lame_encode_mp3_frame (line 304) | int
FILE: app/src/main/jni/libmp3lame/encoder.h
type MPEGChannelMode (line 139) | enum MPEGChannelMode
type lame_internal_flags (line 148) | struct lame_internal_flags
type lame_internal_flags (line 149) | typedef struct lame_internal_flags lame_internal_flags;
FILE: app/src/main/jni/libmp3lame/fft.c
function fht (line 63) | static void
function fft_short (line 193) | void
function fft_long (line 245) | void
function init_fft (line 296) | void
FILE: app/src/main/jni/libmp3lame/gain_analysis.c
function filterYule (line 179) | static void
function filterButter (line 213) | static void
function ResetSampleFrequency (line 235) | int
function InitGainAnalysis (line 293) | int
function fsqr (line 314) | static inline double
function AnalyzeSamples (line 320) | int
function Float_t (line 456) | static Float_t
function Float_t (line 483) | Float_t
function Float_t (line 511) | Float_t
FILE: app/src/main/jni/libmp3lame/gain_analysis.h
type sample_t (line 44) | typedef sample_t Float_t;
type replaygain_data (line 69) | struct replaygain_data {
type replaygain_t (line 94) | typedef struct replaygain_data replaygain_t;
FILE: app/src/main/jni/libmp3lame/id3tag.c
type UsualStringIDs (line 124) | typedef enum UsualStringIDs { ID_TITLE = FRAME_ID('T', 'I', 'T', '2')
type NumericStringIDs (line 133) | typedef enum NumericStringIDs { ID_DATE = FRAME_ID('T', 'D', 'A', 'T') /...
type MiscIDs (line 140) | typedef enum MiscIDs { ID_TXXX = FRAME_ID('T', 'X', 'X', 'X')
function frame_id_matches (line 158) | static int
function isFrameIdMatching (line 172) | static int
function test_tag_spec_flags (line 178) | static int
function debug_tag_spec_flags (line 185) | static void
function copyV1ToV2 (line 205) | static void
function id3v2AddLameVersion (line 220) | static void
function id3v2AddAudioDuration (line 238) | static void
function id3tag_genre_list (line 262) | void
function id3tag_init (line 280) | void
function id3tag_add_v2 (line 293) | void
function id3tag_v1_only (line 301) | void
function id3tag_v2_only (line 309) | void
function id3tag_space_v1 (line 317) | void
function id3tag_pad_v2 (line 325) | void
function id3tag_set_pad (line 331) | void
function hasUcs2ByteOrderMarker (line 341) | static int
function swap_bytes (line 351) | static unsigned short
function toLittleEndian (line 358) | static unsigned short
function fromLatin1Char (line 367) | static unsigned short
function local_strdup (line 377) | static size_t
function local_ucs2_strdup (line 402) | static size_t
function local_ucs2_strlen (line 429) | static size_t
function local_ucs2_substr (line 442) | static size_t
function local_ucs2_pos (line 465) | static int
function local_char_pos (line 477) | static int
function maybeLatin1 (line 489) | static int
function lookupGenre (line 505) | static int
function id3tag_set_genre_utf16 (line 541) | static int
function id3tag_set_albumart (line 583) | int
function toID3v2TagId (line 634) | static uint32_t
function toID3v2TagId_ucs2 (line 655) | static uint32_t
function isNumericString (line 681) | static int
function isMultiFrame (line 696) | static int
function isFullTextString (line 718) | static int
function FrameDataNode (line 730) | static FrameDataNode *
function appendNode (line 743) | static void
function setLang (line 756) | static void
function isSameLang (line 775) | static int
function isSameDescriptor (line 795) | static int
function isSameDescriptorUcs2 (line 810) | static int
function id3v2_add_ucs2 (line 825) | static int
function id3v2_add_latin1 (line 860) | static int
function id3tag_set_userinfo_latin1 (line 896) | static int
function id3tag_set_userinfo_ucs2 (line 912) | static int
function id3tag_set_textinfo_utf16 (line 930) | int
function id3tag_set_textinfo_ucs2 (line 973) | int
function id3tag_set_textinfo_latin1 (line 979) | int
function id3tag_set_comment_latin1 (line 1012) | int
function id3tag_set_comment_utf16 (line 1019) | int
function id3tag_set_comment_ucs2 (line 1029) | int
function id3tag_set_title (line 1036) | void
function id3tag_set_artist (line 1047) | void
function id3tag_set_album (line 1058) | void
function id3tag_set_year (line 1069) | void
function id3tag_set_comment (line 1090) | void
function id3tag_set_track (line 1105) | int
function local_strcasecmp (line 1135) | static int
function sloppyCompared (line 1168) | static int
function sloppySearchGenre (line 1193) | static int
function searchGenre (line 1206) | static int
function id3tag_set_genre (line 1219) | int
function sizeOfNode (line 1242) | static size_t
function sizeOfCommentNode (line 1268) | static size_t
function sizeOfWxxxNode (line 1298) | static size_t
function id3tag_set_fieldvalue (line 1514) | int
function id3tag_set_fieldvalue_utf16 (line 1526) | int
function id3tag_set_fieldvalue_ucs2 (line 1556) | int
function lame_get_id3v2_tag (line 1562) | size_t
function id3tag_write_v2 (line 1711) | int
function lame_get_id3v1_tag (line 1762) | size_t
function id3tag_write_v1 (line 1812) | int
FILE: app/src/main/jni/libmp3lame/id3tag.h
type FrameDataNode (line 20) | typedef struct FrameDataNode {
type id3tag_spec (line 36) | typedef struct id3tag_spec {
FILE: app/src/main/jni/libmp3lame/l3side.h
type scalefac_struct (line 29) | typedef struct {
type III_psy_xmin (line 37) | typedef struct {
type III_psy_ratio (line 42) | typedef struct {
type gr_info (line 47) | typedef struct {
type III_side_info_t (line 86) | typedef struct {
FILE: app/src/main/jni/libmp3lame/lame-analysis.h
type plotting_data (line 34) | struct plotting_data {
type plotting_data (line 91) | typedef struct plotting_data plotting_data;
FILE: app/src/main/jni/libmp3lame/lame.c
function is_lame_global_flags_valid (line 68) | int
function is_lame_internal_flags_valid (line 79) | int
function FLOAT (line 91) | static FLOAT
function lame_init_params_ppflt (line 102) | static void
function optimum_bandwidth (line 193) | static void
function optimum_samplefreq (line 273) | static int
function lame_init_qval (line 362) | static void
function linear_int (line 481) | static double
function lame_init_params (line 537) | int
function concatSep (line 1307) | static void
function lame_print_config (line 1323) | void
function lame_print_internals (line 1414) | void
function save_gain_values (line 1587) | static void
function update_inbuffer_size (line 1618) | static int
function calcNeeded (line 1650) | static int
function lame_encode_buffer_sample_t (line 1694) | static int
type PCMSampleType (line 1800) | enum PCMSampleType
function lame_copy_inbuffer (line 1808) | static void
function lame_encode_buffer_template (line 1861) | static int
function lame_encode_buffer (line 1897) | int
function lame_encode_buffer_float (line 1906) | int
function lame_encode_buffer_ieee_float (line 1916) | int
function lame_encode_buffer_interleaved_ieee_float (line 1926) | int
function lame_encode_buffer_ieee_double (line 1936) | int
function lame_encode_buffer_interleaved_ieee_double (line 1946) | int
function lame_encode_buffer_int (line 1956) | int
function lame_encode_buffer_long2 (line 1967) | int
function lame_encode_buffer_long (line 1978) | int
function lame_encode_buffer_interleaved (line 1989) | int
function lame_encode_flush_nogap (line 2010) | int
function lame_init_bitstream (line 2028) | int
function lame_encode_flush (line 2064) | int
function lame_close (line 2208) | int
function lame_encode_finish (line 2241) | int
function lame_mp3_tags_fid (line 2256) | void
function lame_init_old (line 2302) | int
function lame_global_flags (line 2418) | lame_global_flags *
function lame_bitrate_kbps (line 2467) | void
function lame_bitrate_hist (line 2489) | void
function lame_stereo_mode_hist (line 2515) | void
function lame_bitrate_stereo_mode_hist (line 2533) | void
function lame_block_type_hist (line 2565) | void
function lame_bitrate_block_type_hist (line 2583) | void
FILE: app/src/main/jni/libmp3lame/lame.h
type vbr_mode (line 49) | typedef enum vbr_mode_e {
type MPEG_mode (line 61) | typedef enum MPEG_mode_e {
type Padding_type (line 71) | typedef enum Padding_type_e {
type preset_mode (line 81) | typedef enum preset_mode_e {
type asm_optimizations (line 123) | typedef enum asm_optimizations_e {
type Psy_model (line 131) | typedef enum Psy_model_e {
type buffer_constraint (line 138) | typedef enum buffer_constraint_e {
type lame_global_struct (line 145) | struct lame_global_struct
type lame_global_flags (line 146) | typedef struct lame_global_struct lame_global_flags;
type lame_global_flags (line 147) | typedef lame_global_flags *lame_t;
type lame_version_t (line 655) | typedef struct {
type hip_global_struct (line 1008) | struct hip_global_struct
type hip_global_flags (line 1009) | typedef struct hip_global_struct hip_global_flags;
type hip_global_flags (line 1010) | typedef hip_global_flags *hip_t;
type mp3data_struct (line 1013) | typedef struct {
type lame_errorcodes_t (line 1304) | typedef enum {
FILE: app/src/main/jni/libmp3lame/lame_global_flags.h
type lame_internal_flags (line 6) | struct lame_internal_flags
type lame_internal_flags (line 7) | typedef struct lame_internal_flags lame_internal_flags;
type short_block_t (line 11) | typedef enum short_block_e {
type lame_global_struct (line 27) | struct lame_global_struct {
FILE: app/src/main/jni/libmp3lame/lameerror.h
type lame_errorcodes_t (line 11) | typedef enum {
FILE: app/src/main/jni/libmp3lame/machine.h
type FLOAT (line 135) | typedef float FLOAT;
type FLOAT8 (line 145) | typedef double FLOAT8;
type FLOAT (line 160) | typedef FLOAT sample_t;
FILE: app/src/main/jni/libmp3lame/mpglib_interface.c
function lame_decode_exit (line 85) | int
function lame_decode_init (line 93) | int
function decode1_headersB_clipchoice (line 128) | static int
function lame_decode1_headersB (line 247) | int
function lame_decode1_headers (line 272) | int
function lame_decode1 (line 281) | int
function lame_decode_headers (line 297) | int
function lame_decode (line 319) | int
function hip_t (line 330) | hip_t hip_decode_init(void)
function hip_decode_exit (line 338) | int hip_decode_exit(hip_t hip)
function hip_decode1_unclipped (line 351) | int
function hip_decode1_headers (line 374) | int
function hip_decode1 (line 383) | int
function hip_decode_headers (line 398) | int
function hip_decode (line 420) | int
function hip_decode1_headersB (line 428) | int
function hip_set_pinfo (line 444) | void hip_set_pinfo(hip_t hip, plotting_data* pinfo)
function hip_set_errorf (line 453) | void hip_set_errorf(hip_t hip, lame_report_function func)
function hip_set_debugf (line 460) | void hip_set_debugf(hip_t hip, lame_report_function func)
function hip_set_msgf (line 467) | void hip_set_msgf (hip_t hip, lame_report_function func)
FILE: app/src/main/jni/libmp3lame/newmdct.c
function window_subband (line 430) | inline static void
function mdct_short (line 832) | inline static void
function mdct_long (line 869) | inline static void
function mdct_sub48 (line 944) | void
FILE: app/src/main/jni/libmp3lame/presets.c
function min_int (line 47) | static inline int
function max_int (line 56) | static inline int
type vbr_presets_t (line 67) | typedef struct {
function vbr_presets_t (line 127) | static vbr_presets_t const*
function apply_vbr_preset (line 142) | static void
function apply_abr_preset (line 211) | static int
function apply_preset (line 315) | int
FILE: app/src/main/jni/libmp3lame/psymodel.c
function FLOAT (line 213) | static FLOAT
function mask_add_delta (line 273) | inline static int
function init_mask_add_max_values (line 282) | static void
function FLOAT (line 294) | inline static FLOAT
function convert_partition2scalefac (line 350) | static void
function convert_partition2scalefac_s (line 395) | static void
function convert_partition2scalefac_l (line 411) | static void
function convert_partition2scalefac_l_to_s (line 421) | static void
function FLOAT (line 443) | static inline FLOAT
function FLOAT (line 458) | static FLOAT
function FLOAT (line 503) | static FLOAT
function calc_energy (line 556) | static void
function calc_mask_index_l (line 583) | static void
function vbrpsy_compute_fft_l (line 655) | static void
function vbrpsy_compute_fft_s (line 707) | static void
function vbrpsy_compute_loudness_approximation_l (line 743) | static void
function vbrpsy_attack_detection (line 759) | static void
function vbrpsy_skip_masking_s (line 943) | static void
function vbrpsy_calc_mask_index_s (line 958) | static void
function vbrpsy_compute_masking_s (line 1031) | static void
function vbrpsy_compute_masking_l (line 1134) | static void
function vbrpsy_compute_block_type (line 1265) | static void
function vbrpsy_apply_block_type (line 1289) | static void
function vbrpsy_compute_MS_thresholds (line 1326) | static void
function L3psycho_anal_vbr (line 1397) | int
function FLOAT (line 1605) | static FLOAT
function FLOAT (line 1641) | static FLOAT
function FLOAT (line 1690) | static FLOAT
function init_numline (line 1701) | static void
function compute_bark_values (line 1794) | static void
function init_s3_values (line 1816) | static int
function psymodel_init (line 1867) | int
FILE: app/src/main/jni/libmp3lame/quantize.c
function ms_convert (line 48) | static void
function init_xrpow_core_c (line 72) | static void
function init_xrpow_core_init (line 92) | void
function init_xrpow (line 110) | static int
function psfb21_analogsilence (line 159) | static void
function init_outer_loop (line 226) | static void
type binsearchDirection_t (line 361) | typedef enum {
function bin_search_StepSize (line 367) | static int
function floatcompare (line 443) | static int
function trancate_smallspectrums (line 454) | static void
function loop_break (line 540) | inline static int
function penalties (line 568) | static double
function get_klemm_noise (line 574) | static double
function quant_compare (line 585) | inline static int
function amp_scalefac_bands (line 720) | static void
function inc_scalefac_scale (line 808) | static void
function inc_subblock_gain (line 847) | static int
function balance_noise (line 940) | inline static int
function outer_loop (line 1010) | static int
function iteration_finish_one (line 1213) | static void
function VBR_encode_granule (line 1244) | static void
function get_framebits (line 1340) | static void
function VBR_old_prepare (line 1389) | static int
function bitpressure_strategy (line 1453) | static void
function VBR_old_iteration_loop (line 1490) | void
function VBR_new_prepare (line 1582) | static int
function VBR_new_iteration_loop (line 1645) | void
function calc_target_bits (line 1767) | static void
function ABR_iteration_loop (line 1900) | void
function CBR_iteration_loop (line 1988) | void
FILE: app/src/main/jni/libmp3lame/quantize_pvt.c
function FLOAT (line 210) | static FLOAT
function compute_ath (line 230) | static void
function iteration_init (line 336) | void
function on_pe (line 428) | int
function reduce_side (line 492) | void
function FLOAT (line 554) | FLOAT
function calc_xmin (line 589) | int
function FLOAT (line 750) | static FLOAT
function calc_noise (line 815) | int
function set_pinfo (line 934) | static void
function set_frame_pinfo (line 1044) | void
FILE: app/src/main/jni/libmp3lame/quantize_pvt.h
type calc_noise_result (line 61) | typedef struct calc_noise_result_t {
type calc_noise_data (line 75) | typedef struct calc_noise_data_t {
FILE: app/src/main/jni/libmp3lame/reservoir.c
function ResvFrameBegin (line 82) | int
function ResvMaxBits (line 174) | void
function ResvAdjust (line 225) | void
function ResvFrameEnd (line 238) | void
FILE: app/src/main/jni/libmp3lame/set_get.c
function lame_set_num_samples (line 45) | int
function lame_get_num_samples (line 56) | unsigned long
function lame_set_in_samplerate (line 67) | int
function lame_get_in_samplerate (line 78) | int
function lame_set_num_channels (line 89) | int
function lame_get_num_channels (line 103) | int
function lame_set_scale (line 114) | int
function lame_get_scale (line 125) | float
function lame_set_scale_left (line 137) | int
function lame_get_scale_left (line 148) | float
function lame_set_scale_right (line 160) | int
function lame_get_scale_right (line 171) | float
function lame_set_out_samplerate (line 182) | int
function lame_get_out_samplerate (line 202) | int
function lame_set_analysis (line 219) | int
function lame_get_analysis (line 236) | int
function lame_set_bWriteVbrTag (line 248) | int
function lame_get_bWriteVbrTag (line 265) | int
function lame_set_decode_only (line 278) | int
function lame_get_decode_only (line 295) | int
function lame_set_ogg (line 316) | int
function lame_get_ogg (line 324) | int
function lame_set_quality (line 341) | int
function lame_get_quality (line 359) | int
function lame_set_mode (line 370) | int
function MPEG_mode (line 384) | MPEG_mode
function lame_set_mode_automs (line 408) | int
function lame_get_mode_automs (line 425) | int
function lame_set_force_ms (line 437) | int
function lame_get_force_ms (line 454) | int
function lame_set_free_format (line 466) | int
function lame_get_free_format (line 483) | int
function lame_set_findReplayGain (line 496) | int
function lame_get_findReplayGain (line 513) | int
function lame_set_decode_on_the_fly (line 526) | int
function lame_get_decode_on_the_fly (line 549) | int
function lame_set_findPeakSample (line 579) | int
function lame_get_findPeakSample (line 585) | int
function lame_set_ReplayGain_input (line 592) | int
function lame_get_ReplayGain_input (line 598) | int
function lame_set_ReplayGain_decode (line 606) | int
function lame_get_ReplayGain_decode (line 615) | int
function lame_set_nogap_total (line 627) | int
function lame_get_nogap_total (line 637) | int
function lame_set_nogap_currentindex (line 646) | int
function lame_get_nogap_currentindex (line 656) | int
function lame_set_errorf (line 667) | int
function lame_set_debugf (line 677) | int
function lame_set_msgf (line 687) | int
function lame_set_brate (line 705) | int
function lame_get_brate (line 718) | int
function lame_set_compression_ratio (line 727) | int
function lame_get_compression_ratio (line 737) | float
function lame_set_copyright (line 754) | int
function lame_get_copyright (line 771) | int
function lame_set_original (line 783) | int
function lame_get_original (line 800) | int
function lame_set_error_protection (line 815) | int
function lame_get_error_protection (line 832) | int
function lame_set_padding_type (line 856) | int
function Padding_type (line 864) | Padding_type
function lame_set_extension (line 873) | int
function lame_get_extension (line 889) | int
function lame_set_strict_ISO (line 901) | int
function lame_get_strict_ISO (line 917) | int
function lame_set_disable_reservoir (line 934) | int
function lame_get_disable_reservoir (line 951) | int
function lame_set_experimentalX (line 964) | int
function lame_get_experimentalX (line 975) | int
function lame_set_quant_comp (line 983) | int
function lame_get_quant_comp (line 993) | int
function lame_set_quant_comp_short (line 1004) | int
function lame_get_quant_comp_short (line 1014) | int
function lame_set_experimentalY (line 1025) | int
function lame_get_experimentalY (line 1035) | int
function lame_set_experimentalZ (line 1045) | int
function lame_get_experimentalZ (line 1055) | int
function lame_set_exp_nspsytune (line 1066) | int
function lame_get_exp_nspsytune (line 1077) | int
function lame_set_VBR (line 1094) | int
function vbr_mode (line 1107) | vbr_mode
function lame_set_VBR_q (line 1123) | int
function lame_get_VBR_q (line 1144) | int
function lame_set_VBR_quality (line 1154) | int
function lame_get_VBR_quality (line 1177) | float
function lame_set_VBR_mean_bitrate_kbps (line 1188) | int
function lame_get_VBR_mean_bitrate_kbps (line 1198) | int
function lame_set_VBR_min_bitrate_kbps (line 1207) | int
function lame_get_VBR_min_bitrate_kbps (line 1217) | int
function lame_set_VBR_max_bitrate_kbps (line 1226) | int
function lame_get_VBR_max_bitrate_kbps (line 1236) | int
function lame_set_VBR_hard_min (line 1250) | int
function lame_get_VBR_hard_min (line 1269) | int
function lame_set_lowpassfreq (line 1289) | int
function lame_get_lowpassfreq (line 1299) | int
function lame_set_lowpasswidth (line 1313) | int
function lame_get_lowpasswidth (line 1323) | int
function lame_set_highpassfreq (line 1338) | int
function lame_get_highpassfreq (line 1348) | int
function lame_set_highpasswidth (line 1362) | int
function lame_get_highpasswidth (line 1372) | int
function lame_set_maskingadjust (line 1391) | int
function lame_get_maskingadjust (line 1401) | float
function lame_set_maskingadjust_short (line 1410) | int
function lame_get_maskingadjust_short (line 1420) | float
function lame_set_ATHonly (line 1430) | int
function lame_get_ATHonly (line 1440) | int
function lame_set_ATHshort (line 1451) | int
function lame_get_ATHshort (line 1461) | int
function lame_set_noATH (line 1472) | int
function lame_get_noATH (line 1482) | int
function lame_set_ATHtype (line 1493) | int
function lame_get_ATHtype (line 1504) | int
function lame_set_ATHcurve (line 1515) | int
function lame_get_ATHcurve (line 1525) | float
function lame_set_ATHlower (line 1536) | int
function lame_get_ATHlower (line 1546) | float
function lame_set_athaa_type (line 1557) | int
function lame_get_athaa_type (line 1567) | int
function lame_set_athaa_loudapprox (line 1584) | int
function lame_get_athaa_loudapprox (line 1592) | int
function lame_set_athaa_sensitivity (line 1602) | int
function lame_get_athaa_sensitivity (line 1612) | float
function lame_set_cwlimit (line 1626) | int
function lame_get_cwlimit (line 1634) | int
function lame_set_allow_diff_short (line 1649) | int
function lame_get_allow_diff_short (line 1659) | int
function lame_set_useTemporal (line 1673) | int
function lame_get_useTemporal (line 1690) | int
function lame_set_interChRatio (line 1702) | int
function lame_get_interChRatio (line 1715) | float
function lame_set_substep (line 1727) | int
function lame_get_substep (line 1740) | int
function lame_set_sfscale (line 1751) | int
function lame_get_sfscale (line 1761) | int
function lame_set_subblock_gain (line 1771) | int
function lame_get_subblock_gain (line 1781) | int
function lame_set_no_short_blocks (line 1792) | int
function lame_get_no_short_blocks (line 1807) | int
function lame_set_force_short_blocks (line 1828) | int
function lame_get_force_short_blocks (line 1848) | int
function lame_set_short_threshold_lrm (line 1867) | int
function lame_get_short_threshold_lrm (line 1877) | float
function lame_set_short_threshold_s (line 1886) | int
function lame_get_short_threshold_s (line 1896) | float
function lame_set_short_threshold (line 1905) | int
function lame_set_emphasis (line 1925) | int
function lame_get_emphasis (line 1938) | int
function lame_get_version (line 1961) | int
function lame_get_encoder_delay (line 1975) | int
function lame_get_encoder_padding (line 1988) | int
function lame_get_framesize (line 2002) | int
function lame_get_frameNum (line 2017) | int
function lame_get_mf_samples_to_encode (line 2029) | int
function lame_get_size_mp3buffer (line 2041) | int CDECL
function lame_get_RadioGain (line 2055) | int
function lame_get_AudiophileGain (line 2067) | int
function lame_get_PeakSample (line 2079) | float
function lame_get_noclipGainChange (line 2091) | int
function lame_get_noclipScale (line 2103) | float
function lame_get_totalframes (line 2120) | int
function lame_set_preset (line 2158) | int
function lame_set_asm_optimizations (line 2170) | int
function lame_set_write_id3tag_automatic (line 2196) | void
function lame_get_write_id3tag_automatic (line 2205) | int
function lame_set_tune (line 2229) | void
function lame_set_msfix (line 2239) | void
function lame_get_msfix (line 2248) | float
function lame_set_preset_expopts (line 2262) | int
function lame_set_preset_notune (line 2271) | int
FILE: app/src/main/jni/libmp3lame/tables.c
type huffcodetab (line 409) | struct huffcodetab
type MPEG_t (line 520) | typedef enum {
function lame_get_bitrate (line 538) | int
function lame_get_samplerate (line 549) | int
FILE: app/src/main/jni/libmp3lame/tables.h
type type1_t (line 26) | typedef struct {
type type2_t (line 35) | typedef struct {
type type34_t (line 44) | typedef struct {
type type5_t (line 53) | typedef struct {
type huffcodetab (line 70) | struct huffcodetab {
type huffcodetab (line 77) | struct huffcodetab
FILE: app/src/main/jni/libmp3lame/takehiro.c
function quantize_lines_xrpow_01 (line 113) | static void
type fi_union (line 135) | typedef union {
function quantize_lines_xrpow (line 144) | static void
function quantize_lines_xrpow (line 222) | static void
function quantize_xrpow (line 281) | static void
function ix_max (line 423) | static int
function count_bit_ESC (line 449) | static int
function count_bit_noESC (line 486) | static int
function count_bit_noESC_from2 (line 510) | static int
function count_bit_noESC_from3 (line 538) | inline static int
function count_bit_null (line 588) | static int count_bit_null(const int* ix, const int* end, int max, unsign...
function choose_table_nonMMX (line 618) | static int
function noquant_count_bits (line 654) | int
function count_bits (line 767) | int
function recalc_divide_init (line 809) | inline static void
function recalc_divide_sub (line 847) | inline static void
function best_huffman_divide (line 884) | void
function scfsi_calc (line 964) | static void
function best_scalefac_store (line 1021) | void
function all_scalefactors_not_negative (line 1098) | static int
function mpeg1_scale_bitcount (line 1135) | static int
function mpeg2_scale_bitcount (line 1217) | static int
function scale_bitcount (line 1318) | int
function huffman_init (line 1334) | void
FILE: app/src/main/jni/libmp3lame/util.c
function free_id3tag (line 48) | void
function free_global_data (line 91) | static void
function freegfc (line 109) | void
function malloc_aligned (line 165) | void
function free_aligned (line 181) | void
function FLOAT (line 196) | static FLOAT
function FLOAT (line 240) | FLOAT
function FLOAT (line 271) | FLOAT
function FLOAT (line 285) | FLOAT
function FindNearestBitrate (line 300) | int
function nearestBitrateFullIndex (line 341) | int
function map2MP3Frequency (line 390) | int
function BitrateIndex (line 413) | int
function SmpFrqIndex (line 433) | int
function FLOAT (line 487) | inline static FLOAT
function gcd (line 519) | static int
function fill_buffer_resample (line 528) | static int
function isResamplingNecessary (line 651) | int
function fill_buffer (line 663) | void
function lame_report_def (line 704) | void
function lame_report_fnc (line 711) | void
function lame_debugf (line 723) | void
function lame_msgf (line 735) | void
function lame_errorf (line 747) | void
function has_MMX (line 776) | int
function has_3DNow (line 786) | int
function has_SSE (line 796) | int
function has_SSE2 (line 810) | int
function disable_FPE (line 824) | void
function init_log_table (line 956) | void
function ieee754_float32_t (line 974) | ieee754_float32_t
function init_log_table (line 1001) | void
FILE: app/src/main/jni/libmp3lame/util.h
type replaygain_data (line 108) | struct replaygain_data
type replaygain_t (line 111) | typedef struct replaygain_data replaygain_t;
type plotting_data (line 113) | struct plotting_data
type plotting_data (line 116) | typedef struct plotting_data plotting_data;
type aligned_pointer_t (line 125) | typedef struct {
type Bit_stream_struc (line 140) | typedef struct bit_stream_struc {
type VBR_seek_info_t (line 152) | typedef struct {
type ATH_t (line 170) | typedef struct {
type PsyConst_CB2SB_t (line 192) | typedef struct {
type PsyConst_t (line 213) | typedef struct {
type PsyStateVar_t (line 223) | typedef struct {
type PsyResult_t (line 243) | typedef struct {
type EncStateVar_t (line 250) | typedef struct {
type EncResult_t (line 307) | typedef struct {
type QntStateVar_t (line 322) | typedef struct {
type RpgStateVar_t (line 345) | typedef struct {
type RpgResult_t (line 351) | typedef struct {
type SessionConfig_t (line 359) | typedef struct {
type lame_internal_flags (line 466) | struct lame_internal_flags {
type lame_internal_flags (line 552) | typedef struct lame_internal_flags lame_internal_flags;
FILE: app/src/main/jni/libmp3lame/vbrquantize.c
type algo_s (line 40) | struct algo_s
type algo_t (line 41) | typedef struct algo_s algo_t;
type algo_s (line 46) | struct algo_s {
type VOLATILE (line 77) | typedef VOLATILE union
function vec_max_c (line 115) | inline static float
function find_lowest_scalefac (line 147) | inline static uint8_t
function k_34_4 (line 169) | inline static void
function FLOAT (line 217) | static FLOAT
type calc_noise_cache (line 269) | struct calc_noise_cache {
type calc_noise_cache_t (line 274) | typedef struct calc_noise_cache calc_noise_cache_t;
function tri_calc_sfb_noise_x34 (line 277) | static uint8_t
function calc_scalefac (line 316) | static int
function guess_scalefac_x34 (line 323) | static uint8_t
function find_scalefac_x34 (line 346) | static uint8_t
function block_sf (line 394) | static int
function quantize_x34 (line 500) | static void
function set_subblock_gain (line 595) | static void
function set_scalefacs (line 688) | static void
function checkScalefactor (line 732) | static int
function short_block_constrain (line 769) | static void
function long_block_constrain (line 847) | static void
function bitcount (line 984) | static void
function quantizeAndCountBits (line 999) | static int
function tryGlobalStepsize (line 1011) | static int
function searchGlobalStepsizeMax (line 1040) | static void
function sfDepth (line 1074) | static int
function cutDistribution (line 1093) | static void
function flattenDistribution (line 1104) | static int
function tryThatOne (line 1140) | static int
function outOfBitsStrategy (line 1154) | static void
function reduce_bit_usage (line 1231) | static int
function VBR_encode_frame (line 1254) | int
FILE: app/src/main/jni/libmp3lame/version.c
function get_lame_version_numerical (line 203) | void
FILE: app/src/test/java/com/convert/mymp3convert/ExampleUnitTest.java
class ExampleUnitTest (line 14) | public class ExampleUnitTest {
method addition_isCorrect (line 15) | @Test
method test (line 19) | @Test
FILE: demo/src/androidTest/java/com/convert/demo/ExampleInstrumentedTest.java
class ExampleInstrumentedTest (line 18) | @RunWith(AndroidJUnit4.class)
method useAppContext (line 20) | @Test
FILE: demo/src/main/java/com/convert/demo/MainActivity.java
class MainActivity (line 12) | public class MainActivity extends AppCompatActivity {
method onCreate (line 14) | @Override
method click (line 20) | public void click(View v){
FILE: demo/src/test/java/com/convert/demo/ExampleUnitTest.java
class ExampleUnitTest (line 12) | public class ExampleUnitTest {
method addition_isCorrect (line 13) | @Test
Condensed preview — 100 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (938K chars).
[
{
"path": ".gitignore",
"chars": 109,
"preview": "*.iml\n.gradle\n/local.properties\n.idea/\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n"
},
{
"path": "README.md",
"chars": 3653,
"preview": "# MyMp3Convert\nmp3Convert\n一个mp3转换库,基于lame3来实现\n\n模块简介:\n================================================\n主要实现了wav格式向mp3格式的转"
},
{
"path": "app/.gitignore",
"chars": 6,
"preview": "/build"
},
{
"path": "app/CMakeLists.txt",
"chars": 2112,
"preview": "\n#指定CMake构建本地库时所需的最小版本\ncmake_minimum_required(VERSION 3.4.1)\n\n#该变量为真时会创建完整版本的Makefile\nset(CMAKE_VERBOSE_MAKEFILE on)\nset"
},
{
"path": "app/build.gradle",
"chars": 3099,
"preview": "//plugins {\n// id 'com.android.application'\n//}\nif(isAppLibrary.toBoolean()){\n apply plugin: 'com.android.library'"
},
{
"path": "app/proguard-rules.pro",
"chars": 750,
"preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
},
{
"path": "app/src/androidTest/java/com/convert/mymp3convert/ExampleInstrumentedTest.java",
"chars": 762,
"preview": "package com.convert.mymp3convert;\n\nimport android.content.Context;\n\nimport androidx.test.platform.app.InstrumentationReg"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 1153,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/java/com/convert/mymp3convert/MainActivity.java",
"chars": 3603,
"preview": "package com.convert.mymp3convert;\n\nimport android.Manifest;\nimport android.os.Bundle;\nimport android.os.Environment;\nimp"
},
{
"path": "app/src/main/java/com/convert/mymp3convert/MainActivity2.kt",
"chars": 307,
"preview": "package com.convert.mymp3convert\n\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\n\nclass MainAc"
},
{
"path": "app/src/main/java/com/convert/mymp3convert/Mp3ConvertUtil.java",
"chars": 4779,
"preview": "package com.convert.mymp3convert;\n\nimport android.util.Log;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic clas"
},
{
"path": "app/src/main/java/com/convert/mymp3convert/Mp3ConvertUtilHelper.java",
"chars": 1060,
"preview": "package com.convert.mymp3convert;\n\npublic class Mp3ConvertUtilHelper {\n /**\n * 获取版本号\n * @return\n */\n p"
},
{
"path": "app/src/main/java/com/convert/mymp3convert/MyTest.java",
"chars": 99,
"preview": "package com.convert.mymp3convert;\n\npublic class MyTest {\n public static native String test();\n}\n"
},
{
"path": "app/src/main/java/com/convert/mymp3convert/test/Demo.java",
"chars": 194,
"preview": "package com.convert.mymp3convert.test;\n\nimport com.convert.mymp3convert.Mp3ConvertUtil;\n\npublic class Demo {\n private"
},
{
"path": "app/src/main/jni/NativeMp3ConvertUtil.cpp",
"chars": 10102,
"preview": "//\n// Created by shaomingfa on 2021/1/14.\n//\n\n#include <string>\n#include \"libmp3lame/lame.h\"\n\n#include <jni.h>\n\n#include"
},
{
"path": "app/src/main/jni/NativeMp3ConvertUtil.cpp.bak",
"chars": 10102,
"preview": "//\n// Created by shaomingfa on 2021/1/14.\n//\n\n#include <string>\n#include \"libmp3lame/lame.h\"\n\n#include <jni.h>\n\n#include"
},
{
"path": "app/src/main/jni/NativeMp3ConvertUtil.h",
"chars": 232,
"preview": "//\n// Created by shaomingfa on 2021/1/14.\n//\n#include <jni.h>\n#ifndef MYMP3CONVERT_NATIVEMP3CONVERTUTIL_H\n#define MYMP3C"
},
{
"path": "app/src/main/jni/NativeMyTest.cpp",
"chars": 1317,
"preview": "//\n// Created by shaomingfa on 2021/1/14.\n//\n#include <jni.h>\n#include <string>\n#include \"com_convert_mymp3convert_MyTes"
},
{
"path": "app/src/main/jni/com_convert_mymp3convert_Mp3ConvertUtil.h",
"chars": 1054,
"preview": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class com_convert_mymp3convert_Mp3C"
},
{
"path": "app/src/main/jni/com_convert_mymp3convert_MyTest.h",
"chars": 406,
"preview": "/* DO NOT EDIT THIS FILE - it is machine generated */\n/* Header for class com_convert_mymp3convert_MyTest */\n\n#pragma on"
},
{
"path": "app/src/main/jni/libmp3lame/VbrTag.c",
"chars": 31613,
"preview": "/*\n * Xing VBR tagging for LAME.\n *\n * Copyright (c) 1999 A.L. Faber\n * Copyright (c) 2001 Jonathan Dee\n "
},
{
"path": "app/src/main/jni/libmp3lame/VbrTag.h",
"chars": 2929,
"preview": "/*\n * Xing VBR tagging for LAME.\n *\n * Copyright (c) 1999 A.L. Faber\n *\n * This library is free software; you "
},
{
"path": "app/src/main/jni/libmp3lame/bitstream.c",
"chars": 36122,
"preview": "/*\n * MP3 bitstream Output interface for LAME\n *\n * Copyright (c) 1999-2000 Mark Taylor\n * Copyright (c) "
},
{
"path": "app/src/main/jni/libmp3lame/bitstream.h",
"chars": 1563,
"preview": "/*\n *\tMP3 bitstream Output interface for LAME\n *\n *\tCopyright (c) 1999 Takehiro TOMINAGA\n *\n * This library is free soft"
},
{
"path": "app/src/main/jni/libmp3lame/encoder.c",
"chars": 18055,
"preview": "/*\n * LAME MP3 encoding engine\n *\n * Copyright (c) 1999 Mark Taylor\n * Copyright (c) 2000-2002 Takehiro T"
},
{
"path": "app/src/main/jni/libmp3lame/encoder.h",
"chars": 4096,
"preview": "/*\n * encoder.h include file\n *\n * Copyright (c) 2000 Mark Taylor\n *\n * This library is free software; you can"
},
{
"path": "app/src/main/jni/libmp3lame/fft.c",
"chars": 9761,
"preview": "/*\n** FFT and FHT routines\n** Copyright 1988, 1993; Ron Mayer\n** Copyright (c) 1999-2000 Takehiro Tominaga\n**\n** "
},
{
"path": "app/src/main/jni/libmp3lame/fft.h",
"chars": 1227,
"preview": "/*\n *\tFast Fourier Transform include file\n *\n *\tCopyright (c) 2000 Mark Taylor\n *\n * This library is free software; you "
},
{
"path": "app/src/main/jni/libmp3lame/gain_analysis.c",
"chars": 19486,
"preview": "/*\n * ReplayGainAnalysis - analyzes input samples and give the recommended dB change\n * Copyright (C) 2001 David Robin"
},
{
"path": "app/src/main/jni/libmp3lame/gain_analysis.h",
"chars": 4202,
"preview": "/*\n * ReplayGainAnalysis - analyzes input samples and give the recommended dB change\n * Copyright (C) 2001 David Robin"
},
{
"path": "app/src/main/jni/libmp3lame/id3tag.c",
"chars": 51692,
"preview": "/*\n * id3tag.c -- Write ID3 version 1 and 2 tags.\n *\n * Copyright (C) 2000 Don Melton\n * Copyright (C) 2011-2012 Robert "
},
{
"path": "app/src/main/jni/libmp3lame/id3tag.h",
"chars": 1714,
"preview": "\n#ifndef LAME_ID3_H\n#define LAME_ID3_H\n\n\n#define CHANGED_FLAG (1U << 0)\n#define ADD_V2_FLAG (1U << 1)\n#define V1_"
},
{
"path": "app/src/main/jni/libmp3lame/l3side.h",
"chars": 2414,
"preview": "/*\n *\tLayer 3 side include file\n *\n *\tCopyright (c) 1999 Mark Taylor\n *\n * This library is free software; you can redist"
},
{
"path": "app/src/main/jni/libmp3lame/lame-analysis.h",
"chars": 3077,
"preview": "/*\n * GTK plotting routines source file\n *\n * Copyright (c) 1999 Mark Taylor\n *\n * This library is free softwa"
},
{
"path": "app/src/main/jni/libmp3lame/lame.c",
"chars": 82599,
"preview": "/* -*- mode: C; mode: fold -*- */\n/*\n * LAME MP3 encoding engine\n *\n * Copyright (c) 1999-2000 Mark Taylor\n * "
},
{
"path": "app/src/main/jni/libmp3lame/lame.h",
"chars": 48851,
"preview": "/*\n *\tInterface to MP3 LAME encoding engine\n *\n *\tCopyright (c) 1999 Mark Taylor\n *\n * This library is free software; yo"
},
{
"path": "app/src/main/jni/libmp3lame/lame_global_flags.h",
"chars": 8165,
"preview": "#ifndef LAME_GLOBAL_FLAGS_H\n#define LAME_GLOBAL_FLAGS_H\n\n#ifndef lame_internal_flags_defined\n#define lame_internal_flags"
},
{
"path": "app/src/main/jni/libmp3lame/lameerror.h",
"chars": 637,
"preview": "/*\n * A collection of LAME Error Codes\n *\n * Please use the constants defined here instead of some arbitrary\n * value"
},
{
"path": "app/src/main/jni/libmp3lame/machine.h",
"chars": 4342,
"preview": "/*\n * Machine dependent defines/includes for LAME.\n *\n * Copyright (c) 1999 A.L. Faber\n *\n * This library is f"
},
{
"path": "app/src/main/jni/libmp3lame/mpglib_interface.c",
"chars": 13828,
"preview": "/* -*- mode: C; mode: fold -*- */\n/*\n * LAME MP3 encoding engine\n *\n * Copyright (c) 1999-2000 Mark Taylor\n * "
},
{
"path": "app/src/main/jni/libmp3lame/newmdct.c",
"chars": 37124,
"preview": "/*\n * MP3 window subband -> subband filtering -> mdct routine\n *\n * Copyright (c) 1999-2000 Takehiro Tominaga\n"
},
{
"path": "app/src/main/jni/libmp3lame/newmdct.h",
"chars": 993,
"preview": "/*\n *\tNew Modified DCT include file\n *\n *\tCopyright (c) 1999 Takehiro TOMINAGA\n *\n * This library is free software; you "
},
{
"path": "app/src/main/jni/libmp3lame/presets.c",
"chars": 15429,
"preview": "/*\n * presets.c -- Apply presets\n *\n *\tCopyright (c) 2002-2008 Gabriel Bouvigne\n *\tCopyright (c) 2007-2011 Robert Hegema"
},
{
"path": "app/src/main/jni/libmp3lame/psymodel.c",
"chars": 70574,
"preview": "/*\n * psymodel.c\n *\n * Copyright (c) 1999-2000 Mark Taylor\n * Copyright (c) 2001-2002 Naoki Shibata\n * "
},
{
"path": "app/src/main/jni/libmp3lame/psymodel.h",
"chars": 2024,
"preview": "/*\n *\tpsymodel.h\n *\n *\tCopyright (c) 1999 Mark Taylor\n *\n * This library is free software; you can redistribute it and/o"
},
{
"path": "app/src/main/jni/libmp3lame/quantize.c",
"chars": 65774,
"preview": "/*\n * MP3 quantization\n *\n * Copyright (c) 1999-2000 Mark Taylor\n * Copyright (c) 1999-2003 Takehiro Tominaga\n"
},
{
"path": "app/src/main/jni/libmp3lame/quantize.h",
"chars": 1556,
"preview": "/*\n * MP3 quantization\n *\n * Copyright (c) 1999 Mark Taylor\n *\n * This library is free software; you can redistribute it"
},
{
"path": "app/src/main/jni/libmp3lame/quantize_pvt.c",
"chars": 34061,
"preview": "/*\n * quantize_pvt source file\n *\n * Copyright (c) 1999-2002 Takehiro Tominaga\n * Copyright (c) 2000-2012"
},
{
"path": "app/src/main/jni/libmp3lame/quantize_pvt.h",
"chars": 4263,
"preview": "/*\n *\tquantize_pvt include file\n *\n *\tCopyright (c) 1999 Takehiro TOMINAGA\n *\n * This library is free software; you can "
},
{
"path": "app/src/main/jni/libmp3lame/reservoir.c",
"chars": 10263,
"preview": "/*\n * bit reservoir source file\n *\n * Copyright (c) 1999-2000 Mark Taylor\n *\n * This library is free software;"
},
{
"path": "app/src/main/jni/libmp3lame/reservoir.h",
"chars": 1221,
"preview": "/*\n *\tbit reservoir include file\n *\n *\tCopyright (c) 1999 Mark Taylor\n *\n * This library is free software; you can redis"
},
{
"path": "app/src/main/jni/libmp3lame/set_get.c",
"chars": 51612,
"preview": "/* -*- mode: C; mode: fold -*- */\n/*\n * set/get functions for lame_global_flags\n *\n * Copyright (c) 2001-2005 Alexander "
},
{
"path": "app/src/main/jni/libmp3lame/set_get.h",
"chars": 2587,
"preview": "/*\n * set_get.h -- Internal set/get definitions\n *\n * Copyright (C) 2003 Gabriel Bouvigne / Lame project\n *\n * This libr"
},
{
"path": "app/src/main/jni/libmp3lame/tables.c",
"chars": 21364,
"preview": "/*\n *\tMPEG layer 3 tables source file\n *\n *\tCopyright (c) 1999 Albert L Faber\n *\n * This library is free software; you c"
},
{
"path": "app/src/main/jni/libmp3lame/tables.h",
"chars": 2473,
"preview": "/*\n *\tMPEG layer 3 tables include file\n *\n *\tCopyright (c) 1999 Albert L Faber\n *\n * This library is free software; you "
},
{
"path": "app/src/main/jni/libmp3lame/takehiro.c",
"chars": 38186,
"preview": "/*\n *\tMP3 huffman table selecting and bit counting\n *\n *\tCopyright (c) 1999-2005 Takehiro TOMINAGA\n *\tCopyright (c) 2002"
},
{
"path": "app/src/main/jni/libmp3lame/util.c",
"chars": 25600,
"preview": "/*\n *\tlame utility library source file\n *\n *\tCopyright (c) 1999 Albert L Faber\n *\tCopyright (c) 2000-2005 Alexander Leid"
},
{
"path": "app/src/main/jni/libmp3lame/util.h",
"chars": 22089,
"preview": "/*\n * lame utility library include file\n *\n * Copyright (c) 1999 Albert L Faber\n * Copyright (c) 2008 Rob"
},
{
"path": "app/src/main/jni/libmp3lame/vbrquantize.c",
"chars": 46728,
"preview": "/*\n *\tMP3 quantization\n *\n *\tCopyright (c) 1999-2000 Mark Taylor\n *\tCopyright (c) 2000-2012 Robert Hegemann\n *\n * This l"
},
{
"path": "app/src/main/jni/libmp3lame/vbrquantize.h",
"chars": 1072,
"preview": "/*\n * MP3 VBR quantization\n *\n * Copyright (c) 1999 Mark Taylor\n *\n * This library is free software; you can redistribut"
},
{
"path": "app/src/main/jni/libmp3lame/version.c",
"chars": 6885,
"preview": "/*\n * Version numbering for LAME.\n *\n * Copyright (c) 1999 A.L. Faber\n *\n * This library is free software; you"
},
{
"path": "app/src/main/jni/libmp3lame/version.h",
"chars": 2306,
"preview": "/*\n * Version numbering for LAME.\n *\n * Copyright (c) 1999 A.L. Faber\n *\n * This library is free software; you"
},
{
"path": "app/src/main/library/AndroidManifest.xml",
"chars": 889,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/res/drawable/ic_launcher_background.xml",
"chars": 5606,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
"chars": 1702,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/aapt\"\n "
},
{
"path": "app/src/main/res/layout/activity_main.xml",
"chars": 1511,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmln"
},
{
"path": "app/src/main/res/layout/activity_main2.xml",
"chars": 426,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 378,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"purple_200\">#FFBB86FC</color>\n <color name=\"purpl"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 74,
"preview": "<resources>\n <string name=\"app_name\">MyMp3Convert</string>\n</resources>"
},
{
"path": "app/src/main/res/values/themes.xml",
"chars": 834,
"preview": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n <!-- Base application theme. -->\n <style name=\"Theme.M"
},
{
"path": "app/src/main/res/values-night/themes.xml",
"chars": 834,
"preview": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n <!-- Base application theme. -->\n <style name=\"Theme.M"
},
{
"path": "app/src/test/java/com/convert/mymp3convert/ExampleUnitTest.java",
"chars": 1226,
"preview": "package com.convert.mymp3convert;\n\nimport org.junit.Test;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static"
},
{
"path": "app/说明 .txt",
"chars": 1852,
"preview": "G:\\e\\work\\test\\MyJniDemo\\app\\src\\main\\java>javac com\\example\\myjnidemo\\LameUtils.java\n\nG:\\e\\work\\test\\MyJniDemo\\app\\src\\"
},
{
"path": "build.gradle",
"chars": 658,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n ex"
},
{
"path": "demo/.gitignore",
"chars": 6,
"preview": "/build"
},
{
"path": "demo/build.gradle",
"chars": 1194,
"preview": "plugins {\n id 'com.android.application'\n}\n\nandroid {\n compileSdkVersion 30\n buildToolsVersion \"30.0.3\"\n\n def"
},
{
"path": "demo/proguard-rules.pro",
"chars": 750,
"preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
},
{
"path": "demo/src/androidTest/java/com/convert/demo/ExampleInstrumentedTest.java",
"chars": 746,
"preview": "package com.convert.demo;\n\nimport android.content.Context;\n\nimport androidx.test.platform.app.InstrumentationRegistry;\ni"
},
{
"path": "demo/src/main/AndroidManifest.xml",
"chars": 720,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "demo/src/main/java/com/convert/demo/MainActivity.java",
"chars": 661,
"preview": "package com.convert.demo;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.os.Bundle;\nimport android.ut"
},
{
"path": "demo/src/main/res/drawable/ic_launcher_background.xml",
"chars": 5606,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "demo/src/main/res/drawable-v24/ic_launcher_foreground.xml",
"chars": 1702,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/aapt\"\n "
},
{
"path": "demo/src/main/res/layout/activity_main.xml",
"chars": 935,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmln"
},
{
"path": "demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
"chars": 272,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <b"
},
{
"path": "demo/src/main/res/values/colors.xml",
"chars": 378,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"purple_200\">#FFBB86FC</color>\n <color name=\"purpl"
},
{
"path": "demo/src/main/res/values/strings.xml",
"chars": 66,
"preview": "<resources>\n <string name=\"app_name\">demo</string>\n</resources>"
},
{
"path": "demo/src/main/res/values/themes.xml",
"chars": 834,
"preview": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n <!-- Base application theme. -->\n <style name=\"Theme.M"
},
{
"path": "demo/src/main/res/values-night/themes.xml",
"chars": 834,
"preview": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n <!-- Base application theme. -->\n <style name=\"Theme.M"
},
{
"path": "demo/src/test/java/com/convert/demo/ExampleUnitTest.java",
"chars": 377,
"preview": "package com.convert.demo;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, wh"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 230,
"preview": "#Thu Jan 14 21:57:53 CST 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 1132,
"preview": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will ov"
},
{
"path": "gradlew",
"chars": 5296,
"preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n## Gradle start up"
},
{
"path": "gradlew.bat",
"chars": 2176,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "settings.gradle",
"chars": 64,
"preview": "include ':demo'\ninclude ':app'\nrootProject.name = \"MyMp3Convert\""
}
]
// ... and 3 more files (download for full content)
About this extraction
This page contains the full source code of the fanyuan/MyMp3Convert GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 100 files (875.2 KB), approximately 278.7k tokens, and a symbol index with 678 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.