国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

學做網頁Applet錄音機

2019-11-18 15:19:52
字體:
來源:轉載
供稿:網友

學做網頁Applet錄音機

網絡多媒體是目前Web應用的一個發展方向。在網頁上錄音,并發給朋友,相信他們收到你的聲音一定非常興奮。如今這已經是一項很普通的多媒體應用技術,筆者使用java語言開發出了能夠嵌入Web頁面上的Applet錄音機(界面外觀如下圖所示)。假如你有編程的愛好,不妨試試。在此,我將這種技術介紹給各位編程愛好者。

多媒體基本概念及常識

開發多媒體音頻軟件,必須了解一些多媒體基本概念,諸如采樣、量化、量化位、采樣頻率、單雙聲道、音頻編解碼、音頻壓縮格式等概念。采樣是把時間上連續的模擬信號變成時間上離散的、有限個樣值的信號。量化是在幅度上把連續值的模擬信號變為離散值的數字信號。在時間軸上已變為離散的樣值脈沖,在幅度軸上仍會在動態范圍內有連續值,可能出現任意幅值,即在幅度軸上仍是模擬信號的性質,因此必須用有限個電平等級來代表實際量值。量化位是每個采樣點能夠表示的數據范圍,經常采用的有8、12和16位。采樣頻率是將模擬聲音波形轉換為數字時,每秒鐘所抽取聲波幅度樣本的次數,采樣頻率的計算單位是Hz(赫茲)。根據采樣理論,為了保證聲音不失真,采樣頻率應為聲音頻率的兩倍左右。記錄聲音時,假如每次生成一個聲波數據,稱為單聲道;每次生成二個聲波數據,成為立體聲(雙聲道)。量化位和采樣頻率越高,音質就越好。

正常人耳聽覺的聲音頻率范圍大約在20Hz至20KHz之間,人的語音頻率大概在300Hz至3.4KHz之間。對于語音來說,采用8KHz的采樣頻率已經足夠了。所以我們采用8KHz采樣頻率、16位量化位、單聲道來記錄和播放語音,就可以滿足網頁上的語音需求了。

網頁錄音機的制作過程

了解了以上常識,下面來看看錄音機的制作過程。

首先要碰到的是音頻采集。音頻采集有很多種,JDK 1.3中構建TargetDataLine類實例來實現聲音數據采集。在此例中,我采用Visual J++的J/Direct調用Windows API函數來實現聲音的采集。

聲音俘獲主要由AudioCapture、AudioDataEvent、AudioDataListener三個類組成。我們依次按照0.1秒時間采樣數據塊的大小(即1600字節)作為所送出到系統的錄音數據緩沖區大小,這樣也就相當于每隔0.1秒聲卡提交給我們一次聲音數據。另外,使用Windows API方式聲音采集有一個好處,錄音過程不需要建立單獨的線程。這是因為有回調函數的巨大作用,這樣節省了系統資源,提高了程序的穩定性。

//聲音俘獲類:

...

public class AudioCapture{

...

public AudioCapture(){

...

waveincaps=new WAVEINCAPS();

wavehdr=new WAVEHDR[bufferlen];

}

public void addAudioDataListener(AudioDataListener lter){

listeners.addElement(lter);

}

void applyBuffer(){

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

wavehdr[i]=new WAVEHDR();

int

adr=dlllib.addrOfPinnedObject(dlllib.getPinnedHandle(data[i]));

wavehdr[i].lpData=adr;

...

}

}

int chkData(byte[] a){//將整型低16位高低位交叉并轉為字節

...

}

public void close(){

if(!useful)return;

isclose=true;

waveInStop(deviceid[0]);

...

}

...

synchronized void notifyListener(int minValue,byte[] audioData){

AudioDataEvent evt=new AudioDataEvent(this,minValue,audioData);

For(Enumeration enu=listeners.elements();enu.hasMoreElements();)

((AudioDataListener)enu.nextElement()).onAudioDataArrived(evt);

}

...

public void setMuteValue(int muteValue){

this.muteValue=muteValue;

}

/**@dll.import("WINMM",auto)*/

...

public static native int waveInReset(int hwi);

PRivate class c extends Callback{

AudioCapture record;

c(AudioCapture tt){

record=tt;

}

...

}

}

//緩沖數據提交事件類:

import java.util.EventObject;

public class AudioDataEvent extends EventObject{

...

}

//事件偵聽接口

import java.util.EventListener;

public interface AudioDataListener extends EventListener{

public abstract void onAudioDataArrived(AudioDataEvent evt);

}

第二步,數據的編碼壓縮存儲。由聲卡采集的數據是一連串16位脈沖編碼調制(PCM格式)的數據,數據量很大,假如不采取壓縮處理,不利于文件的存儲和傳輸。所以要進行數據的壓縮編碼,這就是我們會碰到的聲音編碼數據格式。壓縮編碼方法有很多種,有GSM、IAM4、AU格式編碼等,這些壓縮算法比較簡單,可以在很多網站上獲得壓縮和解壓縮的源代碼。筆者對這幾種壓縮格式進行了測試,其主要參數及品質對比見上表。

壓縮格式主要參數及品質對比

壓縮格式 GSM IMA4 AU

壓縮比 10:1 4:1 2:1

文件大小 很小 小 中

聲音質量 一般 好 好

編解碼速度 慢 快 很快

數據量(byte/s) 165 400 800

一般來說,人說話時并不是非常連續的,哪怕是你有意發連續的聲音,其實有很多時間段是處在靜音狀態(沒有聲音或聲音很小,量化數據值很小),只要記錄它的一個狀態就可以了。所以聲音數據區的數據格式就是(數據頭+數據體)的方式。對于靜音數據,數據頭為0,數據體為空。

