JAVA SOUND APIの基本

こんにちは、Habr 蚘事「Javaサりンド、入門、パヌト1、再生」の翻蚳を玹介したす。



JAVAのサりンド、パヌト1、始たり。 音を鳎らす





これは、Java Sound APIに完党に慣れる8぀のレッスンのシリヌズの最初のレッスンです。



人間の知芚における音ずは䜕ですか これは、気圧の倉化が耳の䞭の小さな感芚領域に䌝わるずきに感じる感芚です。



たた、Sound APIを䜜成する䞻な目的は、適切なタむミングで適切な被隓者の耳に圧力波を䌝達するのに圹立぀コヌドを蚘述する手段を提䟛するこずです。



Javaのサりンドの皮類



  1. Java Sound APIは、䞻に2぀のタむプのオヌディオサりンドをサポヌトしおいたす。
  2. デゞタル化され、ファむルずしお盎接録音されたサりンド
  3. MIDIファむルずしお蚘録したす。 非垞に離れおいたすが、楜噚が垌望の順序で挔奏される楜譜に䌌おいたす。


これらのタむプは本質的にかなり異なりたす。ほずんどの堎合、倖郚゜ヌスからファむルに録音するためにデゞタル化する必芁があるサりンド、たたはそのようなファむルから以前に録音されたサりンドを再生するためにデゞタル化する必芁があるサりンドを扱っおいるため、最初に集䞭したす。



プレビュヌ



Java Sound APIは、 ラむンずミキサヌの抂念に基づいおいたす。



次

オヌディオミキサヌに適甚される音のアナログ衚珟の物理的および電気的特性に぀いお説明したす 。



最初のロックバンドのシナリオに戻りたす。この堎合、6぀のマむクず2぀のステレオスピヌカヌを䜿甚したす。 これは、オヌディオミキサヌの動䜜を理解するために必芁です。



次に、ラむン、ミキサヌ、オヌディオデヌタのフォヌマットなど、Java Soundプログラミングのトピックをいく぀か芋おいきたす。



SourceDataLine、Clip、Mixer、AudioFormatの各オブゞェクト間に存圚する関係を理解し​​、オヌディオを再生する簡単なプログラムを䜜成したす。



以䞋に、録音した音を録音しお再生するために䜿甚できるこのプログラムの䟋を瀺したす。



将来、この目的で䜿甚されるプログラムコヌドの完党な説明を提䟛したす。 しかし、このレッスンでは決しお完党ではありたせん。



コヌド䟋ず考慮事項



アナログサりンドの物理的および電気的特性



このレッスンの目的は、Java Sound APIを䜿甚したJavaプログラミングの基本を玹介するこずです。



Java Sound APIは、オヌディオミキサヌの抂念に基づいおいたす。これは、ロックコンサヌトから自宅でのCDの再生たで、ほずんどどこでもサりンドを再生するずきに䞀般的に䜿甚されるデバむスです。 しかし、オヌディオミキサヌの動䜜の詳现な説明に着手する前に、アナログサりンド自䜓の物理的および電気的特性を理解しおおくず圹立ちたす。



図を芋おください。 1







Vasya Pupyrkinはスピヌチを抌したす。



この図は、Vasyaが広域アドレスシステムず呌ばれるシステムを䜿甚しおスピヌチを行っおいる様子を瀺しおいたす。 このようなシステムは通垞、マむク、アンプ、スピヌカヌで構成されたす。 このシステムの目的は、Vasyaの声を匷化しお、倧勢の人でも聞こえるようにするこずです。



ぐら぀き



手短に蚀えば、Vasyaが話すず、声垯が空気粒子を喉頭で振動させたす。 これにより音波が発生し、それがマむクメンブレンを振動させ、Vasyaのオリゞナルの音の振動を正確にシミュレヌトする非垞に小さな振幅の電気振動に倉えたす。 アンプは、その名前が瀺すように、これらの電気振動を増幅したす。 その埌、スピヌカヌに到達したす。スピヌカヌは、増幅された電気振動を非垞に増幅された音波に逆倉換したすが、Vasya Pupyrkinの声垯で生成された同じ波を正確に繰り返したす。



ダむナミックマむク



それでは、図を芋おみたしょう。 図2は、ダむナミックず呌ばれるマむクデバむスの抂略図です。





図 2ダむナミックマむク回路



音の振動は膜に圱響したす



音の振動の圧力は、マむク内郚の柔軟な膜に䜜甚したす。 これにより膜が振動し、膜の振動が音波の振動を繰り返したす。



可動コむル



现いワむダヌのコむルがマむクのメンブレンに取り付けられおいたす。 膜が振動するず、コむルは匷力な氞久磁石で䜜られたコアの磁堎内で埀埩運動もしたす。 そしおファラデヌも確立したように、コむルに電流が発生したす。



電気信号は音波の圢に埓いたす。



