仿QQ語音變聲功能實現(xiàn)

版權(quán)聲明:轉(zhuǎn)載必須注明本文轉(zhuǎn)自張鵬輝的博客: http://blog.csdn.net/qingtiangg


大家好扒腕,這是我從業(yè)以來第一篇博客,給大家拜個晚年浊吏,祝大家雞年大吉斯辰,幸福美滿、事業(yè)有成帖旨。好了請容許我嘮叨幾萬字箕昭。首先自我介紹下
我叫張鵬輝大家可以叫我道長,我是老司······哦不解阅,我是新人請大家多多關(guān)照落竹。 一直都是看別人的博客成長(復(fù)制、黏貼)货抄,總想自己寫點什么述召,發(fā)出來,讓大家去點評蟹地,給建議互相成長积暖。這也是我的初衷,也就有了這個博客的誕生怪与。呀酸。。在下目前從事移動開發(fā)所以目前以移動端內(nèi)容來發(fā)布琼梆,記錄一些日常開發(fā)中碰到的坑性誉,和項目中一些模塊拿出來開源互相學(xué)習(xí)(幾萬字略。茎杂。错览。我用意念給你們介紹完了,就當(dāng)你們了解我了)

閑話不多說了開擼煌往,如題今天請跟貧道一步步來實現(xiàn)球球語音變聲功能

分析

首先我們來看下QQ語音變聲效果倾哺,如下圖所示:

這里寫圖片描述

點擊發(fā)送語音在點擊相應(yīng)的生效發(fā)出去就變聲了轧邪,沒玩過的可以打開QQ試下,那么他們是怎么做到讓聲音變聲呢羞海!看官們接著往下看忌愚。

首先我們知道,錄制人聲到手機(jī)却邓,這些音頻數(shù)據(jù)是由二進(jìn)制十六進(jìn)制組成硕糊,如果我們自己去用算法處理這些數(shù)據(jù)這個難度是比較大的。

那么怎么辦腊徙?简十??慶幸吧我們Android開發(fā)中有個NDK的東西撬腾,簡單來說就是我們在java層調(diào)用c/c++的一些強(qiáng)大的開源庫螟蝙,(這里不講NDK基礎(chǔ)如果想了解請谷歌一下)。

網(wǎng)上有很多開源的音頻處理庫民傻。我不知道騰訊是用的那個胰默,但我們今天用到的是FMOD音頻引擎,如果你做過游戲開發(fā)相信你一定接觸過漓踢,這里附上FMOD官網(wǎng)鏈接大家可以去簡單的看下介紹牵署,國內(nèi)FMOD的中文資料幾乎沒有,所以還是建議你去官網(wǎng)了解彭雾,點我進(jìn)fmod官網(wǎng)碟刺,這里就不詳細(xì)介紹了,他的主要功能就是對音頻進(jìn)行處理薯酝,比如你玩賽車類游戲你的引擎轟鳴聲半沽,會隨著你的速度變化而變化,游戲中有多個視角吴菠,比如車內(nèi)切換到車外者填,你聽到的聲音是不是不一樣的,再比如我們當(dāng)年玩的cs游戲做葵,你附近的敵人在你不同角度開槍占哟,你聽到的聲音也是不一樣的,(D鹗浮Uズ酢!暴露年齡了瘫筐。蜜暑。。)





或許我們來個圖更好理解:

這里寫圖片描述

聽到腳步聲或槍聲策肝,就可以判斷出敵人在你什么位置肛捍,不同的位置方位明顯聽到的聲音不同

開始

好的大體環(huán)境介紹完了隐绵,接下來我們看代碼。

首先我們新建eclipse工程‘’mysound‘’(這里不要問我為什么不用Android Studio開發(fā)as現(xiàn)在多火白竞痢依许!,因為ndk開發(fā)as還是有些問題的缀蹄,有些坑我也沒解決峭跳,我能怎么辦?我也很絕望呀 袍患。當(dāng)然了以后我主要還是以as去寫坦康,如果今天的項目你能移植到as里面請聯(lián)系我?⒏丁)

首先我們導(dǎo)入一下FMOD的so動態(tài)庫和一些需要用到的頭文件诡延。

