1、介绍

总览

音频编辑服务(Audio Editor Kit)是帮助开发者快速构建各类应用音频能力的服务。在本codelab中,您将学会创建一个Demo Project,了解如何使用音频编辑服务实现音源分离、合成分离的音频源的功能。

您将建立什么

在本codelab中,您将构建APP实现编辑并从音乐中删除音频。

您将学会什么

在本codelab中,你需要学习:

1、从视频中提取音源。

2、实现音源分离,提取乐器声音。

3、合成音频。

4、导出音频文件

2、您需要什么

硬件需求

  • 安装了Android Studio并已连接到互联网的计算机。

  • 华为或安卓手机(带USB线)。

  • 手机用于运行和调试demo

软件需求

  • JDK版本:1.8.211或以上

  • Android(API版本21或以上)

  • HMS Core (APK) 6.0.0.300或以上

  • Android Studio版本:3.6.1或以上

  • 华为手机:EMUI 5.0版本或以上;非华为手机:Android 5.0或以上。

3、集成前准备

如果您需要正式发布集成音频编辑服务的APP,请参考HUAWEI HMS Core集成准备章节,为集成做好准备。本代codelab提供的示例代码已完成为您准备的工作。如果使用示例代码,则可以跳过此步骤。

在准备集成HUAWEI HMS Core之前,您需要先注册开发者帐号并完成实名认证。详细信息,请参考注册认证

4、开发Demo应用

在本节中,您将构建一个Demo,以了解如何将视频转换为音频文件,并使用音频编辑服务分离其音频源。

新建工程

1)创建一个Android项目,将FileUtils.ktPermissionUtil.kt文件拷贝到“src\main\java\com\example\myapplication\util”目录下。

2)创建包和类,如下所示。

cke_8908.png

说明:将“FileUtils.kt”和“PermissionUtil.kt”复制到您的项目后,请检查文件中指定的包名是否与您的项目包名相同。如果不同,请将其更改为您的项目包名称。

3)将res目录下的所有资源文件复制到项目的“src\main\res”目录下。

cke_10060.png

说明:xml是一个新的空目录。

配置HMS Core SDK的Maven仓地址

Android Studio的代码库配置在Gradle插件7.0以下版本、7.0版本和7.1及以上版本有所不同。请根据您当前的Gradle插件版本,选择对应的配置过程。

说明:Maven仓地址无法直接在浏览器中打开访问,只能在IDE中配置。如需添加多个Maven代码库,请将华为公司的Maven仓地址配置在最后。

1)7.0以下版本

a.打开Android Studio项目级“build.gradle”文件。

cke_13219.png

b.添加HUAWEI AGC插件以及Maven代码库。

①在“buildscript > repositories”中配置HMS Core SDK的Maven仓地址。

②在“allprojects > repositories”中配置HMS Core SDK的Maven仓地址。

③如果App中添加了“agconnect-services.json”文件则需要在“buildscript > dependencies”中增加AGC插件配置。

buildscript {  
      repositories {  
          google()  
          jcenter()  
          // Configure the Maven repository address for the HMS Core SDK.  
          maven {url 'https://developer.huawei.com/repo/'}  
      }  
      dependencies {  
          ...  
          // Add the AppGallery Connect plugin configuration. Please refer to AppGallery Connect Plugin Dependency to select a proper plugin version.   
          classpath 'com.huawei.agconnect:agcp:1.6.0.300'  
      }  
  }    
  allprojects {  
      repositories {  
          google()  
          jcenter()  
          // Configure the Maven repository address for the HMS Core SDK.  
          maven {url 'https://developer.huawei.com/repo/'}  
      }  
  } 

2)7.0版本

a.打开Android Studio项目级“build.gradle”文件。

cke_18161.png

b.添加HUAWEI AGC插件以及Maven代码库。

①在“buildscript > repositories”中配置HMS Core SDK的Maven仓地址。

②如果App中添加了“agconnect-services.json”文件则需要在“buildscript > dependencies”中增加AGC插件和Android Gradle插件配置。