したがっお、コむルに誘導された非垞に匱い電流から、亀互の電気信号が埗られ、マむクロホンの膜に䜜甚する音波の圢を繰り返したす。 さらに、亀流電圧の圢のこの信号は、図1の増幅噚の入力に䟛絊されたす。 1。



拡声噚



実際、スピヌカヌの動䜜原理はダむナミックマむクのデバむスを繰り返し、反察方向でのみオンになりたす。 圓然、この堎合、巻線ははるかに倪く、膜は増幅された信号での動䜜を保蚌するためにはるかに倧きくなりたす









ラりドスピヌカヌ膜の振動は空気粒子に圱響を䞎え、匷力な音波を䜜成したす。 これらの波の圢状は、Vasyaの声垯によっお䜜成されるはるかに䜎い匷床の音波の圢状を正確に繰り返したす。 しかし、新しい波の匷さは、Vasyaからの音の振動が倧勢の人の埌ろの列にさえ立っおいる人々の耳に届くようにするのに十分です。



ロックコンサヌト



この時たでに、あなたはこれがすべおJava Sound APIず䜕の関係があるのか​​ず疑問に思うかもしれたせん。 しかし、もう少し埅っおください。オヌディオミキサヌの基本的な仕組みを玹介しおいたす。



䞊蚘の回路は非垞にシンプルでした。 Vasya Pupyrkin、1぀のマむク、アンプ、スピヌカヌで構成されおいたした。 次に、図2の回路を考えたす。 4、最初の音楜グルヌプのロックコンサヌトのために準備されたステヌゞを提瀺したす。







6぀のマむクず2぀のスピヌカヌ



図 4぀の6぀のマむクがステヌゞ䞊にありたす。 ステヌゞの䞡偎に2぀のスピヌカヌスピヌカヌがありたす。 コンサヌトが始たるず、挔奏者は6぀のマむクのそれぞれで歌ったり、音楜を挔奏したりしたす。 したがっお、6぀の電気信号があり、それらを個別に増幅しおから䞡方のスピヌカヌに䟛絊する必芁がありたす。 これに加えお、挔奏者はさたざたなサりンド特殊効果、たずえばリバヌブを䜿甚できたす。リバヌブは、スピヌカヌに適甚する前に電気信号に倉換する必芁がありたす。



ステヌゞの䞡偎にある2぀のスピヌカヌは、ステレオサりンドの効果を䜜り出すように蚭蚈されおいたす。 ぀たり、右偎のステヌゞにあるマむクからの電気信号は、右偎にもあるスピヌカヌに萜ちたす。 同様に、巊偎のマむクからの信号は、シヌンの巊偎にあるスピヌカヌに送る必芁がありたす。 ただし、ステヌゞの䞭倮近くにある他のマむクからの電気信号は、適切な比率で䞡方のスピヌカヌに既に送信されおいるはずです。 たた、䞭倮の2぀のマむクは、䞡方のスピヌカヌに均等に信号を送信する必芁がありたす。



オヌディオミキサヌ



䞊蚘のタスクは、オヌディオミキサヌず呌ばれる電子デバむスによっお実行されたす。



音声回線チャンネル



著者はオヌディオミキサヌの専門家ではありたせんが、圌の謙虚な理解では、兞型的なオヌディオミキサヌは、それぞれの元のオヌディオ信号たたはラむンチャネルを衚す互いに独立した電気信号を䞀定数受信する胜力を持っおいたす。



オヌディオチャネルの抂念は、Java Sound APIを詳现に理解し始めるず非垞に重芁になりたす。



各オヌディオチャンネルの独立した凊理



いずれにせよ、暙準のオヌディオミキサヌには、他のチャンネルずは独立しお各オヌディオラむンを増幅する機胜がありたす。 たた、ミキサヌには通垞、たずえばオヌディオラむンのリバヌブなど、サりンドの特殊効果をスヌパヌむンポヌズする機胜がありたす。 最終的に、ミキサヌは、その名前が瀺すように、出力チャンネルぞの各オヌディオラむンの寄䞎を制埡するために、蚭定される出力チャンネルの個々の電気信号をすべおミックスできたすこのコントロヌルは通垞、パンたたはパンず呌ばれたす-空間での分垃。



ステレオサりンドに戻る



したがっお、図 4、オヌディオミキサヌのサりンド゚ンゞニアは、6぀のマむクからの信号を結合しお、それぞれがスピヌカヌに送信される2぀の出力信号を取埗するこずができたす。



操䜜を正垞に行うには、ステヌゞ䞊のマむクの物理的な䜍眮に応じお、各マむクからの信号を適切な割合で䟛絊する必芁がありたす。 パンニングを倉曎するこずにより、資栌のあるサりンド゚ンゞニアは、必芁に応じお、たずえばコンサヌト䞭にリヌドボヌカリストがステヌゞ内を移動する堎合に、各マむクの寄䞎を倉曎できたす。



プログラミングの䞖界に戻る時間



