pcm混音

近段时间公司做一个电信项目,铃音助手,用户可以从网上下载背景铃音,和自己的录音合成一个性化的铃音后设为自己手机的彩铃 ,开始是其他同事搞的,在其用了多天时间无法解决的情况下,我介入处理,轻松搞定 。我发现我们的背景音是a-law或µ-law编码的,需要对其解码成PCM编码,和录音混音后再转回原来的编码。转码混音处理使用NDK开发JNI C代码放native层执行实现,以提高处理的效率,经过对 Android系统的性能监控发现,在运行处理的时候,内存无明显消耗增加,cpu使用不到20%(mtk四核),远远低于浏览网页时的消耗。在wav文件头中的14H位置是音频压缩算法的标记,其数值对应的是:

Code  Description
0 (0x0000) Unknown
1 (0x0001) PCM/uncompressed
2 (0x0002) Microsoft ADPCM
6 (0x0006) ITU G.711 a-law 
7 (0x0007) ITU G.711 µ-law 
17 (0x0011) IMA ADPCM 
20 (0x0016) ITU G.723 ADPCM (Yamaha) 
49 (0x0031) GSM 6.10 
64 (0x0040) ITU G.721 ADPCM 
80 (0x0050) MPEG 
65,536 (0xFFFF) Experimental

其中:

6. ITU G.711 a-law [3]

 G.711标准也是PCM码的一种。是国际电报联盟(International Telegraph Union, ITU)订定出来的一套语音压缩标准,主要用于电话。它主要用脉冲编码调制对音频采样,采样率为8kHz。它利用一个 64kbit/s 未压缩通道传输语音讯号。起压缩率为1:2,即把16位数据压缩成8位。G.711是主流的波形声音编解码器。
 G.711 标准下主要有两种压缩算法。一种是?μ-law algorithm (又称μ-law),主要运用于北美和日本;另一种就是a-law algorithm,主要运用于欧洲和世界其他地区。其中,a-law是特别设计用来方便计算机处理的。