這里寫圖片描述

今天的所有代碼和用到的庫我都會放到github上,所以不用擔(dān)心這些文件去哪找古胆。

1.接了下我們將工程轉(zhuǎn)成C/C++工程 Add Native Support

這里寫圖片描述

之后會給你生成android.mk文件 我們來配置一下里面的文件肆良,引入提供的預(yù)編譯的so庫把他們放到j(luò)ni目錄下,還有他自己的函數(shù)的實現(xiàn)也要引入看下面

LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)
LOCAL_MODULE := fmod
LOCAL_SRC_FILES := libfmod.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := fmodL
LOCAL_SRC_FILES := libfmodL.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE    := sound
LOCAL_SRC_FILES :=effect_fix.cpp
LOCAL_SHARED_LIBRARIES := fmod fmodL
LOCAL_LDLIBS := -llog
LOCAL_CPP_FEATURES :=exceptions
include $(BUILD_SHARED_LIBRARY)

LOCAL_MODULE := sound 自己的動態(tài)庫名切記要和System.loadLibrary("sound");一致這坑我踩過 逸绎,fmod fmodL這是2個預(yù)編譯的庫
如果你引入的是官網(wǎng)提供的庫可能會出現(xiàn)一些路徑的問題改一下就好我的已經(jīng)改了惹恃。

劃重點 FMOD 用到了標(biāo)準(zhǔn)模板庫STL,說用這玩意會變慢棺牧?巫糙,但我沒感覺出來
安卓ndk里面已經(jīng)有了一個最小的c++運行庫,想用那么我們就需要另外的配置

怎么配置呢颊乘?看ndk提供的文檔 在我們下載的ndk目錄里就有解決方法APP_STL

這里寫圖片描述
這里寫圖片描述

2.創(chuàng)建Application.mk 支持C++異常處理参淹,標(biāo)準(zhǔn)模板塊

里面就一句話 :

APP_STL := gnustl_static

3.配置完我們來寫java代碼

布局我就不在這貼出來了幾個按鈕,看關(guān)鍵代碼

我們先來個工具類Utils

public class Utils {
        //音效類型 大叔蘿莉什么的類型
        public static final int MODE_NORMAL=0;
        public static final int MODE_LUOLI=1;
        public static final int MODE_DASHU=2;
        public static final int MODE_JINGSONG=3;
        public static final int MODE_GAOGUAI=4;
        public static final int MODE_KONGLING=5;
    /**
     * 音效處理傳2個值
     * @param path 音頻文件路徑
     * @param type 音頻文件類型
     */
        public native static void fix(String path,int type);
        //加載動態(tài)庫
        //要和你android.mk文件一致
        static{
                System.loadLibrary("fmodL");
                System.loadLibrary("fmod");
                System.loadLibrary("sound");
        }
}

接下來我們生成頭文件

這里寫圖片描述

然后到項目F5刷新一下src目錄下會多出個.h的文件把它拖到j(luò)ni目錄下
繼續(xù)在jni目錄下創(chuàng)建一個c++源文件 supersound.cpp代碼

#include "inc/fmod.hpp"
#include <stdlib.h>
#include <unistd.h>
#include  "org_fmod_example_Utils.h"

#include <android/log.h>
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"zph",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"zph",FORMAT,##__VA_ARGS__);

#define MODE_NORMAL 0
#define MODE_LUOLI 1
#define MODE_DASHU 2
#define MODE_JINGSONG 3
#define MODE_GAOGUAI 4
#define MODE_KONGLING 5
using namespace FMOD;