物理的な䞖界からプログラミングの䞖界に戻りたしょう。 Sunによるず、 「Java Soundには特別なハヌドりェア構成は含たれおいたせん。 さたざたなオヌディオコンポヌネントをシステムにむンストヌルし、APIを介しおナヌザヌが利甚できるように蚭蚈されおいたす。 Java Soundは、サりンドカヌドからの暙準の入力および出力機胜たずえば、オヌディオファむルの蚘録ず再生、および耇数のオヌディオストリヌムをミックスする機胜をサポヌトしおいたす。



ミキサヌずチャンネル



既に述べたように、Java Sound APIはミキサヌずチャンネルの抂念に基づいお構築されおいたす。 物理的な䞖界からプログラミングの䞖界に移行する堎合、Sunはミキサヌに関しお次のように蚘述したす。



「ミキサヌずは、1぀以䞊のチャンネルを持぀オヌディオデバむスです。 しかし、オヌディオ信号を実際にミキシングするミキサヌには、゜ヌス゜ヌスの耇数の入力チャネルず、少なくずも1぀の出力タヌゲットチャネルが必芁です。



入力行はSourceDataLineオブゞェクトを持぀クラスのむンスタンスにでき、出力行はTargetDataLineオブゞェクトにできたす。 ミキサヌは、事前に録音されルヌプされたサりンドを入力ずしお受け取り、その入力゜ヌスチャンネルをClipむンタヌフェむスを実装するクラスオブゞェクトのむンスタンスずしお定矩するこずもできたす。



チャネル回線むンタヌフェヌス。



Sunは、Lineむンタヌフェヌスから次のこずを報告したす。「 Lineは、入力たたは出力オヌディオポヌト、ミキサヌ、たたはミキサヌずの間のオヌディオパスなどのデゞタルオヌディオパむプラむンの芁玠です。 チャンネルを通過する音声デヌタは、モノたたはマルチチャンネルステレオなどです。 ...チャンネルには、ゲむン、パン、リバヌブなどのコントロヌルを蚭定できたす。



甚語をたずめる



したがっお、䞊蚘のSunからの匕甚は、次の甚語を意味しおいたした



゜ヌスデヌタラむン

タヌゲットゲタタリン

枯

クリップ

コントロヌル



図 図5は、これらの甚語を䜿甚しお簡単なオヌディオ出力プログラムを䜜成する䟋を瀺しおいたす。







プログラムスクリプト



゜フトりェアの芳点から 図5は、1぀のClipオブゞェクトず2぀のSourceDataLineオブゞェクトで取埗したMixerオブゞェクトを瀺しおいたす。



クリップずは



クリップは、ミキサヌの入力にあるオブゞェクトであり、その内容は時間ずずもに倉化したせん。 ぀たり、オヌディオデヌタを再生する前にClipオブゞェクトにロヌドしたす。 Clipオブゞェクトのオヌディオコンテンツは1回以䞊再生できたす。 クリップをルヌプバックするず、コンテンツが䜕床も再生されたす。



入力ストリヌム



䞀方、SourceDataLineオブゞェクトは、ミキサヌの入力にあるストリヌムオブゞェクトです。 このタむプのオブゞェクトは、オヌディオデヌタのストリヌムを受信し、リアルタむムでミキサヌに送信できたす。 必芁なオヌディオデヌタは、オヌディオファむル、ネットワヌク接続、メモリバッファなど、さたざたな゜ヌスから取埗できたす。



さたざたなタむプのチャネル



したがっお、ClipおよびSourceDataLineオブゞェクトは、Mixerオブゞェクトの入力チャネルず芋なすこずができたす。 これらの各入力チャンネルには、パン、ゲむン、リバヌブずいう独自のチャンネルを蚭定できたす。



オヌディオコンテンツを再生する



このような単玔なシステムでは、Mixerは入力ラむンからデヌタを読み取り、コントロヌルを䜿甚しお入力信号をミキシングし、スピヌカヌ、ラむン出力、ヘッドフォンゞャックなどの1぀以䞊の出力チャンネルに出力を提䟛したす。



リスト11は、マむクポヌトからオヌディオデヌタをキャプチャし、このデヌタをメモリに保存し、スピヌカヌポヌトから再生する単玔なプログラムを瀺しおいたす。



キャプチャず再生のみを説明したす。 䞊蚘のプログラムのほずんどは、ナヌザヌ甚のりィンドりずグラフィカルむンタヌフェむスを䜜成しお、蚘録ず再生を制埡できるようにするこずです。 この郚分に぀いおは、目暙を超えるものずしお説明したせん。 しかし、その埌、デヌタのキャプチャず再生を怜蚎したす。 このレッスンで負けを議論し、次のキャプチャを行いたす。 途䞭で、Java Sound APIでのオヌディオチャネルの䜿甚に぀いお説明したす。



キャプチャされたデヌタは、ByteArrayOutputStreamオブゞェクトに保存されたす。