在聲音回放時,先讀數據頭,假如數據頭不為0,則解壓數據體播放;假如數據頭為0,則暫停一定時間或者寫入一定長度的靜音數據即可。采用這種方式可以大大減小記錄語音文件,并且不影響聲音的還原回放。

//處理錄音數據到達事件

public void onAudioDataArrived(AudioDataEvent evt){

...

int min=evt.getAudioMinValue();

fileWriter.write((min==0?0:1));

if(min!=0){

Convert.BytesToInts(evt.getAudioData(),audiodata);

fileWriter.write(Codec.encode(evt.getAudioData()));

}

...

}

第三步,聲音采集編碼保存結束后,就可以回放我們錄制的聲音。

接下來我們要在網頁上來播放它。Java Applet支持AU格式聲音的回放,使用非常簡單。所以我們把錄制并壓縮的聲音數據解碼為AU格式,就可以很方便地進行聲音回放了。在sun.audio包中提供的au流數據播放sun.audio.AudioPlayer.start(InputStream),實際上是虛擬機的au播放類每隔50毫秒依次調用InputStream的read(byte[],abyte0,int i,int j)方法,每次讀取長度為400字節的AU格式數據用來播放。我們知道,輸入流的read方法是阻塞方式的,而解壓縮聲音數據是要費時的,假如在其請求數據時再解壓數據并寫入緩沖區,則播放聲音時聽起來會斷斷續續的,那是不可行的。所以需要單獨建立解壓縮數據的線程,也就是說從虛擬機的au播放類讀取數據的線程中獨立出來,用緩沖區做為兩個線程的管道連接,解壓縮線程不停地寫入緩沖區中,播放線程不斷地從緩沖區中讀取并播放。這樣一來,對于播放聲音的暫停、停止等功能就很輕易實現。所以我們需要重載read(byte[],abyte0,int I,int j)方法。

//音頻緩沖區類

import java.io.*;

public class AudioBuffer extends InputStream{

int capacity=4096;

...

public AudioBuffer(AudioPlayer ap){

player=ap;

clearData();

}

public void close(){

isclose=true;

synchronized(putManager){

if(waitingPut>0)putManager.notify();

}

synchronized(getManager){

if(waitingGet>0)getManager.notify();

}

}

public void clearData(){

...

}

public void suspend(){ispause=true;}

public void resume(){ispause=false;}

public void write(int i){

synchronized(putManager){

while(emptyBytes<1){

waitingPut++;

try{

putManager.wait();

}catch(InterruptedException _ex){}

waitingPut--;

}

...

}

synchronized(getManager){

usedBytes++;

if(waitingGet>0)getManager.notify();

}

}

public void write(byte[] d){

write(d,0,d.length);

}

public void write(byte[] d,int i,int j){

...

synchronized(getManager){

usedBytes+=j;

if(waitingGet>0)getManager.notify();

}

}

public int read(){

...

}

public int read(byte[] d){

return read(d,0,d.length);

}

public int read(byte[] d,int i,int j){

if(isclose)return -1;

if(ispause){

d[i]=127;

return 1;

}

synchronized(getManager){

...

}

System.arraycopy(data,readPtr,d,i,k);

ReadPtr+=k;

readPtr%=capacity;

usedBytes-=j;

}

synchronized(putManager){

emptyBytes+=j;

if(waitingPut>0)putManager.notify();

}

try{

player.notifyListener(AudioPlayEvent.PLAY_DATA,d);

}catch(Exception e){}

return j;

}

}

//音頻播放器類

public class AudioPlayer implements Runnable{

...

AudioBuffer buffer=new AudioBuffer(this);

sun.audio.AudioPlayer.start(buffer);

...

byte[] auData=new byte[400];

//存放解壓后的au數據

int compressLength=165;

//GSM格式為165;IMA格式為400;AU格式為800

byte[] compressData=new byte[compressLength];

//存儲從文件流中讀取的壓縮格式數據

...

public void run(){

...

fileInputStream.read(compressData);//從音頻文件讀取壓縮格式數據,此輸入流要處理靜音

Codec.decode(abyte0,auData); //解壓縮數據到auData

Buffer.write(auData,0,400);//寫入到緩沖區

...

}

...

}

最后,將上述各個模塊拼接起來,并把GUI做好就可以使用了。假如在GUI上加入聲音顯示效果,你的錄音機就更酷了。

總結

這里介紹的聲音處理的主要技術,可以組合或衍生使用。例如,可以在網頁上方便地實現聲音回放;可以加入調節播放起點(跳躍播放)功能,而不使用其它播放器;還可以做語音留言系統。假如數據通過流格式以組播方式實時傳出,另一端接收下來然后播放出來,又可非常簡單地實現實時語音系統,即語音聊天。另外,有了自己的語音庫,還可以實現簡單的語音合成技術,讓計算機讀出文本內容(請訪問播放程序演示地址:http://home.njenet.net.cn/hawa/player.htm)。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 威信县| 沿河| 和林格尔县| 蓝山县| 六枝特区| 尚志市| 宿迁市| 赫章县| 石门县| 疏附县| 莱西市| 丘北县| 突泉县| 穆棱市| 卢湾区| 沐川县| 江永县| 绩溪县| 外汇| 八宿县| 黄石市| 含山县| 大宁县| 江孜县| 太康县| 崇左市| 库伦旗| 于田县| 清远市| 疏勒县| 龙陵县| 崇信县| 乌什县| 安化县| 汾阳市| 田东县| 玉田县| 汝州市| 通道| 游戏| 进贤县|