buildscript {  
      repositories {  
          google()  
          jcenter()  
          // Configure the Maven repository address for the HMS Core SDK.  
          maven {url 'https://developer.huawei.com/repo/'}  
      }  
      dependencies {  
          ...  
          // Add the Android Gradle plugin configuration. You need to replace {version} with the actual Gradle plugin version, for example, 7.0.1.  
          classpath 'com.android.tools.build:gradle:{version}'  
          // Add the AppGallery Connect plugin configuration. Please refer to AppGallery Connect Plugin Dependency to select a proper plugin version.   
          classpath 'com.huawei.agconnect:agcp:1.6.0.300'  
      }  
  }

c.打开项目级“settings.gradle”文件,配置HMS Core SDK的Maven仓地址。

dependencyResolutionManagement {  
      ...  
      repositories {  
          google()  
          jcenter()   
          // Configure the Maven repository address for the HMS Core SDK.  
          maven {url 'https://developer.huawei.com/repo/'}  
      }  
  }

3)7.1及以上版本

a.打开Android Studio项目级“build.gradle”文件。

cke_26631.png

b.如果App中添加了“agconnect-services.json”文件则需要在“buildscript > dependencies”中增加AGC插件和Android Gradle插件配置。

buildscript {  
      dependencies {  
          ...  
          // Add the Android Gradle plugin configuration. You need to replace {version} with the actual Gradle plugin version, for example, 7.1.1.  
          classpath 'com.android.tools.build:gradle:{version}'  
          // Add the AppGallery Connect plugin configuration. Please refer to AppGallery Connect Plugin Dependency to select a proper plugin version.   
          classpath 'com.huawei.agconnect:agcp:1.6.0.300'  
      }  
  }

c.打开项目级“settings.gradle”文件,配置HMS Core SDK的Maven仓地址。

pluginManagement {  
      repositories {  
          gradlePluginPortal()  
          google()  添加编译依赖
          mavenCentral()  
          // Configure the Maven repository address for the HMS Core SDK.  
          maven { url 'https://developer.huawei.com/repo/' }  
      }  
  }  
  dependencyResolutionManagement {  
      ...  
      repositories {  
          google()  
          mavenCentral()  
          // Configure the Maven repository address for the HMS Core SDK.  
          maven { url 'https://developer.huawei.com/repo/' }  
      }  
  }

添加编译依赖

1)打开应用级的“build.gradle”文件。

cke_39824.png

2)添加Java版本配置。

compileOptions {  
      sourceCompatibility JavaVersion.VERSION_1_8  
      targetCompatibility JavaVersion.VERSION_1_8 
   }

3)在dependencies代码段中添加如下编译依赖。

dependencies {  
      implementation 'com.huawei.hms:audio-editor-sdk:1.5.0.301' 
   }

说明:如果需要添加其他依赖,请按照上述格式将其添加到依赖块中。

示例

cke_54004.png

cke_57772.png

cke_77522.png

说明:

  • 将{version}替换为实际的SDK版本号,例如:1.5.0.301。具体操作请参见版本变更记录

  • minSdkVersion:21或以上

  • 将“API Key”添加到“buildTypes”中。“API Key”可以在“appgallery_connect.json”文件中找到。

配置AndroidManifest.xml文件

Nearby Connection开发前,需要添加特定的权限到“AndroidManifest.xml”。

cke_95746.png

权限添加位置与标签“application”同级。示例代码如下:

<!-- Vibrate --> 
<uses-permission android:name="android.permission.VIBRATE" /> 
<!-- Microphone --> 
<uses-permission android:name="android.permission.RECORD_AUDIO" /> 
<!-- Write into storage --> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<!-- Read from storage --> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
<!-- Connect to Internet --> 
<uses-permission android:name="android.permission.INTERNET" /> 
<!-- Obtain the network status --> 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
<!-- Obtain the changed network connectivity state --> 
 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
  • ACCESS_FINE_LOCATION、WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE是危险的系统权限。您需要通过本项目提供的PermissionUtil类的launchMultiplePermission,在“HomeActivity”中动态申请这些权限。如果权限不足,音频编辑服务将会由于缺少必需权限无法开启广播或者扫描。

  • Android 10及以上版本的设备默认只允许应用访问外部存储的私有目录。如果您尝试访问外部存储的其他目录,将抛出异常FileNotFoundException。因此,您需要在“AndroidManifest.xml”文件中的“application”元素下面设置“requestLegacyExternalStorage="true"”。示例代码如下:

cke_136456.png

同步工程

点击“File > Sync Project with Gradle Files”同步工程。

cke_142801.png

如果显示“successful”,则表示同步成功,如下图所示。

cke_147201.png

音频提取-视频到音频

现在我们可以开始集成音频提取了。函数“extractAudio”可以从获取HAEAudioExpansion实例调用,如下所示。此函数采用5个参数:上下文(context)、视频源路径(videoPath)、输出路径(exportPath)、提取音频文件的名称(txtVideoName)和音频提取回调结果(AudioExtractCallBack),帮助您跟踪提取过程的进度与提取步骤。

binding.imgVideoEdit.setOnClickListener {     val intent = Intent() 
     intent.type = "video/*" 
     intent.action = Intent.ACTION_GET_CONTENT 
     startActivityForResult( 
         Intent.createChooser(intent, "Select Video"), 
         REQUEST_TAKE_GALLERY_VIDEO 
     ) 
 }
binding.btnExtraction.setOnClickListener { 
     exportPath = File( 
         Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) 
             .toString() + File.separator + "SeparateAudioCodelab" + File.separator 
     ) 
     if(!exportPath.exists()) exportPath.mkdir() 
     if(videoPath!=""){ 
         HAEAudioExpansion.getInstance().extractAudio( 
             context, 
             videoPath, 
             exportPath.toString(), 
             binding.txtVideoName.text.toString(), 
             object : AudioExtractCallBack { 
                 override fun onSuccess(audioPath: String) { 
                     showDialog() 
                 } 
 
                 override fun onProgress(progress: Int) { 
                     //Runs on progress 
                 } 
 
                 override fun onFail(errCode: Int) { 
                     if(errCode==1006){ 
                         Toast.makeText(context,"File already exist",Toast.LENGTH_LONG).show() 
                     } 
                 } 
 
                 override fun onCancel() { 
                     //Runs on when process canceled 
                 } 
             }) } 
 }

提取完成后,我们可以在分离页面上使用提取的音频文件分离其音频源。

音源分离

提取后,用户将被导航到分离页面。在此页面上,有一个可以与音频文件分离的源列表,我们将从“HAEAudioSeparationFile”实例中收集源列表。在这个过程中,所有源或其中的少数源都可以分离。“HAEAudioSeparationFile”采用一个源列表来设置分离哪些音频源,分离过程有4个参数:音频路径(filePath)、导出路径(folderPath)、创建的文件名(fileName)和分离结果回调(AudioSeparationCallBack)。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 
     super.onViewCreated(view, savedInstanceState) 
     haeAudioSeparationFile = HAEAudioSeparationFile()
private fun getInstruments() { 
     haeAudioSeparationFile.getInstruments(object : 
         SeparationCloudCallBack<List<SeparationBean?>?> { 
         override fun onFinish(response: List<SeparationBean>) { 
             for (separationBean in response) { 
                 instruments.add(Instrument(separationBean.instrument, separationBean.desc,"")) 
             } 
             rvAdapter.setItems(instruments) 
         } 
 
         override fun onError(errorCode: Int) { 
             //Runs when when error occurred 
         } 
     }) 
 }