コヌドスニペットコヌドスニペットは、マむクからオヌディオデヌタを読み取り、ByteArrayOutputStreamオブゞェクトずしお保存したす。



リスト1で始たるplayAudioずいうメ゜ッドは、キャプチャされおByteArrayOutputStreamオブゞェクトに保存されたオヌディオデヌタを再生したす。



private void playAudio() { try{ byte audioData[] = byteArrayOutputStream. toByteArray(); InputStream byteArrayInputStream = new ByteArrayInputStream( audioData);
      
      





リスト1



暙準コヌドから始めたす。



リスト1のプログラムのスニペットは、実際にはただJava Soundに関連しおいたせん。



その目的は次のずおりです。





これは、埌で再生するために音声デヌタを利甚可胜にするために必芁です。



Sound APIに移動する



リスト2のコヌド行は、すでにJava Sound APIに関連しおいたす。



  AudioFormat audioFormat = getAudioFormat();
      
      





リスト2



ここでは、このトピックに぀いお簡単に觊れたす。これに぀いおは、次のレッスンで詳しく説明したす。



2぀の独立した圢匏



ほずんどの堎合、オヌディオデヌタの2぀の独立した圢匏を扱っおいたす。



オヌディオデヌタを含むファむル圢匏任意デヌタはメモリに栌玍されるため、プログラムではただ䜜成されおいたせん



提出された音声デヌタの圢匏は、それ自䜓です。



オヌディオ圢匏ずは䜕ですか



Sunがそれに぀いお曞いおいるこずは次のずおりです。



「各デヌタチャネルには、デヌタストリヌムに関連付けられた独自のオヌディオ圢匏がありたす。 圢匏AudioFormatのむンスタンスは、オヌディオストリヌムのバむト順を決定したす。 圢匏パラメヌタヌは、チャネル数、サンプリング呚波数、量子化ビット、゚ンコヌド方法などです。通垞の゚ンコヌド方法は、PCMずその倉圢の線圢パルス笊号倉調です。



バむトシヌケンス



゜ヌスオヌディオデヌタは、バむナリデヌタのバむトシヌケンスです。 このシヌケンスを敎理および解釈する方法にはさたざたなオプションがありたす。 これらすべおのオプションを詳现に扱うこずはしたせんが、ここでプログラムで䜿甚するオヌディオ圢匏に぀いお少し説明したす。



䜙談



ここでは、今のずころplayAudioメ゜ッドをそのたたにしお、リスト2のgetAudioFormatメ゜ッドを芋おください。



完党なgetAudioFormatメ゜ッドをリスト3に瀺したす。



  private AudioFormat getAudioFormat(){ float sampleRate = 8000.0F; int sampleSizeInBits = 16; int channels = 1; boolean signed = true; boolean bigEndian = false; return new AudioFormat( sampleRate, sampleSizeInBits, channels, signed, bigEndian); }//end getAudioFormat
      
      





リスト3



初期化された倉数の宣蚀に加えお、リスト3のコヌドには1぀の実行可胜匏が含たれおいたす。



AudioFormatオブゞェクト



getAudioFormatメ゜ッドは、AudioFormatクラスのオブゞェクトのむンスタンスを䜜成しお返したす。 Sunはこのクラスに぀いお次のように曞いおいたす。



「AudioFormatクラスは、オヌディオストリヌム内のデヌタの特定の順序を定矩したす。 AudioFormatオブゞェクトのフィヌルドを参照するず、バむナリデヌタストリヌムのビットを正しく解釈する方法に関する情報を取埗できたす。



最も単玔なコンストラクタヌを䜿甚したす



AudioFormatクラスには2皮類のコンストラクタヌがありたす最も単玔なコンストラクタヌを䜿甚したす。 このコンストラクタヌには次のパラメヌタヌが必芁です。





リスト3を芋るずわかるように、今回のケヌスでは、AudioFormatオブゞェクトのむンスタンスに次のパラメヌタヌを䜿甚したした。





デフォルトでは、デヌタはリニアPCMで゚ンコヌドされたす。



䜿甚したコンストラクタヌは、線圢パルスコヌド倉調ず䞊蚘のパラメヌタヌを䜿甚しおAudioFormatオブゞェクトのむンスタンスを䜜成したす次のレッスンでは線圢PCMおよびその他の゚ンコヌド方法に戻りたす



再びplayAudioメ゜ッドに戻る



Javaサりンドでオヌディオデヌタ圢匏がどのように機胜するかを理解したので、playAudioメ゜ッドに戻りたしょう。 䜿甚可胜なオヌディオデヌタを再生する堎合、AudioInputStreamクラスのオブゞェクトが必芁になりたす。 リスト4でそのむンスタンスを取埗したす。



  audioInputStream = new AudioInputStream( byteArrayInputStream, audioFormat, audioData.length/audioFormat. getFrameSize());
      
      





リスト4



AudioInputStreamコンストラクタヌのパラメヌタヌ





フレヌムサむズを取埗



リスト4からわかるように、3番目のパラメヌタヌの倀は蚈算を䜿甚しお䜜成されたす。 これは、これたで蚀及しおいないオヌディオ圢匏の属性の1぀にすぎず、フレヌムず呌ばれたす。



フレヌムずは䜕ですか



プログラムで䜿甚されおいる単玔な線圢PCMの堎合、フレヌムには、特定の時間のすべおのチャネルのサンプルのセットが含たれおいたす。



したがっお、フレヌムサむズは、バむト単䜍のカりントサむズにチャネル数を掛けたものに等しくなりたす。



ご想像のずおり、getFrameSizeずいうメ゜ッドはフレヌムサむズをバむト単䜍で返したす。



フレヌムサむズの蚈算



したがっお、フレヌム内のオヌディオデヌタの長さは、オヌディオデヌタシヌケンス内の合蚈バむト数を1フレヌム内のバむト数で陀算するこずによっお蚈算できたす。 この蚈算は、リスト4の3番目のパラメヌタヌに䜿甚されたす。



SourceDataLineオブゞェクトの取埗



次に説明するプログラムの次の郚分は、単玔なオヌディオ出力システムです。 図5の図からわかるように、この問題を解決するにはSourceDataLineオブゞェクトが必芁です。



SourceDataLineオブゞェクトのむンスタンスを取埗する方法はいく぀かありたすが、そのすべおが非垞に泚意が必芁です。 リスト5のコヌドは、SourceDataLineオブゞェクトのむンスタンスぞの参照を取埗しお保存したす。



このコヌドはSourceDataLineオブゞェクトをむンスタンス化するだけではありたせん。それはかなり遠回りの方法で取埗したす。



  DataLine.Info dataLineInfo = new DataLine.Info( SourceDataLine.class, audioFormat); sourceDataLine = (SourceDataLine) AudioSystem.getLine( dataLineInfo);
      
      





リスト5



SourceDataLineオブゞェクトずは䜕ですか



これに぀いお、サンは次のように曞いおいたす。



「SourceDataLineは、デヌタを曞き蟌むこずができるデヌタチャネルです。 ミキサヌの入力ずしお機胜したす。 アプリケヌションは、バむトシヌケンスをSourceDataLineに曞き蟌みたす。SourceDataLineは、デヌタをバッファリングし、ミキサヌに配信したす。 ミキサヌは、次のステヌゞで凊理するデヌタを、たずえば出力ポヌトに送信できたす。



このペアリングの呜名芏則は、チャネルずミキサヌの関係を反映しおいるこずに泚意しおください。



AudioSystemクラスのGetLineメ゜ッド



SourceDataLineオブゞェクトのむンスタンスを取埗する方法の1぀は、AudioSystemクラスから静的なgetLineメ゜ッドを呌び出すこずですこれに぀いおは、次のレッスンで詳しく報告したす。



getLineメ゜ッドは、Line.Info型の入力パラメヌタヌを必芁ずし、既に定矩されおいるLine.Infoオブゞェクトの説明ず䞀臎するLineオブゞェクトを返したす。



別の短い䜙談



Sunは、Line.Infoオブゞェクトに関する次の情報を報告したす。



「チャネルには独自の情報オブゞェクトLine.Infoのむンスタンスがありたす。このオブゞェクトは、混合オヌディオデヌタを出力ずしおチャネルに盎接送信するミキサヌ存圚する堎合ず、チャネルから盎接入力ずしおオヌディオデヌタを受信するミキサヌ存圚する堎合を瀺したす。 Lineの皮類はLine.Infoのサブクラスに察応できたす。これにより、特定のタむプのチャネルに関連する他のタむプのパラメヌタヌを指定できたす。



DataLine.Infoオブゞェクト



リスト5の最初の匏は、DataLine.Infoオブゞェクトの新しいむンスタンスを䜜成したす。これは、Line.Infoオブゞェクトの特別な圢匏サブクラスです。



DataLine.Infoクラスには、オヌバヌロヌドされたコンストラクタヌがいく぀かありたす。 最も䜿いやすいものを遞択したした。 このコンストラクタヌには2぀のパラメヌタヌが必芁です。



クラスオブゞェクト



最初のパラメヌタヌはClassです。これは、SourceDataLine.classずしお定矩したクラスを衚したす



2番目のパラメヌタヌは、チャネルに必芁なデヌタ圢匏を決定したす。 既に定矩枈みのAudioFormatオブゞェクトのむンスタンスを䜿甚したす。



すでに必芁な堎所にいたすか



残念ながら、最も必芁なSourceDataLineオブゞェクトはただありたせん。 これたでのずころ、必芁なSourceDataLineオブゞェクトに関する情報のみを提䟛するオブゞェクトがありたす。



SourceDataLineオブゞェクトの取埗



リスト5の2番目の匏は、最終的に必芁なSourceDataLineのむンスタンスを䜜成しお保存したす。 これは、AudioSystemクラスの静的getLineメ゜ッドを呌び出し、dataLineInfoをパラメヌタヌずしお枡すこずで発生したす。 次のレッスンでは、Lineオブゞェクトを取埗する方法を芋お、Mixerオブゞェクトを盎接操䜜したす。



getLineメ゜ッドは、SourceDataLineの芪であるLine型のオブゞェクトぞの参照を返したす。 したがっお、戻り倀がSourceDataLineずしお保存される前に、ここでダりンキャストが必芁です。



SourceDataLineオブゞェクトを䜿甚する準備をしたしょう



SourceDataLineオブゞェクトのむンスタンスを取埗したら、リスト6に瀺すように、それを開いお実行する準備をする必芁がありたす。



  sourceDataLine.open(audioFormat); sourceDataLine.start();
      
      





リスト6



開封方法



リスト6からわかるように、AudioFormatオブゞェクトをSourceDataLineオブゞェクトのopeningメ゜ッドに送信したした。



Sunによるず、これはメ゜ッドです。



「以前に定矩された圢匏で回線チャネルを開き、必芁なシステムリ゜ヌスを受け取り、䜜業䜜業状態にできるようにしたす。」



ディスカバリヌ状態



このスレッドでは、Sunが圌に぀いお曞いたこずはほずんどありたせん。



「チャネルの開閉は、システムリ゜ヌスの分配に圱響したす。 チャネルを正垞に開くず、必芁なすべおのリ゜ヌスがチャネルに提䟛されたす。



オヌディオデヌタの入力ポヌトず出力ポヌトがあるミキサヌを開くには、ずりわけ、必芁な゜フトりェアコンポヌネントの䜜業ず初期化が行われるプラットフォヌムのハヌドりェアの䜿甚が含たれたす。



ミキサヌぞの、たたはミキサヌからのオヌディオデヌタのルヌトであるチャンネルを開くには、ミキサヌリ゜ヌスの無制限の初期化ず受信の䞡方が含たれたす。 ぀たり、ミキサヌのチャンネル数には限りがあるため、独自のチャンネルニヌズを持぀アプリケヌションおよび1぀のアプリケヌションでさえもがミキサヌリ゜ヌスを正しく共有する必芁がありたす ''



チャネルでstartメ゜ッドを呌び出したす



Sunによるず、チャネルのstartメ゜ッドを呌び出すず、次のこずを意味したす。



「チャネルはI / Oラむンを䜿甚できたす。 すでに動䜜しおいる回線を䜿甚しようずするず、メ゜ッドは䜕もしたせん。 しかし、デヌタバッファヌが空になった埌、バッファヌが完党に読み蟌たれた埌に凊理できなかった最初のフレヌムから、I / Oの開始が再開されたす。



もちろん、この堎合、チャネルは停止したせんでした。 初めお発売しお以来。



これで必芁なものはほがすべお揃った



この時点で、以前に録音しおByteArrayOutputStreamオブゞェクトのむンスタンスに保存したオヌディオデヌタを再生するために必芁なすべおのオヌディオリ゜ヌスを受け取りたした。 このオブゞェクトはコンピュヌタヌのRAMにのみ存圚するこずを思い出しおください。



フロヌを開始したす



ストリヌムを䜜成しお開始し、オヌディオを再生したす。 リスト7のコヌドは、このスレッドを䜜成しお開始したす。



このスレッドのstartメ゜ッドの呌び出しず、リスト6のSourceDataLineオブゞェクトのstartメ゜ッドの呌び出しを混同しないでください。これらはたったく異なる操䜜です



 Thread playThread = new Thread(new PlayThread()); playThread.start(); } catch (Exception e) { System.out.println(e); System.exit(0); }//end catch }//end playAudio
      
      





リスト7



気取らないコヌド



リスト7のプログラムのスニペットは、非垞に単玔ですが、Javaでのマルチスレッドプログラミングの䟋を瀺しおいたす。 理解できない堎合は、Javaを孊習するための専門的なトピックでこのトピックに粟通しおください。



ストリヌムが開始されるず、事前に録音されたすべおのオヌディオデヌタが最埌たで再生されるたで動䜜したす。



新しいスレッドオブゞェクト



リスト7のコヌドは、PlayThreadクラスに属するThreadオブゞェクトのむンスタンスを䜜成したす。 このクラスは、プログラムの内郚クラスずしお定矩されおいたす。 その説明はリスト8から始たりたす。



 class PlayThread extends Thread{ byte tempBuffer[] = new byte[10000];
      
      





リスト8



Threadクラスのrunメ゜ッド



tempBuffer倉数バむトの配列を参照を宣蚀するこずを陀いお、このクラスの完党な定矩は、単にrunメ゜ッドの定矩です。 既にご存じのずおり、Threadオブゞェクトでstartメ゜ッドを呌び出すず、このオブゞェクトのrunメ゜ッドが実行されたす



このスレッドのrunメ゜ッドはリスト9から始たりたす。



 public void run(){ try{ int cnt; //  //    -1 // while((cnt = audioInputStream. read(tempBuffer, 0, tempBuffer.length)) != -1){ if(cnt > 0){ //   //    //    //   . sourceDataLine.write( tempBuffer, 0, cnt); }//end if }//end while
      
      





リスト9



runメ゜ッドのプログラムフラグメントの最初の郚分



runメ゜ッドには2぀の重芁な郚分が含たれおいたす。最初の郚分をリスト9に瀺したす。



぀たり、ここではルヌプを䜿甚しおAudioInputStreamからオヌディオデヌタを読み取り、SourceDataLineに枡したす。



SourceDataLineオブゞェクトに送信されたデヌタは、デフォルトのオヌディオ出力に自動的に転送されたす。 内蔵のコンピュヌタヌスピヌカヌたたはラむン出力を䜿甚できたす。 次のレッスンで必芁なサりンドデバむスを決定する方法を孊習したす。 cnt倉数ずtempBufferデヌタバッファヌは、読み取り操䜜ず曞き蟌み操䜜の間のデヌタの流れを制埡するために䜿甚されたす。



AudioInputStreamからのデヌタの読み取り



AudioInputStreamオブゞェクトからの読み取りサむクルは、指定された最倧バむト数のデヌタをAudioInputStreamから読み取り、そのバむト配列を配眮したす。



戻り倀



さらに、このメ゜ッドは読み取られたバむトの合蚈数を返したす。蚘録されたシヌケンスの終わりに達した堎合は-1を返したす。 読み取られたバむト数は、cnt倉数に栌玍されたす。



SourceDataLine曞き蟌みルヌプ



読み取られたバむト数がれロより倧きい堎合、SourceDataLineにデヌタを曞き蟌むサむクルぞの移行がありたす。 このルヌプでは、オヌディオデヌタがミキサヌに入りたす。 バむトは、むンデックスに埓っおバむト配列から読み取られ、チャネルバッファに曞き蟌たれたす。



入力ストリヌムが也燥したずき



読み取りルヌプが-1を返すずき、これは以前に蚘録されたすべおのオヌディオデヌタが終了し、さらに制埡がリスト10のプログラムフラグメントに枡されるこずを意味したす。



  sourceDataLine.drain(); sourceDataLine.close(); }catch (Exception e) { System.out.println(e); System.exit(0); }//end catch }//end run }//   PlayThread
      
      





リスト10



ロックしお埅぀



リスト10のコヌドは、SourceDataLineオブゞェクトのdrainメ゜ッドを呌び出しお、プログラムがブロックし、SourceDataLineで内郚バッファヌが空になるのを埅機できるようにしたす。 バッファヌが空の堎合、次の郚分党䜓がコンピュヌタヌの音声出力に配信されるこずを意味したす。



SourceDataLineを閉じる



次に、プログラムはcloseメ゜ッドを呌び出しおチャネルを閉じたす。これにより、チャネルが䜿甚するすべおのシステムリ゜ヌスが解攟されたこずを瀺したす。 Sunは、次のチャネル閉鎖を報告しおいたす。



「チャネルを閉じるず、このチャネルに関連するすべおのリ゜ヌスが解攟できるこずを瀺したす。 リ゜ヌスを解攟するには、アプリケヌションが終了したずきだけでなく、すでに関䞎しおいるかどうかに関係なく、アプリケヌションはチャネルを閉じる必芁がありたす。 ミキサヌはシステムリ゜ヌスを共有し、繰り返し閉じたり開いたりできるず想定されおいたす。 他のチャネルは、閉じた埌の再開をサポヌトする堎合ずしない堎合がありたす。 䞀般に、線を開くメカニズムは、サブタむプによっお異なりたす。



そしお今、物語の終わり



そこで、ここでは、コンピュヌタヌの内郚メモリからサりンドカヌドぞのオヌディオデヌタの配信を保蚌するために、プログラムがJava Sound APIを䜿甚する方法に぀いお説明したした。



プログラムを実行する



これで、リスト11のプログラムをコンパむルしお実行できるようになり、レッスンの最埌になりたす。



オヌディオデヌタをキャプチャしお再生する



このプログラムは、マむクからデヌタを蚘録し、コンピュヌタヌのサりンドカヌドを介しお再生する機胜を瀺しおいたす。 䜿甚方法は非垞に簡単です。



プログラムを実行したす。 図6に瀺すシンプルなGUI GUIが画面に衚瀺されたす。









䜕も聞こえない堎合は、マむクの感床たたはスピヌカヌの音量を䞊げおみおください。



プログラムはコンピュヌタのメモリにレコヌドを保存したすので、泚意しおください。 オヌディオデヌタを倧量に保存しようずするず、RAMが䞍足する可胜性がありたす。



おわりに





次は



このチュヌトリアルでは、Java Sound APIはミキサヌずチャンネルの抂念に基づいおいるこずがわかりたした。 ただし、説明したコヌドにはミキサヌが明瀺的に含たれおいたせんでした。 AudioSystemクラスは、ミキサヌに盎接アクセスせずにオヌディオ凊理プログラムを䜜成できる静的メ゜ッドを提䟛したした。 ぀たり、これらの静的メ゜ッドはミキサヌを私たちから遠ざけたす。



次のレッスンでは、このレッスンで瀺したものず比范しお倉曎されたデヌタキャプチャコヌドを瀺したす。新しいバヌゞョンでは、本圓に必芁なずきにミキサヌを䜿甚する方法を瀺すために、ミキサヌを明瀺的に䜿甚したす。



 import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import javax.sound.sampled.*; public class AudioCapture01 extends JFrame{ boolean stopCapture = false; ByteArrayOutputStream byteArrayOutputStream; AudioFormat audioFormat; TargetDataLine targetDataLine; AudioInputStream audioInputStream; SourceDataLine sourceDataLine; public static void main( String args[]){ new AudioCapture01(); }//end main public AudioCapture01(){ final JButton captureBtn = new JButton("Capture"); final JButton stopBtn = new JButton("Stop"); final JButton playBtn = new JButton("Playback"); captureBtn.setEnabled(true); stopBtn.setEnabled(false); playBtn.setEnabled(false); captureBtn.addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent e){ captureBtn.setEnabled(false); stopBtn.setEnabled(true); playBtn.setEnabled(false); //  //   //   Stop captureAudio(); } } ); getContentPane().add(captureBtn); stopBtn.addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent e){ captureBtn.setEnabled(true); stopBtn.setEnabled(false); playBtn.setEnabled(true); //  //    stopCapture = true; } } ); getContentPane().add(stopBtn); playBtn.addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent e){ //  //    playAudio(); } } ); getContentPane().add(playBtn); getContentPane().setLayout( new FlowLayout()); setTitle("Capture/Playback Demo"); setDefaultCloseOperation( EXIT_ON_CLOSE); setSize(250,70); setVisible(true); } //    //     //   ByteArrayOutputStream private void captureAudio(){ try{ //    audioFormat = getAudioFormat(); DataLine.Info dataLineInfo = new DataLine.Info( TargetDataLine.class, audioFormat); targetDataLine = (TargetDataLine) AudioSystem.getLine( dataLineInfo); targetDataLine.open(audioFormat); targetDataLine.start(); //     //    //   //    Thread captureThread = new Thread( new CaptureThread()); captureThread.start(); } catch (Exception e) { System.out.println(e); System.exit(0); } } //    // ,    //  ByteArrayOutputStream private void playAudio() { try{ //  //  byte audioData[] = byteArrayOutputStream. toByteArray(); InputStream byteArrayInputStream = new ByteArrayInputStream( audioData); AudioFormat audioFormat = getAudioFormat(); audioInputStream = new AudioInputStream( byteArrayInputStream, audioFormat, audioData.length/audioFormat. getFrameSize()); DataLine.Info dataLineInfo = new DataLine.Info( SourceDataLine.class, audioFormat); sourceDataLine = (SourceDataLine) AudioSystem.getLine( dataLineInfo); sourceDataLine.open(audioFormat); sourceDataLine.start(); //    //     //     //      Thread playThread = new Thread(new PlayThread()); playThread.start(); } catch (Exception e) { System.out.println(e); System.exit(0); } } //     //  AudioFormat private AudioFormat getAudioFormat(){ float sampleRate = 8000.0F; //8000,11025,16000,22050,44100 int sampleSizeInBits = 16; //8,16 int channels = 1; //1,2 boolean signed = true; //true,false boolean bigEndian = false; //true,false return new AudioFormat( sampleRate, sampleSizeInBits, channels, signed, bigEndian); } //===================================// //    //    class CaptureThread extends Thread{ byte tempBuffer[] = new byte[10000]; public void run(){ byteArrayOutputStream = new ByteArrayOutputStream(); stopCapture = false; try{ while(!stopCapture){ int cnt = targetDataLine.read( tempBuffer, 0, tempBuffer.length); if(cnt > 0){ //     byteArrayOutputStream.write( tempBuffer, 0, cnt); } } byteArrayOutputStream.close(); }catch (Exception e) { System.out.println(e); System.exit(0); } } } //===================================// //   //     class PlayThread extends Thread{ byte tempBuffer[] = new byte[10000]; public void run(){ try{ int cnt; //     -1 while((cnt = audioInputStream. read(tempBuffer, 0, tempBuffer.length)) != -1){ if(cnt > 0){ //    //   //    //    sourceDataLine.write( tempBuffer, 0, cnt); } } sourceDataLine.drain(); sourceDataLine.close(); }catch (Exception e) { System.out.println(e); System.exit(0); } } } //===================================// }//end outer class AudioCapture01.java
      
      





リスト11



All Articles