7. ITU G.711 µ-law
 G.711标准下的另一种压缩算法,主要运用于北美和日本,美国电话格式(CCITT G.711)就采用这种算法。

    Android 手机录音的码流就是16位PCM 编码的,可以直接和wav解码出来的码流进行混音处理,下面是JNI 的C代码实现:


  1. /* 
  2.  * 文件名:wav_codec.c 
  3.  * 创建时间:2014年11月26日 
  4.  */  
  5. #include <wav_codec.h>  
  6.   
  7.   
  8. #define SIGN_BIT    (0x80)      /* Sign bit for a A-law byte. */    
  9. #define QUANT_MASK  (0xf)       /* Quantization field mask. */    
  10. #define SEG_SHIFT   (4)         /* Left shift for segment number. */    
  11. #define SEG_MASK    (0x70)      /* Segment field mask. */    
  12. #define BIAS        (0x84)      /* Bias for linear code. */    
  13. #define CLIP        8159    
  14. static const short seg_aend[8] = { 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,  
  15.         0xFFF };  
  16. static const short seg_uend[8] = { 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF,  
  17.         0x1FFF };  
  18.   
  19. short search(short val, short *table, short size);  
  20. char linear2alaw(short pcm_val);  
  21. short alaw2linear(unsigned char a_val);  
  22. char linear2ulaw(short pcm_val);  
  23. short ulaw2linear(unsigned char u_val);  
  24. short PcmMix0(short shortIntCh0, short shortIntCh1);  
  25.   
  26. /* 
  27.  * Class:     com_demo_mymix_WavConvertUtils 
  28.  * Method:    pcmToAlaw 
  29.  * Signature: ([BI)[B 
  30.  * 16位pcm转a-law 
  31.  */  
  32. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_PcmToAlaw(  
  33.         JNIEnv *env, jclass thiz, jbyteArray src) {  
  34.     int length = (*env)->GetArrayLength(env, src);  
  35.     uint8 buffer[length];  
  36.     (*env)->GetByteArrayRegion(env, src, 0, length, buffer);  
  37.   
  38.     char resultTemp[length / 2];  
  39.     int i = 0;  
  40.     for (i = 0; i < length; i += 2) {  
  41.         short shortInt = (((buffer[i + 1] & 0xff) << 8) | (buffer[i] & 0x00ff));  
  42.         resultTemp[i / 2] = linear2alaw(shortInt);  
  43.     }  
  44.   
  45.     jbyteArray result = (*env)->NewByteArray(env, length / 2);  
  46.     (*env)->SetByteArrayRegion(env, result, 0, length / 2, resultTemp);  
  47.   
  48.     return result;  
  49. }  
  50.   
  51. /* 
  52.  * Class:     com_demo_mymix_WavConvertUtils 
  53.  * Method:    AlawTopcm 
  54.  * Signature: ([BI)[B 
  55.  * a-law转16位pcm 
  56.  */  
  57. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_AlawToPcm(  
  58.         JNIEnv *env, jclass thiz, jbyteArray src) {  
  59.     int length = (*env)->GetArrayLength(env, src);  
  60.     uint8 buffer[length];  
  61.     (*env)->GetByteArrayRegion(env, src, 0, length, buffer);  
  62.   
  63.     char resultTemp[length * 2];  
  64.     int i = 0;  
  65.     for (i = 0; i < length; i++) {  
  66.         short resultShort = alaw2linear(buffer[i]);  
  67.         resultTemp[i * 2] = (char) (resultShort);  
  68.         resultTemp[i * 2 + 1] = (char) (resultShort >> 8);  
  69.     }  
  70.   
  71.     jbyteArray result = (*env)->NewByteArray(env, length * 2);  
  72.     (*env)->SetByteArrayRegion(env, result, 0, length * 2, resultTemp);  
  73.   
  74.     return result;  
  75. }  
  76. /* 
  77.  * Class:     com_demo_mymix_WavConvertUtils 
  78.  * Method:    pcmToUlaw 
  79.  * Signature: ([BI)[B 
  80.  * 16位pcm转u-law 
  81.  */  
  82. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_PcmToUlaw(  
  83.         JNIEnv *env, jclass thiz, jbyteArray src) {  
  84.     int length = (*env)->GetArrayLength(env, src);  
  85.     uint8 buffer[length];  
  86.     (*env)->GetByteArrayRegion(env, src, 0, length, buffer);  
  87.   
  88.     char resultTemp[length / 2];  
  89.     int i = 0;  
  90.     for (i = 0; i < length; i += 2) {  
  91.         short shortInt = (((buffer[1 + i] & 0xff) << 8) | (buffer[i] & 0x00ff));  
  92.         resultTemp[i / 2] = linear2ulaw(shortInt);  
  93.     }  
  94.   
  95.     jbyteArray result = (*env)->NewByteArray(env, length / 2);  
  96.     (*env)->SetByteArrayRegion(env, result, 0, length / 2, resultTemp);  
  97.   
  98.     return result;  
  99. }  
  100. /* 
  101.  * Class:     com_demo_mymix_WavConvertUtils 
  102.  * Method:    UlawTopcm 
  103.  * Signature: ([BI)[B 
  104.  * u-law转16位pcm 
  105.  */  
  106. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_UlawToPcm(  
  107.         JNIEnv *env, jclass thiz, jbyteArray src) {  
  108.     int length = (*env)->GetArrayLength(env, src);  
  109.     uint8 buffer[length];  
  110.     (*env)->GetByteArrayRegion(env, src, 0, length, buffer);  
  111.   
  112.     char resultTemp[length * 2];  
  113.     int i = 0;  
  114.     for (i = 0; i < length; i++) {  
  115.         short resultShort = ulaw2linear(buffer[i]);  
  116.         resultTemp[i * 2] = (char) (resultShort);  
  117.         resultTemp[i * 2 + 1] = (char) (resultShort >> 8);  
  118.     }  
  119.   
  120.     jbyteArray result = (*env)->NewByteArray(env, length * 2);  
  121.     (*env)->SetByteArrayRegion(env, result, 0, length * 2, resultTemp);  
  122.   
  123.     return result;  
  124. }  
  125.   
  126. /* 
  127.  * Class:     com_demo_mymix_WavConvertUtils 
  128.  * Method:    Pcm16ALawCompound 
  129.  * Signature: ([BI)[B 
  130.  * 16位pcm与a-law混音成a-law 
  131.  */  
  132. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_Pcm16ALawCompoundAlaw(  
  133.         JNIEnv *env, jclass thiz, jbyteArray ch0, jbyteArray ch1) {  
  134.     int ch0Length = (*env)->GetArrayLength(env, ch0);  
  135.     int ch1Length = (*env)->GetArrayLength(env, ch1);  
  136.     uint8 ch0Buffer[ch0Length];  
  137.     uint8 ch1Buffer[ch1Length];  
  138.     (*env)->GetByteArrayRegion(env, ch0, 0, ch0Length, ch0Buffer);  
  139.     (*env)->GetByteArrayRegion(env, ch1, 0, ch1Length, ch1Buffer);  
  140.   
  141.     char alawPcm[ch1Length * 2];  
  142.     int i = 0;  
  143.     for (i = 0; i < ch1Length; i++) {  
  144.         short resultShort = alaw2linear(ch1Buffer[i]);  
  145.         alawPcm[i * 2] = (char) (resultShort);  
  146.         alawPcm[i * 2 + 1] = (char) (resultShort >> 8);  
  147.     }  
  148.   
  149.     char compoundTemp[ch0Length];  
  150.     for (i = 0; i < ch0Length; i += 2) {  
  151.         //转换结果  
  152.         short dataMix = 0;  
  153.         //byte2short  
  154.         short shortIntCh0 = (((ch0Buffer[1 + i] & 0xff) << 8)  
  155.                 | (ch0Buffer[i] & 0x00ff));  
  156.         short shortIntCh1 = (((alawPcm[1 + i] & 0xff) << 8)  
  157.                 | (alawPcm[i] & 0x00ff));  
  158.         dataMix = PcmMix0(shortIntCh0, shortIntCh1);  
  159.   
  160.         compoundTemp[i] = (char) (dataMix);  
  161.         compoundTemp[i + 1] = (char) (dataMix >> 8);  
  162.     }  
  163.   
  164.     char resultTemp[ch1Length];  
  165.     for (i = 0; i < ch0Length; i += 2) {  
  166.         short shortInt = (((compoundTemp[i + 1] & 0xff) << 8)  
  167.                 | (compoundTemp[i] & 0x00ff));  
  168.         resultTemp[i / 2] = linear2alaw(shortInt);  
  169.     }  
  170.   
  171.     jbyteArray result = (*env)->NewByteArray(env, ch1Length);  
  172.     (*env)->SetByteArrayRegion(env, result, 0, ch1Length, resultTemp);  
  173.   
  174.     return result;  
  175. }  
  176.   
  177. /* 
  178.  * Class:     com_demo_mymix_WavConvertUtils 
  179.  * Method:    Pcm16ULawCompound 
  180.  * Signature: ([BI)[B 
  181.  * 16位pcm与u-law混音成a-law 
  182.  */  
  183. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_Pcm16ULawCompoundAlaw(  
  184.         JNIEnv *env, jclass thiz, jbyteArray ch0, jbyteArray ch1) {  
  185.     int ch0Length = (*env)->GetArrayLength(env, ch0);  
  186.     int ch1Length = (*env)->GetArrayLength(env, ch1);  
  187.     uint8 ch0Buffer[ch0Length];  
  188.     uint8 ch1Buffer[ch1Length];  
  189.     (*env)->GetByteArrayRegion(env, ch0, 0, ch0Length, ch0Buffer);  
  190.     (*env)->GetByteArrayRegion(env, ch1, 0, ch1Length, ch1Buffer);  
  191.   
  192.     char ulawPcm[ch1Length * 2];  
  193.     int i = 0;  
  194.     for (i = 0; i < ch1Length; i++) {  
  195.         short resultShort = ulaw2linear(ch1Buffer[i]);  
  196.         ulawPcm[i * 2] = (char) (resultShort);  
  197.         ulawPcm[i * 2 + 1] = (char) (resultShort >> 8);  
  198.     }  
  199.   
  200.     char compoundTemp[ch0Length];  
  201.     for (i = 0; i < ch0Length; i += 2) {  
  202.         //转换结果  
  203.         short dataMix = 0;  
  204.         //byte2short  
  205.         short shortIntCh0 = (((ch0Buffer[1 + i] & 0xff) << 8)  
  206.                 | (ch0Buffer[i] & 0x00ff));  
  207.         short shortIntCh1 = (((ulawPcm[1 + i] & 0xff) << 8)  
  208.                 | (ulawPcm[i] & 0x00ff));  
  209.         dataMix = PcmMix0(shortIntCh0, shortIntCh1);  
  210.   
  211.         compoundTemp[i] = (char) (dataMix);  
  212.         compoundTemp[i + 1] = (char) (dataMix >> 8);  
  213.     }  
  214.   
  215.     char resultTemp[ch1Length];  
  216.     for (i = 0; i < ch0Length; i += 2) {  
  217.         short shortInt = (((compoundTemp[i + 1] & 0xff) << 8)  
  218.                 | (compoundTemp[i] & 0x00ff));  
  219.         resultTemp[i / 2] = linear2alaw(shortInt);  
  220.     }  
  221.   
  222.     jbyteArray result = (*env)->NewByteArray(env, ch1Length);  
  223.     (*env)->SetByteArrayRegion(env, result, 0, ch1Length, resultTemp);  
  224.   
  225.     return result;  
  226. }  
  227.   
  228. /* 
  229.  * Class:     com_demo_mymix_WavConvertUtils 
  230.  * Method:    DoublePcm16Compound 
  231.  * Signature: ([BI)[B 
  232.  * 两路16位PCM编码混音 
  233.  */  
  234. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_DoublePcm16Compound(  
  235.         JNIEnv *env, jclass thiz, jbyteArray ch0, jbyteArray ch1) {  
  236.     int ch0Length = (*env)->GetArrayLength(env, ch0);  
  237.     int ch1Length = (*env)->GetArrayLength(env, ch1);  
  238.     uint8 ch0Buffer[ch0Length];  
  239.     uint8 ch1Buffer[ch1Length];  
  240.     (*env)->GetByteArrayRegion(env, ch0, 0, ch0Length, ch0Buffer);  
  241.     (*env)->GetByteArrayRegion(env, ch1, 0, ch1Length, ch1Buffer);  
  242.   
  243.     char resultTemp[ch1Length];  
  244.     int i = 0;  
  245.     for (i = 0; i < ch1Length; i += 2) {  
  246.         //转换结果  
  247.         short dataMix = 0;  
  248.         //byte2short  
  249.         short shortIntCh0 = (((ch0Buffer[1 + i] & 0xff) << 8)  
  250.                 | (ch0Buffer[i] & 0x00ff));  
  251.         short shortIntCh1 = (((ch1Buffer[1 + i] & 0xff) << 8)  
  252.                 | (ch1Buffer[i] & 0x00ff));  
  253.         dataMix = PcmMix0(shortIntCh0, shortIntCh1);  
  254.   
  255.         resultTemp[i] = (char) (dataMix);  
  256.         resultTemp[i + 1] = (char) (dataMix >> 8);  
  257.     }  
  258.   
  259.     jbyteArray result = (*env)->NewByteArray(env, ch1Length);  
  260.     (*env)->SetByteArrayRegion(env, result, 0, ch1Length, resultTemp);  
  261.   
  262.     return result;  
  263. }  
  264.   
  265. /*************** 检查输入信号在哪个压缩区间 *********************/  
  266. short search(short val, short *table, short size) {  
  267.     short i;  
  268.   
  269.     for (i = 0; i < size; i++) {  
  270.         if (val <= *table++) //找出一个与输入信号最相近的值(大于)  
  271.                 {  
  272.             return (i);  
  273.         }  
  274.     }  
  275.     return (size);  
  276. }  
  277.   
  278. /********************* PCM 2 a-law ****************************/  
  279. char linear2alaw(short pcm_val) {  
  280.     short mask;  
  281.     short seg;  
  282.     unsigned char aval;  
  283.   
  284.     pcm_val = pcm_val >> 3;  
  285.   
  286.     if (pcm_val >= 0) {  
  287.         mask = 0xD5; /* sign (7th) bit = 1 */  
  288.     } else {  
  289.         mask = 0x55; /* sign bit = 0 */  
  290.         pcm_val = -pcm_val - 1;  
  291.     }  
  292.   
  293.     /* Convert the scaled magnitude to segment number. */  
  294.     seg = search(pcm_val, (short *) seg_aend, (short) 8);  
  295.   
  296.     /* Combine the sign, segment, and quantization bits. */  
  297.   
  298.     if (seg >= 8) /* out of range, return maximum value. */  
  299.     {  
  300.         return (unsigned char) (0x7F ^ mask);  
  301.     } else {  
  302.         aval = (unsigned char) seg << SEG_SHIFT;  
  303.   
  304.         if (seg < 2) {  
  305.             aval |= (pcm_val >> 1) & QUANT_MASK;  
  306.         } else {  
  307.             aval |= (pcm_val >> seg) & QUANT_MASK;  
  308.         }  
  309.         return (aval ^ mask);  
  310.     }  
  311. }  
  312.   
  313. /***************** a-law 2 PCM *******************/  
  314. short alaw2linear(unsigned char a_val) {  
  315.     short t;  
  316.     short seg;  
  317.   
  318.     a_val ^= 0x55;  
  319.   
  320.     t = (a_val & QUANT_MASK) << 4;  
  321.     seg = ((unsigned) a_val & SEG_MASK) >> SEG_SHIFT;  
  322.     switch (seg) {  
  323.     case 0:  
  324.         t += 8;  
  325.         break;  
  326.     case 1:  
  327.         t += 0x108;  
  328.         break;  
  329.     default:  
  330.         t += 0x108;  
  331.         t <<= seg - 1;  
  332.         break;  
  333.     }  
  334.     return ((a_val & SIGN_BIT) ? t : -t);  
  335. }  
  336.   
  337. /*********************** pcm 2 u law *************************/  
  338. char linear2ulaw(short pcm_val) {  
  339.     short mask;  
  340.     short seg;  
  341.     unsigned char uval;  
  342.   
  343.     /* Get the sign and the magnitude of the value. */  
  344.     pcm_val = pcm_val >> 2;  
  345.     if (pcm_val < 0) {  
  346.         pcm_val = -pcm_val;  
  347.         mask = 0x7F;  
  348.     } else {  
  349.         mask = 0xFF;  
  350.     }  
  351.     if (pcm_val > CLIP) {  
  352.         pcm_val = CLIP; /* clip the magnitude */  
  353.     }  
  354.     pcm_val += (BIAS >> 2);  
  355.   
  356.     /* Convert the scaled magnitude to segment number. */  
  357.     seg = search(pcm_val, (short *) seg_uend, (short) 8);  
  358.   
  359.     /* 
  360.      * Combine the sign, segment, quantization bits; 
  361.      * and complement the code word. 
  362.      */  
  363.     if (seg >= 8) /* out of range, return maximum value. */  
  364.     {  
  365.         return (unsigned char) (0x7F ^ mask);  
  366.     } else {  
  367.         uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);  
  368.         return (uval ^ mask);  
  369.     }  
  370. }  
  371.   
  372. /*********************** ulaw 2 pcm *************************/  
  373. short ulaw2linear(unsigned char u_val) {  
  374.     short t;  
  375.   
  376.     /* Complement to obtain normal u-law value. */  
  377.     u_val = ~u_val;  
  378.   
  379.     /* 
  380.      * Extract and bias the quantization bits. Then 
  381.      * shift up by the segment number and subtract out the bias. 
  382.      */  
  383.     t = ((u_val & QUANT_MASK) << 3) + BIAS;  
  384.     t <<= ((unsigned) u_val & SEG_MASK) >> SEG_SHIFT;  
  385.   
  386.     return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));  
  387. }  