private fun separateAudio() { 
     haeAudioSeparationFile.setInstruments(selectedInstruments.map { it.name }) 
     binding.layoutSeparationFragment.visibility = View.VISIBLE 
     binding.layoutSeparationFragment.bringToFront() 
     val instrumentsToCompose = arrayListOf<Instrument>() 
     var doneTaskCount = 0 
     binding.txtSeparationProcess.text = "${doneTaskCount}/${selectedInstruments.size}" 
 
     haeAudioSeparationFile.startSeparationTasks( 
         filePath, 
         folderPath, 
         fileName, 
         object : AudioSeparationCallBack { 
             override fun onResult(separationBean: SeparationBean) { 
                 activity?.runOnUiThread { 
                     binding.txtSeparationProcess.text = 
                         "${++doneTaskCount}/${selectedInstruments.size}" 
                 } 
                 separationBean.apply { instrumentsToCompose.add(Instrument(this.instrument,this.desc,this.outAudioPath)) } 
             } 
 
             override fun onFinish(separationBeans: List<SeparationBean>) { 
                 activity?.runOnUiThread { 
                     binding.layoutSeparationFragment.visibility = View.GONE 
                     binding.btnSeparate.isClickable = true 
                     val action = SeparationFragmentDirections.actionSeparationFragmentToComposeFragment(instrumentsToCompose.toList().toTypedArray(),folderPath) 
                     findNavController().navigate(action) 
                 } 
             } 
 
             override fun onFail(errorCode: Int) { 
                 //Runs when process failed 
             } 
             override fun onCancel() { 
                 //Runs when process canceled 
             } 
         }) 
  }

分离过程可能需要几分钟。在这个过程之后,我们可以导航到第三个页面,即编辑页面。

合成音频文件

此页面设计类似于分离页面。但是包含音频源的列表只包含上一页上的分离源。用户可以选择这些源,并将它们合成到新的音频文件中。要合成这些音频文件,我们需要一个

“HuaweiAudioEditor”实例。我们将使用“appendAudioAsset”函数将所有要合成的路径添加到此实例中。要创建最终文件,我们需要使用音频编辑器服务的导出音频功能。

fileName = binding.txtComposeName.text.toString() 
val mEditor = HuaweiAudioEditor.create(context) 
 mEditor.initEnvironment() 
val mTimeLine = mEditor.timeLine 
for(instrument in selectedInstruments){ 
     mTimeLine.appendAudioLane().appendAudioAsset(instrument.filePath,mTimeLine.currentTime) 
 } 
val path = exportPath+ File.separator+ fileName + ".mp3" 
val exportAudioCallback: ExportAudioCallback = object : ExportAudioCallback { 
     override fun onCompileProgress(time: Long, duration: Long) { 
         //Runs on progress 
     } 
     override fun onCompileFinished() { 
         activity?.runOnUiThread{
             binding.processCompose.visibility = View.INVISIBLE 
binding.txtSelectInstruments.text = getString(R.string.select_instruments) 
             Toast.makeText(context,"DONE",Toast.LENGTH_LONG) 
         } 
     } 
     override fun onCompileFailed(errCode: Int, errorMsg: String) { 
         //Runs when process failed 
     } 
 }
HuaweiAudioEditor.getInstance().setExportAudioCallback(exportAudioCallback) 
val audioProperty = HAEAudioProperty() 
 audioProperty.encodeFormat = Constants.AV_CODEC_ID_MP3 
 audioProperty.sampleRate = Constants.SAMPLE_RATE_44100 
 audioProperty.channels = 2  HuaweiAudioEditor.getInstance().exportAudio(audioProperty, path) 

5、测试Demo

完成上述步骤后,编译演示。

演示构建完成后,会生成APK文件。安装在华为手机上,调试并运行。

a.初始屏幕

cke_173878.png

以上是在手机上运行的APP的截图。

APP提供以下两个按钮:

1)提取音频:打开文件选择器,选择要提取的视频。

2)分离音频:引导到页面,将音频源与文件分离。

b.音频提取

选择要提取的视频后

cke_187706.png

1)点击提取音频。

2)提取完成后,将出现分离页。

c.音源分离

cke_202256.png

1)选择要与音频文件分离的乐器。

2)点击分离音频,以启动音源分类离过程。

d.音频源合成

cke_213635.png

1)选择要作曲的乐器。

2)点击合成声音,以启动合成过程。

6、恭喜您

祝贺您,您已经成功完成本codelab并学到了:

  • 构建Demo App,并将HMS Core Audio Editor SDK集成到APP中。

  • 现在,使用HMS Core音频编辑服务来实现您的创意吧。

7、参考文件

更多信息,请点击以下链接:

相关文档

下载示例代码,请点击以下链接:

下载

欲了解更多更全技术文章,欢迎访问 https://developer.huawei.com/consumer/cn/forum/?ha_source=zzh

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