android剪切合并MP3音乐,android剪切合并MP3音乐

news/2024/12/22 9:18:25/

以前做过一个音乐播放器,基本的功能都有,什么在线播放,下载,歌词显示,分享等。下面是剪切合并代码,算法也有,结合算法才好看代码

package com.cdu.hhmusic.utils;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.RandomAccessFile;

import java.util.ArrayList;

import java.util.List;

/**

* 使用注意事项

* @作者 胡楠启

* 在android中操作肯定需要操作SD卡的权限的。

*调用顺序:

*1、fenLiData//只要调用了它就会产生中间文件

*2、initMP3Frame

*3、CutingMp3

*4、在调用端,切割完毕后删除中间产生的垃圾文件

*String fenLiData = CutingMp3.fenLiData(str1);

*File file=new File(fenLiData);

*if(file.exists())file.delete();

*原因是在工具端删除中间文件时,这个删除失败。懒得继续画精力去找 ,所以必须在调用端切割完毕后删除,

*一避免垃圾文件占用内存

*/

public class CaoZuoMp3Utils {

/**

* 返回分离出MP3文件中的数据帧的文件路径

*

* @作者 胡楠启

*

*/

public static String fenLiData(String path) throws IOException {

File file = new File(path);// 原文件

File file1 = new File(path + "01");// 分离ID3V2后的文件,这是个中间文件,最后要被删除

File file2 = new File(path + "001");// 分离id3v1后的文件

RandomAccessFile rf = new RandomAccessFile(file, "rw");// 随机读取文件

FileOutputStream fos = new FileOutputStream(file1);

byte ID3[] = new byte[3];

rf.read(ID3);

String ID3str = new String(ID3);

// 分离ID3v2

if (ID3str.equals("ID3")) {

rf.seek(6);

byte[] ID3size = new byte[4];

rf.read(ID3size);

int size1 = (ID3size[0] & 0x7f) << 21;

int size2 = (ID3size[1] & 0x7f) << 14;

int size3 = (ID3size[2] & 0x7f) << 7;

int size4 = (ID3size[3] & 0x7f);

int size = size1 + size2 + size3 + size4 + 10;

rf.seek(size);

int lens = 0;

byte[] bs = new byte[1024*4];

while ((lens = rf.read(bs)) != -1) {

fos.write(bs, 0, lens);

}

fos.close();

rf.close();

} else {// 否则完全复制文件

int lens = 0;

rf.seek(0);

byte[] bs = new byte[1024*4];

while ((lens = rf.read(bs)) != -1) {

fos.write(bs, 0, lens);

}

fos.close();

rf.close();

}

RandomAccessFile raf = new RandomAccessFile(file1, "rw");

byte TAG[] = new byte[3];

raf.seek(raf.length() - 128);

raf.read(TAG);

String tagstr = new String(TAG);

if (tagstr.equals("TAG")) {

FileOutputStream fs = new FileOutputStream(file2);

raf.seek(0);

byte[] bs=new byte[(int)(raf.length()-128)];

raf.read(bs);

fs.write(bs);

raf.close();

fs.close();

} else {// 否则完全复制内容至file2

FileOutputStream fs = new FileOutputStream(file2);

raf.seek(0);

byte[] bs = new byte[1024*4];

int len = 0;

while ((len = raf.read(bs)) != -1) {

fs.write(bs, 0, len);

}

raf.close();

fs.close();

}

if (file1.exists())// 删除中间文件

{

file1.delete();

}

return file2.getAbsolutePath();

}

/**

* 分离出数据帧每一帧的大小并存在list数组里面

*失败则返回空

* @param path

* @return

* @throws IOException

*/

public static List initMP3Frame(String path) {

File file = new File(path);

List list = new ArrayList<>();

/*int framSize=0;

RandomAccessFile rad = new RandomAccessFile(file, "rw");

byte[] head = new byte[4];

rad.seek(framSize);

rad.read(head);

int bitRate = getBitRate((head[2] >> 4) & 0x0f) * 1000;

int sampleRate = getsampleRate((head[2] >> 2) & 0x03);

int paing = (head[2] >> 1) & 0x01;

int len = 144 * bitRate / sampleRate + paing;

for(int i=0,lens=(int)(file.length())/len;i

list.add(len);// 将数据帧的长度添加进来

}*/

int framSize = 0;

RandomAccessFile rad = null;

try {

rad = new RandomAccessFile(file, "rw");

} catch (FileNotFoundException e) {

e.printStackTrace();

}

while (framSize < file.length()) {

byte[] head = new byte[4];

try {

rad.seek(framSize);

} catch (IOException e) {

e.printStackTrace();

}

try {

rad.read(head);

} catch (IOException e) {

e.printStackTrace();

}

int bitRate = getBitRate((head[2] >> 4) & 0x0f) * 1000;

int sampleRate = getsampleRate((head[2] >> 2) & 0x03);

int paing = (head[2] >> 1) & 0x01;

if(bitRate==0||sampleRate==0)return null;

int len = 144 * bitRate / sampleRate + paing;

list.add(len);// 将数据帧的长度添加进来

framSize += len;

}

return list;

}

/**

* 返回切割后的MP3文件的路径 返回null则切割失败 开始时间和结束时间的整数部分都是秒,以秒为单位

*

*

* @param list

* @param startTime

* @param stopTime

* @return

* @throws IOException

*/

public static String CutingMp3(String path, String name,

List list, double startTime, double stopTime)

throws IOException {

File file = new File(path);

String luJing="/storage/emulated/0/"+"HH音乐播放器/切割/";

File f=new File(luJing);

f.mkdirs();

int start = (int) (startTime / 0.026);

int stop = (int) (stopTime / 0.026);

if ((start > stop) || (start < 0) || (stop < 0) || (stop > list.size())) {

return null;

} else {

long seekStart = 0;// 开始剪切的字节的位置

for (int i = 0; i < start; i++) {

seekStart += list.get(i);

}

long seekStop = 0;// 结束剪切的的字节的位置

for (int i = 0; i < stop; i++) {

seekStop += list.get(i);

}

RandomAccessFile raf = new RandomAccessFile(file, "rw");

raf.seek(seekStart);

File file1 = new File(luJing + name + "(HH切割).mp3");

FileOutputStream out = new FileOutputStream(file1);

byte[] bs=new byte[(int)(seekStop-seekStart)];

raf.read(bs);

out.write(bs);

raf.close();

out.close();

File filed=new File(path);

if(filed.exists())

filed.delete();

return file1.getAbsolutePath();

}

}

private static int getBitRate(int i) {

int a[] = {0,32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224,

256, 320,0 };

return a[i];

}

private static int getsampleRate(int i) {

int a[] = { 44100, 48000, 32000,0 };

return a[i];

}

/**

* 返回合并后的文件的路径名,默认放在第一个文件的目录下

* @param path

* @param path1

* @param name

* @return

* @throws IOException

*/

public static String heBingMp3(String path,String path1,String name) throws IOException{

String fenLiData = fenLiData(path);

String fenLiData2 = fenLiData(path1);

File file=new File(fenLiData);

File file1=new File(fenLiData2);

String luJing="/storage/emulated/0/"+"HH音乐播放器/合并/";

File f=new File(luJing);

f.mkdirs();

//生成处理后的文件

File file2=new File(luJing+name+"(HH合并).mp3");

FileInputStream in=new FileInputStream(file);

FileOutputStream out=new FileOutputStream(file2);

byte bs[]=new byte[1024*4];

int len=0;

//先读第一个

while((len=in.read(bs))!=-1){

out.write(bs,0,len);

}

in.close();

out.close();

//再读第二个

in=new FileInputStream(file1);

out=new FileOutputStream(file2,true);//在文件尾打开输出流

len=0;

byte bs1[]=new byte[1024*4];

while((len=in.read(bs1))!=-1){

out.write(bs1,0,len);

}

in.close();

out.close();

if(file.exists())file.delete();

if(file1.exists())file1.delete();

return file2.getAbsolutePath();

}

} 作用就是可以剪切合并音乐,各种路劲需要根据实际情况修改。