下面是C头文件:

  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. #include <android/log.h>  
  4. /* Header for class com_demo_mymix_WavConvertUtils */  
  5. #ifndef  LOG_TAG  
  6. #define  LOG_TAG    "XIAXC"  
  7. #define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)  
  8. #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
  9. #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  10. #endif  
  11.   
  12. typedef unsigned char uint8;  
  13. typedef unsigned short uint16;  
  14. typedef unsigned int uint32;  
  15.   
  16. #ifndef _Included_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils  
  17. #define _Included_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils  
  18. #ifdef __cplusplus  
  19. extern "C" {  
  20. #endif  
  21. /* 
  22.  * Class:     cn_easier_RingtoneHelper_logic_diy_WavConvertUtils 
  23.  * Method:    PcmToAlaw 
  24.  * Signature: ([B)[B 
  25.  */  
  26. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_PcmToAlaw  
  27.   (JNIEnv *, jclass, jbyteArray);  
  28.   
  29. /* 
  30.  * Class:     cn_easier_RingtoneHelper_logic_diy_WavConvertUtils 
  31.  * Method:    AlawToPcm 
  32.  * Signature: ([B)[B 
  33.  */  
  34. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_AlawToPcm  
  35.   (JNIEnv *, jclass, jbyteArray);  
  36.   
  37. /* 
  38.  * Class:     cn_easier_RingtoneHelper_logic_diy_WavConvertUtils 
  39.  * Method:    PcmToUlaw 
  40.  * Signature: ([B)[B 
  41.  */  
  42. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_PcmToUlaw  
  43.   (JNIEnv *, jclass, jbyteArray);  
  44.   
  45. /* 
  46.  * Class:     cn_easier_RingtoneHelper_logic_diy_WavConvertUtils 
  47.  * Method:    UlawToPcm 
  48.  * Signature: ([B)[B 
  49.  */  
  50. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_UlawToPcm  
  51.   (JNIEnv *, jclass, jbyteArray);  
  52.   
  53. /* 
  54.  * Class:     cn_easier_RingtoneHelper_logic_diy_WavConvertUtils 
  55.  * Method:    DoublePcm16Compound 
  56.  * Signature: ([B[B)[B 
  57.  */  
  58. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_DoublePcm16Compound  
  59.   (JNIEnv *, jclass, jbyteArray, jbyteArray);  
  60.   
  61. /* 
  62.  * Class:     cn_easier_RingtoneHelper_logic_diy_WavConvertUtils 
  63.  * Method:    Pcm16ALawCompoundAlaw 
  64.  * Signature: ([B[B)[B 
  65.  */  
  66. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_Pcm16ALawCompoundAlaw  
  67.   (JNIEnv *, jclass, jbyteArray, jbyteArray);  
  68.   
  69. /* 
  70.  * Class:     cn_easier_RingtoneHelper_logic_diy_WavConvertUtils 
  71.  * Method:    Pcm16ULawCompoundAlaw 
  72.  * Signature: ([B[B)[B 
  73.  */  
  74. JNIEXPORT jbyteArray JNICALL Java_cn_easier_RingtoneHelper_logic_diy_WavConvertUtils_Pcm16ULawCompoundAlaw  
  75.   (JNIEnv *, jclass, jbyteArray, jbyteArray);  
  76.   
  77. #ifdef __cplusplus  
  78. }  
  79. #endif  
  80. #endif 