JNIEXPORT void JNICALL Java_org_fmod_example_Utils_fix(JNIEnv *env,
        jclass jcls, jstring path_jstr, jint type) {
    //初始化
    System *system;
    Sound *sound;
    DSP *dsp;
    bool playing = true;
    Channel *channel; 
    float frequency = 0;
    System_Create(&system);
    system->init(32, FMOD_INIT_NORMAL, NULL);//32通道
    const char* path_cstr = env->GetStringUTFChars(path_jstr, NULL);
    try {

        //創(chuàng)建聲音
        system->createSound(path_cstr, FMOD_DEFAULT, NULL, &sound);
        switch (type) {
        case MODE_NORMAL:
            //原生播放
            LOGI("%s", path_cstr);
            system->playSound(sound, 0, false, &channel);
            LOGI("%s", "fix normal");
            break;
        case MODE_LUOLI:
            //loli
            //DSP digital singal process
            //dsp->音效
            //dsp 提升或者降低音調(diào)的一種音效
            system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
            //設(shè)置音調(diào)的參數(shù)
            dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 8.0);
            //添加進(jìn)到channel
            system->playSound(sound, 0, false, &channel);
            channel->addDSP(0, dsp);
            break;
        case MODE_DASHU:
            //大叔
            system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
            //設(shè)置音調(diào)的參數(shù)
            dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.8);
            //添加進(jìn)到channel
            system->playSound(sound, 0, false, &channel);
            channel->addDSP(0, dsp);
            break;
        case MODE_JINGSONG:
            //驚悚
            system->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);
            dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 5);
            system->playSound(sound, 0, false, &channel);
            channel->addDSP(0, dsp);
            break;
        case MODE_GAOGUAI:
            //搞怪
            //提高說話的速度
            system->playSound(sound, 0, false, &channel);
            channel->getFrequency(&frequency);
            frequency = frequency * 2;
            channel->setFrequency(frequency);
            break;
        case MODE_KONGLING:
            //空靈
            system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);
            dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 300);
            dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 20);
            system->playSound(sound, 0, false, &channel);
            channel->addDSP(0, dsp);
            break;
        default:
            break;
        }
    } catch (...) {
        LOGE("%s", "發(fā)生異常");
        goto end;
    }
    system->update();
    //釋放資源
    //單位是微妙
    //每秒鐘判斷下是否是播放
    while (playing) {
        channel->isPlaying(&playing);
        usleep(1000 * 1000);
    }
    goto end;
    end: env->ReleaseStringUTFChars(path_jstr, path_cstr);
    sound->release();
    system->close();
    system->release();
}

舉個例子比如在我們播放一段mp3的時候里面又人聲乏悄,樂器聲等浙值,如果我想對其中一個鋼琴的聲音加一個特效

這里寫圖片描述

那么怎么加呢!這就用到它了Channel *channel; 一般是32個通道修改完以后混音

好了到這里關(guān)鍵代碼已經(jīng)寫完檩小,我們可以測試玩玩了.

項目源碼下載地址:

https://github.com/CN-ZPH/MySound.git
覺得不錯請點一個star蛤开呐!
有問題下面留言評論,我看到會回復(fù)规求。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筐付,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子阻肿,更是在濱河造成了極大的恐慌瓦戚,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冕茅,死亡現(xiàn)場離奇詭異伤极,居然都是意外死亡蛹找,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門哨坪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庸疾,“玉大人,你說我怎么就攤上這事当编〗齑龋” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵忿偷,是天一觀的道長金顿。 經(jīng)常有香客問我,道長鲤桥,這世上最難降的妖魔是什么揍拆? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮茶凳,結(jié)果婚禮上嫂拴,老公的妹妹穿的比我還像新娘。我一直安慰自己贮喧,他們只是感情好筒狠,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著箱沦,像睡著了一般辩恼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谓形,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天灶伊,我揣著相機(jī)與錄音,去河邊找鬼套耕。 笑死谁帕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冯袍。 我是一名探鬼主播匈挖,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼康愤!你這毒婦竟也來了儡循?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤征冷,失蹤者是張志新(化名)和其女友劉穎择膝,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體检激,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡肴捉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年腹侣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片齿穗。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡傲隶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窃页,到底是詐尸還是另有隱情跺株,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布脖卖,位于F島的核電站乒省,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏畦木。R本人自食惡果不足惜袖扛,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望馋劈。 院中可真熱鬧攻锰,春花似錦晾嘶、人聲如沸妓雾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽械姻。三九已至,卻和暖如春机断,著一層夾襖步出監(jiān)牢的瞬間楷拳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工吏奸, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留欢揖,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓奋蔚,卻偏偏與公主長得像她混,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泊碑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容