用法:剪切

String fenLiData = CaoZuoMp3Utils.fenLiData(str);

final List list = CaoZuoMp3Utils.initMP3Frame

(fenLiData);

if(list==null){

han.post(new Runnable() {

@Override

public void run() {

Toast.makeText(Cut_Mp3_Activity.this, "剪切失败",

Toast.LENGTH_SHORT).show();

prodiialog.dismiss();

}

});

}else{

final String path = CaoZuoMp3Utils.CutingMp3(fenLiData, cuting_name,

list,

start, stop);

final File file = new File(fenLiData);

合并:

final String s = CaoZuoMp3Utils.heBingMp3(path, path1, name);

因为是耗时操作所以需要放在线程中进行。


http://www.ppmy.cn/news/292889.html

相关文章

mp3cutter java_开源一款超级好用的mp3剪切器app

功能上虽然简洁&#xff0c;但是技术上该项目“麻雀虽小&#xff0c;五脏俱全”。 下面从技术层面上做一些简单介绍&#xff1a; 首页使用了CoordinatorLayoutAppBarLayoutDrawerLayoutNavigationView的经典MD设计风格。 项目整体采用了MVPdatabindingrxjava2rxandroid2dagger2…

喜报!恭喜知了堂学员成功通过CISP-PTE证书考试

有人说&#xff0c;大学可以不谈恋爱&#xff0c;但一定要考证。 考证&#xff0c;是大学校园生活的关键一环。充分利用在校时间为后期就业提前储备优势&#xff0c;毕业后如果从事IT领域&#xff0c;证书就是一个高含金量的专业认证&#xff0c;尤其是网络安全行业&#xff0…

MCP1501基准电源系列输出电容为什么不能超过300P

1 介绍 在我们通常理解中基准的输出电容需要在100nF以上&#xff0c;才能有较好的性能输出&#xff0c;为什么MCP1501系列官方推荐输出负载电容不能超过300P呢 2 原理分析 如下是MCP1501手册中标注的&#xff0c;最大负载电容不能超过300pF&#xff0c;超过300pF容易振荡 MC…

6.9 条件变量的使用及注意事项

目录 条件变量 使用步骤&#xff1a; 初始化&#xff1a; 生产资源线程&#xff1a; 开始产生资源 消费者线程&#xff1a; 条件变量 应用场景&#xff1a;生产者消费者问题&#xff0c;是线程同步的一种手段。 必要性&#xff1a;为了实现等待某个资源&#xff0c;让线…

Vue.js 中的 v-for 中的 key 属性

Vue.js 中的 v-for 中的 key 属性 Vue.js 是一个流行的 JavaScript 前端框架&#xff0c;它提供了一种简单的方式来构建可复用的组件和应用程序。在 Vue.js 中&#xff0c;v-for 指令用于循环渲染一个数组或对象&#xff0c;并将每个元素渲染为一个 DOM 元素。在使用 v-for 指…

【无标题】2024年、2025年毕业五年制专转本辅导班招生简章

2024年、2025年毕业五年制专转本辅导班招生简章 要不要上课外班&#xff1f;选择什么样的课外班&#xff1f;如何选择一个合适的课外班&#xff1f;一个最为基本的思考立足点是课外班应该满足你孩子的需求。 这里面有两个意思&#xff0c;一个是不要因为别人孩子上课外班&…

【算法与数据结构】206、LeetCode 反转链表

文章目录 一、题目二、翻转链表双指针法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、翻转链表双指针法 思路分析&#xff1a;代码首先进行头结点合法性判断&#xff0c;如果是空链表或者仅有一个节点的链…

.msi文件安装报错

.msi文件安装报错一般是因为安装权限不够&#xff0c;但右键.msi文件没有以管理员权限运行&#xff0c;所以需要用命令提示符来操作。 打开命令提示符管理员——H:\工具软件\iplat>msiexec /package "OPC Core Components 2.00 SDK 2.20.msi" 命令格式为msiexec /…