一个PCM音频转换与混音的示例

  做语音通讯时通常会碰到需要将某种格式的音频信号转换成其它格式的音频信号和将两个或多个音频信号混合的情况,参考网上搜寻到的一些资料,我做了一个示例程序,此程序可以将两个 8Bit 8000Sample 1Channel PCM A-Law 格式的音频文件转换成为容易混音的16Bit 8000Sample 1Channel PCM Line格式的音频数据,然后对两个信号进行混音处理,最后将混音结果再转换为8Bit 8000Sample 1Channel PCM A-Law格式保存。
  格式转换使用了ACM,参考了《 VC下调用ACM音频编程接口压缩Wave音频》(原文不知何处,GOOGLE一下一大把),混音则采用最简便的线性累加的方法进行累加。
  我提供了两个文件A1.PCM和A2.PCM,点击Convert按钮会将这两个文件转换为B1.PCM与B2.PCM,生成这两个文件后,点击MIX按钮会将B1.PCM与B2.PCM混合并生成M.PCM。

  A1.PCM、A2.PCM、M.PCM格式均为 8Bit 8000Sample 1Channel PCM A-Law格式
  B1.PCM、B2.PCM格式为16Bit 8000Sample 1Channel PCM Line格式
  以上文件可以使用CoolEdit或Adobe Audition打开。

  工程基于CodeGear C++ Builder 2007,在Windows Server 2003和Vista下均调试通过。

代码下载: 点此下载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值