功能上虽然简洁,但是技术上该项目“麻雀虽小,五脏俱全”。

下面从技术层面上做一些简单介绍:

首页使用了CoordinatorLayout+AppBarLayout+DrawerLayout+NavigationView的经典MD设计风格。

项目整体采用了MVP+databinding+rxjava2+rxandroid2+dagger2框架设计,数据缓存使用了greendao。

音频频谱的绘制主要是通过Visualizer中获取到的波形数据来进行绘制。

剪切功能上,mp3剪切核心功能使用了jaudiotagger jar包获取mp3元数据获取字节位置并进行文件io操作生成目标文件。此功能作为重点,本文后续会做详细的说明。

动画方面,欢迎页使用了lottie动画,如感兴趣可以看这篇博客做了详尽的步骤介绍,制作lottie动画并应用到android项目(https://juejin.im/post/5a355cf5f265da433227a53d)。 项目中文件选择页以及关于页面使用了属性动画和属性动画组件AVLoadingIndicatorView(https://github.com/81813780/AVLoadingIndicatorView)。

自定义控件,范围选取控件CustomRangeSeekBar(https://github.com/zyl409214686/CustomRangeSeekBar),不是本文重点可以看之前的博文android 自定义范围选取控件CustomRangeSeekBar(https://www.jianshu.com/p/712c13584636)。

首页使用了CoordinatorLayout+AppBarLayout+DrawerLayout+NavigationView的经典MD设计风格。

项目整体采用了MVP+databinding+rxjava2+rxandroid2+dagger2框架设计,数据缓存使用了greendao。

音频频谱的绘制主要是通过Visualizer中获取到的波形数据来进行绘制。

剪切功能上,mp3剪切核心功能使用了jaudiotagger jar包获取mp3元数据获取字节位置并进行文件io操作生成目标文件。此功能作为重点,本文后续会做详细的说明。

动画方面,欢迎页使用了lottie动画,如感兴趣可以看这篇博客做了详尽的步骤介绍,制作lottie动画并应用到android项目(https://juejin.im/post/5a355cf5f265da433227a53d)。 项目中文件选择页以及关于页面使用了属性动画和属性动画组件AVLoadingIndicatorView(https://github.com/81813780/AVLoadingIndicatorView)。

自定义控件,范围选取控件CustomRangeSeekBar(https://github.com/zyl409214686/CustomRangeSeekBar),不是本文重点可以看之前的博文android 自定义范围选取控件CustomRangeSeekBar(https://www.jianshu.com/p/712c13584636)。

2

使用说明+gif

Step1. 选择mp3文件

Step2. 通过滑块选择剪切范围然后点击剪切按钮

Tips:主界面上可以看到三个按钮,从左到右的功能分别为:

播放暂停

切换播放的滑块(切换当前播放的位置,前滑块or后滑块)

音乐剪切

播放暂停

切换播放的滑块(切换当前播放的位置,前滑块or后滑块)

音乐剪切

mp3剪切实现思想

实现思想主要有两点

获取mp3开始时间(要剪切的开始时间)所在的文件字节位置及结束时间所在文件的字节位置

根据开始时间的字节位置和结束时间的字节位置结合源文件生成我们的目标文件

获取mp3开始时间(要剪切的开始时间)所在的文件字节位置及结束时间所在文件的字节位置

根据开始时间的字节位置和结束时间的字节位置结合源文件生成我们的目标文件

3

mp3剪切技术实现

那么如何来获取mp3开始时间所在文件的字节位置呢? 这里用到了jaudiotagger.jar。

http://www.jthink.net/jaudiotagger/

http://www.jthink.net/jaudiotagger/

它的主页是这样描述它的

Jaudiotagger is a Java API for audio metatagging. Both a common API and format specific APIs are available, currently supports reading and writing metadata for:Mp3、Flac、OggVorbis、Mp4、Aiff、Wav、Wma、Dsf

Jaudiotagger is a Java API for audio metatagging. Both a common API and format specific APIs are available, currently supports reading and writing metadata for:Mp3、Flac、OggVorbis、Mp4、Aiff、Wav、Wma、Dsf

它是一个音频元标记的java库,可以支持mp3等特定格式进行读写元数据操作。

mp3剪切实现细节:

一、我们要做的事通过Jaudiotagger获取到mp3的元数据,通过元数据取到mp3的首帧字节位置以及比特率。然后根据首帧字节位置以及比特率和开始时间可以其对应文件的字节位置。最后得到开始字节位置和结束字节位置。

1.获取mp3元数据

MP3Filemp3 = new MP3File( this.mp3File);

//获取mp3的元数据

MP3AudioHeaderheader = ( MP3AudioHeader) mp3.getAudioHeader();

2. 根据元数据获取mp3比特率

//根据元数据获取比特率

longbitRateKbps = header.getBitRateAsNumber();

可能你会问,什么是比特率?

比特率是每秒传输的比特(bit)数

比特率是每秒传输的比特(bit)数

来看我们取mp3比特率的方法看注释

long bitRate = header.getBitRateAsNumber();看该方法源码注释如下:

/**

*

* @ returnbitrate inkbps, no indicator isprovided asto

* whether ornotit isvbr

*/

public long getBitRateAsNumber()

{

returnbitrate;

}

通过注释得知,此方法返回的比特率单位为kbps(每秒千字节) ,而我们需要的比特率的单位是(每毫秒位),下一步进行单位转换计算。

3. 转换比特率

这里我们需要换算它为每毫秒位数,1字节是8位,1秒是1000毫秒,千字节是1024字节,那么转换后算到的也就是getBitRateAsNumber() *1024L / 8L / 1000L。代码如下:

//计算出开始字节位置

longbitRatebpm = bitRateKbps * 1024L/ 8L/ 1000L* beginTime;

4.计算开始字节

这个值就是开始时间所在文件的字节位置吗?当然不是,我们的mp3文件当中并不只包含音乐的数据,还包含有音乐的信息头数据。

同样我们可以从头信息中取到我们的mp3首帧字节位置。首帧字节位置+每毫秒位为单位比特率,就是我们要的mp3开始字节位置了。

代码如下:

longfirstFrameByte = header.getMp3StartByte();

longbeginByte = firstFrameByte + beginBitRateBpm;

5. 计算结束字节位置

同理, 利用上面计算出来的开始字节beginType+时间差(剪切结束时间-开始时间)的比特率(单位为每毫秒位)就可以计算出结束的字节位置了,代码入下:

//计算出结束字节位置

longendByte = beginByte + convertKbpsToBpm(bitRateKbps) * (endTime - beginTime);

long endIndex(截取结束字节位置) = beginIndex(截取开始字节位置) + bitRate *1024L / 8L / 1000L(比特率每毫秒位) * (endTime - beginTime)(截取的时长毫秒单位);

二、 有了开始时间的字节位置和结束时间的字节位置,那我们就可以结合源文件生成我们的目标文件拉。

读写文件我们可以使用RandomAccessFile实现随机的读写操作,通过RandomAccessFile.seek()方法调到指定位置。

问题&解决方案

如果我们要操作的mp3文件很大,比如我们截取的字节大小为100MB,这时候我们的app就会因为OOM直接crash掉了。

这里我的解决方案是通过一个缓存数组来限制每次读写的数据大小,每次操作指定大小的数据,这样无论文件多大,我们都不会出现OOM问题啦。

1.首先我们写一个工具方法,以缓存的方式来生成目标文件,源文件读取指定大小的数据读取写入到目标文件,代码如下:

/**

* @paramtargetFile 输出的文件

* @paramsourceFile 读取的文件

* @parambuffer 输入输出的缓存容器

* @paramoffset 读入文件时seek的偏移值

*/

privatestaticvoidwriteSourceToTargetFile(RandomAccessFile targetFile,

RandomAccessFile sourceFile,

bytebuffer[], longoffset)throwsException {

sourceFile.seek(offset);

sourceFile.read(buffer);

longfileLength = targetFile.length();

// 将写文件指针移到文件尾。

targetFile.seek(fileLength);

targetFile.write(buffer);

}

2. 需要根据需要剪切文件的字节大小,分别考虑小于缓存以及大于等于缓存的情况,分别进行操作。

代码如下:

privatestaticvoidwriteSourceToTargetFileWithBuffer(

RandomAccessFile targetFile,

RandomAccessFile sourceFile,

longtotalSize,

longoffset)throwsException {

//缓存大小,每次写入指定数据防止内存泄漏

intbuffersize = BUFFER_SIZE;

longcount = totalSize / buffersize;

if(count <= 1) {

//文件总长度小于小于缓存大小情况

writeSourceToTargetFile(targetFile, sourceFile, newbyte[( int) totalSize], offset);

} else{

//计算出整除后剩余的数据数

longremainSize = totalSize % buffersize;

bytedata[] = newbyte[buffersize];

//读入文件时seek的偏移量

for( inti = 0; i < count; i++) {

writeSourceToTargetFile(targetFile, sourceFile, data, offset);

offset += BUFFER_SIZE;

}

//写入剩余数据

if(remainSize > 0) {

writeSourceToTargetFile(targetFile, sourceFile, newbyte[( int) remainSize], offset);

}

}

}

3. 最后要考虑不但要讲mp3乐音帧相关数据写入, 还要讲头信息写入进去,代码如下:

/**

* 生成目标mp3文件

*

* @paramtargetFile

* @parambeginByte

* @paramendByte

* @paramfirstFrameByte

* @throwsException

*/

privatevoidgenerateTargetMp3File(RandomAccessFile targetFile,

longbeginByte, longendByte, longfirstFrameByte)throwsException {

RandomAccessFile sourceFile = newRandomAccessFile(mSourceMp3File, "rw");

try{

//write mp3 header info

writeSourceToTargetFileWithBuffer(targetFile, sourceFile, firstFrameByte, 0);

//write mp3 frame info

intsize = ( int) (endByte - beginByte);

writeSourceToTargetFileWithBuffer(targetFile, sourceFile, size, beginByte);

} catch(Exception e) {

e.printStackTrace();

} finally{

if(sourceFile != null)

sourceFile.close();

}

}

到这里就结束啦,能力有限,写的不对好的地方,请多提意见。

项目计划讲一直进行维护升级,谢谢您的关注!!!

https://github.com/zyl409214686/Mp3Cutter

https://github.com/zyl409214686/Mp3Cutter

github APK下载

https://github.com/zyl409214686/Mp3Cutter/blob/master/apk/app-cutter-release.apk

蒲公英 APK下载

https://www.pgyer.com/mp3cutter

github APK下载

https://github.com/zyl409214686/Mp3Cutter/blob/master/apk/app-cutter-release.apk

蒲公英 APK下载

https://www.pgyer.com/mp3cutter

单元测试

如果没有手机或其他原因不方便使用app。项目中提供了单元测试和mp3文件,可以通过单元测试来体验mp3剪切功能。

laozi.mp3是源mp3

test.mp3是运行完单元测试,生成的mp3文件。

startTime、endTime为剪切的开始时间及结束时间

laozi.mp3是源mp3

test.mp3是运行完单元测试,生成的mp3文件。

startTime、endTime为剪切的开始时间及结束时间

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

  1. 开源一款超级好用的mp3剪切器app

    本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. app&技术介绍 该app使用了MD规范,界面风格简洁,功能上mp3剪切铃声制作,实用性比较强. 功能上 ...

  2. 推荐一款超级好用的开源画图工具:用例图、架构图、时序图、类图、E-R图、甘特图

    在项目开发的过程中需要各种类型的图来进行支撑,比如用例图.系统架构图.时序图.类图.E-R图,甚至项目管理的甘特图等等.为了画这些图我们往往需要寻找各类付费.免费的软件进行操作. 今天给大家推荐一款开 ...

  3. python七大神级插件_IntelliJ IDEA 15款超级牛逼插件推荐(自用,超级牛逼)

    满满的都是干货  所有插件都是在 ctrl+alt+s   里的plugins 里进行搜索安装 1.CodeGlance 代码迷你缩放图插件 2. Codota 代码提示工具,扫描你的代码后,根据你的 ...

  4. 强势分享5款超级实用的办公软件,建议收藏!

    !!!!!实用预警!!!!!! 小智整理了5款超级好用的办公软件,可以提高你的办公效率,直接上干货! 1.Cencrack在线工具箱 Cencrack是一个非常强大的工具箱软件,里面有大量实用的工具, ...

  5. 软件:9款超级实用的办公软件,值得收藏!

    今天给大家分享9款超级实用的办公软件,值得收藏! 一.Quicker 作为全网好评的这款国产软件,可以秒杀很多办公软件.打开它的首页就能看到很多常用的工具,包括截图.快搜.百度翻译.OCR文字识别.o ...

  6. 4 款超级好用的终端文件管理器

    作为 Linux 操作系统的必备工具,选择一款非常好用的终端文件管理器,能让日常使用更加提高效率. 今天跟大家推荐几款适用于 Linux 的开源文件管理器,希望对大家有所帮助. 1.nnn nnn(或 ...

  7. 微软欲模仿“微信”,打造一款超级 App?

    「Write Once,Run Anywhere」是很多开发者的梦想,而对于不少开发商而言,他们更希望能够打造一套系统或服务走天下. 近日,据外媒 The Information 报道,微软或正在构建 ...

  8. 百度2020年开源总结:超级链与Apollo、飞桨等成行业领先者

    "从 2009 年大规模定制 Hadoop 到 2013 年第一个前端可视化产品 ECharts率先开源,再到2016年.2017年.2019年分别正式对外开源飞桨.Apollo.超级链. ...

  9. ftp 客户端,9款超级好用而且免费的ftp 客户端,你值得拥有

    说到ftp客户端,我首先想到的就是上传下载,很多人都是用来做这个,但是也有很多人都不知道它是干什么的,其实ftp客户端一般是从事网站工作者使用的.平常使用的人不是很多,像小编就是,等到真正要使用的时候 ...

  10. 四款超级好用的终端文件管理器,提高你的使用效率!

    作为 Linux 操作系统的必备工具,选择一款非常好用的终端文件管理器,能让日常使用更加提高效率. 今天跟大家推荐几款适用于 Linux 的开源文件管理器,希望对大家有所帮助. 1.nnn 图片 nn ...

最新文章

  1. Cenetos 下sudo的使用
  2. 解析TOMCAT框架 .
  3. 《研磨设计模式》chap2 简单工厂simplefactory
  4. 计算机专业c语言题库,计算机专业C语言考试题.doc
  5. 偷懒大法好,用 selenium 做 web 端自动化测试
  6. C语言string.h文件函数汇总详解
  7. html页面包含头文件,Web前端技术:HTML部分---Head标签中包含的头文件标签,body标签包含的内部标签...
  8. 计算机视觉基础---图像处理(几何变换)cpp+python
  9. 数据结构开发(5):线性表的链式存储结构
  10. POJ - 1458(最长公共子序列,动态规划)
  11. 第三章 图表辅助元素的定制
  12. Android 仿百合网超火爆社交app首页滑动效果
  13. Python爬虫实训案例之爬取豆瓣电影Top250并保存至excel
  14. 弹性裸金属服务器EBM
  15. OpenGL学习二十九:模板缓冲区与模板测试
  16. html 定义列表dddt,TDDD 文件扩展名: 它是什么以及如何打开它?
  17. [经济杂谈]经济危机的真相
  18. onMeasure()和onSizeChanged()
  19. 全国计算机vf题库,全国计算机等级VF机试题库.pdf
  20. C# DllImport 系统调用使用详解 托管代码的介绍 EntryPoint的使用

热门文章

  1. 【InSAR 笔记2】哨兵一号精轨数据批量下载【修改0704】
  2. 计算机脚本模板,mv分镜头脚本范文mv的分镜头脚本格式.doc
  3. vue从零搭建一个前中后台权限管理模板
  4. 饥荒专用服务器全图显示代码,饥荒地图怎么看 饥荒地图全开代码
  5. kettle Call From LAPTOP-14BPR3NI/192.168.1.2 to locahost:8020 failed on connection
  6. 共享鸡皮疙瘩?庆应大学开发了一种贴身设备,利用腕带和颈带数据,分享刺激感受...
  7. 油菜的做法及营养知识详细介绍
  8. 不要再重复造轮子了,Hutool 这款开源工具类库贼好使
  9. PHP Failed opening required
  10. 基于单片机原理的暖风机控制系统设计-毕设课设资料