レトロなゲヌムから効果音のシンセサむザヌを䜜成する

画像

この蚘事では、レトロスタむルのゲヌム甚のサりンドを生成できるシンセサむザヌベヌスのオヌディオ゚ンゞンを䜜成する方法を孊びたす。 サりンド゚ンゞンは実行時にすべおのサりンドを生成し、MP3やWAVファむルなどの倖郚䟝存関係を必芁ずしたせん。 最終的に、ゲヌムに䟿利に埋め蟌むこずができる䜜業ラむブラリを取埗したす。

オヌディオ゚ンゞンの䜜成を開始する前に、いく぀かの抂念に察凊する必芁がありたす。 たず、゚ンゞンが音を生成するために䜿甚する波に぀いお。 次に、音波がデゞタル圢匏でどのように保存されラベル付けされるかを理解する必芁がありたす。

このチュヌトリアルでは、ActionScript 3.0プログラミング蚀語を䜿甚したすが、䜿甚する手法ず抂念は、䜎レベルオヌディオAPIぞのアクセスを提䟛する他の蚀語に簡単に倉換できたす。



æ³¢


䜜成するオヌディオ゚ンゞンは、4぀の基本的な皮類の波基本的な圢匏が定期的に繰り返されるため、 呚期的な波ずも呌ばれたすを䜿甚したす。 それらはすべお、アナログシンセサむザヌずデゞタルシンセサむザヌの䞡方で非垞に頻繁に䜿甚されたす。 各波圢には独自のサりンド特性がありたす。

以䞋は、各波圢の芖芚的衚珟、サりンドの䟋、および各波圢をサンプリングされたデヌタの配列ずしお生成するために必芁なコヌドです。

パルス




パルス波は、シャヌプで調和の取れた音を䜜成したす。

MP3をダりンロヌドしたす。

配列のパルス波-1.0〜1.0の範囲を衚す倀を生成するには、次のコヌドを䜿甚できたすnは配列を満たすのに必芁な倀の数、 aは配列、 pは波内の正芏化された䜍眮です。

 var i:int = 0; var n:int = 100; var p:Number; while( i < n ) { p = i / n; a[i] = p < 0.5 ? 1.0 : -1.0; i ++; } 

芋た




のこぎり波は、シャヌプで耳障りな音を䜜りたす。

MP3をダりンロヌドしたす。

ノコギリ波-1.0から1.0の範囲を衚す倀の配列を生成するには、 nは配列を満たすのに必芁な倀の数、 aは配列、 pは波内の正芏化された䜍眮です。

 var i:int = 0; var n:int = 100; var p:Number; while( i < n ) { p = i / n; a[i] = p < 0.5 ? p * 2.0 : p * 2.0 - 2.0; i ++; } 


正匊波




正匊波は、滑らかでクリアなサりンドを䜜成したす。

MP3をダりンロヌドしたす。

正匊波-1.0〜1.0の範囲を衚す倀の配列を生成するには、次のコヌドを䜿甚できたすnは配列を満たすために必芁な倀の数、 aは配列、 pは波内の正芏化された䜍眮です。

 var i:int = 0; var n:int = 100; var p:Number; while( i < n ) { p = i / n; a[i] = Math.sin( p * 2.0 * Math.PI ); i ++; } 

トラむアングル




䞉角波は滑らかで調和のずれた音を䜜りたす。

MP3をダりンロヌドしたす。

䞉角波-1.0から1.0の範囲を衚す倀の配列を生成するには、次のコヌドを䜿甚できたすnは配列を満たすために必芁な倀の数、 aは配列、 pは波内の正芏化された䜍眮です。

 var i:int = 0; var n:int = 100; var p:Number; while( i < n ) { p = i / n; a[i] = p < 0.25 ? p * 4.0 : p < 0.75 ? 2.0 - p * 4.0 : p * 4.0 - 4.0; i ++; } 

6行目の拡匵バヌゞョンは次のずおりです。

 if (p < 0.25) { a[i] = p * 4.0; } else if (p < 0.75) { a[i] = 2.0 - (p * 4.0); } else { a[i] = (p * 4.0) - 4.0; } 



波の振幅ず呚波数


音波には2぀の重芁な特性がありたす-波の振幅ず呚波数  ボリュヌムずピッチはそれぞれ、それらに䟝存したす。 振幅は波の絶察ピヌク倀であり、呚波数は波が1秒間に繰り返す回数です。 通垞、呚波数はヘルツHz、Hzで枬定されたす。

次の図は、振幅が0.5、呚波数が20 Hzののこぎり波の200ミリ秒のスナップショットを瀺しおいたす。



波の呚波数がピッチに盎接どのように圱響するかの䟋を瀺したす。呚波数が440 Hzの波は、珟代のコンサヌトピアノの最初のオクタヌブA4の暙準音ず同じ高さです。 この頻床を考えるず、次のコヌドを䜿甚しお他のノヌトの頻床を蚈算できたす。

 f = Math.pow( 2, n / 12 ) * 440.0; 

このコヌドの倉数nは、A4から察象のノヌトたでのノヌトの数です。 たずえば、2オクタヌブA5の呚波数A4より1オクタヌブ高いを芋぀けるには、A5がA4より12音高いため、 nを12に蚭定する必芁がありたす。 倧きなオクタヌブE2のmi呚波数を芋぀けるには、E2がA4の5ノヌト䞋にあるため、 nに-5倀を割り圓おる必芁がありたす。 たた、逆の操䜜を行っお、特定の頻床でA4に関連するノヌトを芋぀けるこずもできたす。

 n = Math.round( 12.0 * Math.log( f / 440.0 ) * Math.LOG2E ); 

これらの蚈算は、音の呚波数が察数であるため機胜したす。呚波数を2倍するず音が1オクタヌブ䞊にシフトし、2で陀算するず1オクタヌブ音が䜎くなりたす。



デゞタル音波


デゞタルの䞖界では、音波はバむナリデヌタずしお保存する必芁があり、これは通垞、音波の状態たたはサンプルの定期的なスナップショットを䜜成するこずによっお行われたす。 音の持続時間の1秒ごずに受信される波のサンプルの数は、サンプリング呚波数ず呌ばれたす 。぀たり、サンプリング呚波数44100の音には、音の持続時間の1秒あたり44100の波のサンプルが含たれたす。

以䞋の図は、音波をサンプリングする方法を瀺しおいたす。



図の癜い点は、サンプリングされおデゞタル圢匏で保存された波の振幅ポむントを瀺しおいたす。 ビットマップの解像床ずしおそれらを䜿甚できたすビットマップにピクセルが倚いほど、栌玍できる芖芚情報が倚くなり、情報量が増えるずファむルサむズが倧きくなりたすここでは圧瞮を考慮したせん。 同じこずがデゞタルサりンドにも圓おはたりたす。サりンドファむルに含たれるりェヌブサンプルが倚いほど、再珟されるサりンドりェヌブはより正確になりたす。

サンプリング呚波数に加えお、デゞタルサりンドにはビット/秒で枬定されるビットレヌトもありたす。 ビットレヌトビットレヌトは、各波圢サンプルの保存に䜿甚されるバむナリビットの数によっお異なりたす。 これは、ビットマップの各ピクセルのARGB情報を栌玍するために䜿甚されるビット数に䌌おいたす。 たずえば、サンプリング呚波数が44100でビットレヌトが705600のサりンドは、各波のサンプルを16ビット倀ずしお保存したす。次のコヌドを䜿甚するず、非垞に簡単に蚈算できたす。

 bitsPerSample = bitRate / sampleRate; 

䞊蚘の倀を䜿甚する実甚的な䟋を次に瀺したす。

 trace( 705600 / 44100 ); // "16" 

ここで最も重芁なこずは、サりンドサンプルずは䜕かを理解するこずです。 䜜成する゚ンゞンは、生のサりンドサンプルを生成および操䜜したす。



倉調噚


サりンド゚ンゞンのプログラミングを開始する前に、アナログシンセサむザヌずデゞタルシンセサむザヌの䞡方で積極的に䜿甚されおいる倉調噚ずいう別の抂念を理解する必芁がありたす。 本質的に、倉調噚は暙準的な波ですが、通垞は音を䜜成する代わりに、音波の1぀たたは耇数のプロパティ぀たり、振幅たたは呚波数を倉調するために䜿甚されたす。

たずえば、 vibratoを䜿甚したす。 ビブラヌトは、呚期的に脈動する高さの倉化です。 倉調噚を䜿甚しおこのような効果を䜜成するには、正匊波の倉調波を蚭定し、倉調呚波数をたずえば8 Hzに蚭定したす。 その埌、この倉調噚を音波の呚波数に接続するず、ビブラヌト効果が埗られたす。倉調噚は、音波の呚波数高さを1秒間に8回埐々に増枛させたす。

䜜成する゚ンゞンにより、モゞュレヌタヌをサりンドにアタッチしお、さたざたな゚フェクトを幅広く提䟛できたす。



デモオヌディオ゚ンゞン


このパヌトでは、完党なオヌディオ゚ンゞンに必芁なすべおの基本コヌドを蚘述したす。 オヌディオ゚ンゞンFlashの簡単なデモを次に瀺したす。demo 。

このデモでは、1぀のサりンドのみが再生されたすが、サりンドの呚波数はランダムに倉化したす。 モゞュレヌタヌもサりンドに接続され、ビブラヌト効果を䜜成したすサりンドの振幅を倉調するこずにより。モゞュレヌタヌの呚波数もランダムに倉化したす。



クラスAudioWaveform


最初に䜜成するクラスは、゚ンゞンがサりンドを生成するために䜿甚するりェヌブの定数倀を保存するだけです。

noiseずいう新しいクラスパッケヌゞを䜜成しおから、次のクラスをこのパッケヌゞに远加したす。

 package noise { public final class AudioWaveform { static public const PULSE:int = 0; static public const SAWTOOTH:int = 1; static public const SINE:int = 2; static public const TRIANGLE:int = 3; } } 

たた、クラスに静的な䞀般メ゜ッドを远加したす。これは、波の倀を確認するために䜿甚できたす。 このメ゜ッドは、波の倀の正確さに応じおtrueたたはfalseを返したす。

 static public function validate( waveform:int ):Boolean { if( waveform == PULSE ) return true; if( waveform == SAWTOOTH ) return true; if( waveform == SINE ) return true; if( waveform == TRIANGLE ) return true; return false; } 

最埌に、クラスを䜜成する理由がないため、クラスをむンスタンス化から保護する必芁がありたす。 これはクラスコンストラクタヌ内で実行できたす。

 public function AudioWaveform() { throw new Error( "AudioWaveform class cannot be instantiated" ); } 

これで、クラスの䜜成が完了したした。

列挙型のクラス、完党に静的なクラス、およびシングルトンクラスを盎接むンスタンス化しないように保護するこずをお勧めしたす。そのようなクラスのむンスタンスは䜜成しないでください。これには理由がありたせん。 Javaなどの䞀郚のプログラミング蚀語では、これらのタむプのクラスのほずんどでこれは自動的に行われたすが、ActionScript 3.0では、クラスコンストラクタヌ内でこの動䜜を匷制する必芁がありたす。



オヌディオクラス


リストの次はAudioクラスです。 その性質䞊、このクラスはネむティブActionScript 3.0 Soundクラスに䌌おおり、各オヌディオ゚ンゞンはAudioクラスのむンスタンスずしお提瀺されたす。

次のスケルトンをnoiseパッケヌゞに远加したす。

 package noise { public class Audio { public function Audio() {} } } 

クラスに最初に远加する必芁があるのは、サりンドを再生するずきにオヌディオ゚ンゞンにサりンドりェヌブを生成する方法を䌝えるプロパティです。 これらのプロパティは、サりンドで䜿甚される波の皮類、波の呚波数ず振幅、音の持続時間、枛衰時間です。 これらのプロパティはすべおプラむベヌトであり、それらぞのアクセスはゲッタヌ/セッタヌを介しお行われたす。

 private var m_waveform:int = AudioWaveform.PULSE; private var m_frequency:Number = 100.0; private var m_amplitude:Number = 0.5; private var m_duration:Number = 0.2; private var m_release:Number = 0.2; 

ご芧のずおり、各プロパティに適切なデフォルト倀を蚭定しおいたす。 amplitudeは0.0の範囲の倀で、 frequency Hz単䜍で、 durationずreleaseは秒単䜍です。

たた、サりンドに接続されたモゞュレヌタヌのプラむベヌトプロパティを2぀远加する必芁がありたす。 これらのプロパティぞのアクセスは、ゲッタヌ/セッタヌ経由でも行われたす。

 private var m_frequencyModulator:AudioModulator = null; private var m_amplitudeModulator:AudioModulator = null; 

最埌に、 Audioクラスには、 AudioEngineクラスのみがアクセスできるいく぀かの内郚プロパティが含たれおいる必芁がありたすすぐに蚘述したす。 これらのプロパティは、ゲッタヌ/セッタヌの埌ろに隠す必芁はありたせん。

 internal var position:Number = 0.0; internal var playing:Boolean = false; internal var releasing:Boolean = false; internal var samples:Vector.<Number> = null; 

positionは秒単䜍で蚭定され、 AudioEngineクラスAudioEngine再生䞭のサりンドの䜍眮AudioEngine远跡できるようにしたす。 これは、音波サンプルを蚈算するために必芁です。 playingずreleasingは、 AudioEngineクラスにサりンドの状態releasing䌝え、 samplesプロパティは、サりンドで䜿甚されるキャッシュされたりェヌブサンプルぞの参照です。 これらのプロパティの䜿甚方法は、 AudioEngineクラスを蚘述するずきにわかりたす。

Audioクラスを終了するには、ゲッタヌ/セッタヌを远加する必芁がありたす。

Audio. waveform

 public final function get waveform():int { return m_waveform; } public final function set waveform( value:int ):void { if( AudioWaveform.isValid( value ) == false ) { return; } switch( value ) { case AudioWaveform.PULSE: samples = AudioEngine.PULSE; break; case AudioWaveform.SAWTOOTH: samples = AudioEngine.SAWTOOTH; break; case AudioWaveform.SINE: samples = AudioEngine.SINE; break; case AudioWaveform.TRIANGLE: samples = AudioEngine.TRIANGLE; break; } m_waveform = value; } 

Audio. frequency

 [Inline] public final function get frequency():Number { return m_frequency; } public final function set frequency( value:Number ):void { //  frequency  1.0 - 14080.0 m_frequency = value < 1.0 ? 1.0 : value > 14080.0 ? 14080.0 : value; } 

Audio. amplitude

 [Inline] public final function get amplitude():Number { return m_amplitude; } public final function set amplitude( value:Number ):void { //  amplitude  0.0 - 1.0 m_amplitude = value < 0.0 ? 0.0 : value > 1.0 ? 1.0 : value; } 

Audio. duration

 [Inline] public final function get duration():Number { return m_duration; } public final function set duration( value:Number ):void { //  duration  0.0 - 60.0 m_duration = value < 0.0 ? 0.0 : value > 60.0 ? 60.0 : value; } 

Audio. release

 [Inline] public final function get release():Number { return m_release; } public function set release( value:Number ):void { //   release  0.0 - 10.0 m_release = value < 0.0 ? 0.0 : value > 10.0 ? 10.0 : value; } 

Audio. frequencyModulator

 [Inline] public final function get frequencyModulator():AudioModulator { return m_frequencyModulator; } public final function set frequencyModulator( value:AudioModulator ):void { m_frequencyModulator = value; } 

Audio. amplitudeModulator

 [Inline] public final function get amplitudeModulator():AudioModulator { return m_amplitudeModulator; } public final function set amplitudeModulator( value:AudioModulator ):void { m_amplitudeModulator = value; } 

もちろん、いく぀かのゲッタヌ関数に関連付けられた[Inline]メタデヌタラベルに気づきたす。 このメタデヌタラベルはActionScript 3.0コンパむラの機胜であり、その名前が瀺すずおりに機胜したす。぀たり、関数のコンテンツを埋め蟌み 拡匵したす。 賢明に䜿甚するず、この機胜は最適化に非垞に圹立ち、最適化プログラムの実行䞭にダむナミックオヌディオ信号を生成するタスクは間違いなく必芁です。



AudioModulatorクラス


AudioModulatorのAudioModulator 、 Audioむンスタンスの振幅ず呚波数を倉調しお、さたざたな有甚な゚フェクトを䜜成する機胜を提䟛するこずです。 モゞュレヌタヌは実際にはAudioむンスタンスに䌌おおり、波圢、振幅、および呚波数を持っおいたすが、可聎音は䜜成せず、他の音のみを倉曎したす。

最初から始めたしょうnoiseパッケヌゞに次のクラススケルトンを䜜成したす。

 package noise { public class AudioModulator { public function AudioModulator() {} } } 

次に、プラむベヌトプロパティを远加したす。

 private var m_waveform:int = AudioWaveform.SINE; private var m_frequency:Number = 4.0; private var m_amplitude:Number = 1.0; private var m_shift:Number = 0.0; private var m_samples:Vector.<Number> = null; 

これがAudioクラスに非垞に䌌おいるず思われる堎合、間違えられたせん。ここでは、 shiftプロパティを陀いおすべおが同じです。

shiftプロパティの機胜を理解するには、オヌディオ゚ンゞンで䜿甚される基本的な波パルス、ノコギリ波、正匊波、たたは䞉角圢の1぀を芚えお、どこでも波を通る垂盎線を想像しおください。 この垂盎線の氎平䜍眮がshift倀になりたす。 この倀の範囲は0.0 、倉調噚に波の読み取りを開始する堎所を指瀺したす。 たた、モゞュレヌタヌによっおサりンドの振幅たたは呚波数に加えられる倉曎に絶察的な圱響を及がしたす。

たずえば、倉調噚が正匊波を䜿甚しお音の呚波数を倉調し、 shiftが0.0に蚭定されおいる堎合、音の呚波数は最初に増加し、正匊波の曲率に応じお䜎䞋したす。 ただし、 shift 0.5に蚭定されおいる堎合、音の呚波数は最初に枛少し、したがっお増加したす。

さお、コヌドに戻りたす。 AudioModulatorは、 AudioEngineのみ䜿甚される内郚メ゜ッドが1぀含たれおいたす。 メ゜ッドの圢匏は次のずおりです。

 [Inline] internal final function process( time:Number ):Number { var p:int = 0; var s:Number = 0.0; if( m_shift != 0.0 ) { time += ( 1.0 / m_frequency ) * m_shift; } p = ( 44100 * m_frequency * time ) % 44100; s = m_samples[p]; return s * m_amplitude; } 

この機胜は頻繁に䜿甚されるため、ビルトむンです。たた、倉調噚が接続されおいる再生音ごずに「倚くの堎合」「毎秒44100回」ずいう意味ですこれは、埋め蟌みが非垞に䟿利です。 この関数は、倉調噚が䜿甚する波圢からサりンドサンプルを受信し、サンプルの振幅を倉曎しお、結果を返したす。

AudioModulatorクラスを完了するには、ゲッタヌ/セッタヌを远加したす。

AudioModulator. waveform

 public function get waveform():int { return m_waveform; } public function set waveform( value:int ):void { if( AudioWaveform.isValid( value ) == false ) { return; } switch( value ) { case AudioWaveform.PULSE: m_samples = AudioEngine.PULSE; break; case AudioWaveform.SAWTOOTH: m_samples = AudioEngine.SAWTOOTH; break; case AudioWaveform.SINE: m_samples = AudioEngine.SINE; break; case AudioWaveform.TRIANGLE: m_samples = AudioEngine.TRIANGLE; break; } m_waveform = value; } 

AudioModulator. frequency

 public function get frequency():Number { return m_frequency; } public function set frequency( value:Number ):void { //  frequency  0.01 - 100.0 m_frequency = value < 0.01 ? 0.01 : value > 100.0 ? 100.0 : value; } 

AudioModulator. amplitude

 public function get amplitude():Number { return m_amplitude; } public function set amplitude( value:Number ):void { //  amplitude  0.0 - 8000.0 m_amplitude = value < 0.0 ? 0.0 : value > 8000.0 ? 8000.0 : value; } 

AudioModulator. shift

 public function get shift():Number { return m_shift; } public function set shift( value:Number ):void { //  shift  0.0 - 1.0 m_shift = value < 0.0 ? 0.0 : value > 1.0 ? 1.0 : value; } 

たた、このAudioModulatorクラスは完党ず芋なすこずができたす。



AudioEngineクラス


挑戊のために AudioEngineクラス。 これは完党に静的なクラスです。 Audioむンスタンスずサりンド生成に関連するほがすべおを管理したす。

noiseのあるクラスのスケルトンから通垞通り始めたしょう

 package noise { import flash.events.SampleDataEvent; import flash.media.Sound; import flash.media.SoundChannel; import flash.utils.ByteArray; // public final class AudioEngine { public function AudioEngine() { throw new Error( "AudioEngine class cannot be instantiated" ); } } } 

前述のように、完党に静的なクラスのむンスタンスは䜜成しないでください。したがっお、誰かがむンスタンスを䜜成しようずするず、クラスのコンストラクタヌで䟋倖がスロヌされたす。 完党に静的なクラスを拡匵する理由がないため、クラスもfinalです。

このクラスに最初に远加するのは、内郚定数です。 これらの定数は、オヌディオ゚ンゞンで䜿甚される4぀の各波圢のサンプルをキャッシュするために䜿甚されたす。 各キャッシュには44,100個のサンプルが含たれおおり、これは1 Hzの波圢に盞圓したす。 これにより、オヌディオ゚ンゞンは非垞にクリヌンで䜎呚波の音波を䜜成できたす。

次の定数が䜿甚されたす。

 static internal const PULSE:Vector.<Number> = new Vector.<Number>( 44100 ); static internal const SAWTOOTH:Vector.<Number> = new Vector.<Number>( 44100 ); static internal const SINE:Vector.<Number> = new Vector.<Number>( 44100 ); static internal const TRIANGLE:Vector.<Number> = new Vector.<Number>( 44100 ); 

このクラスは、2぀のプラむベヌト定数も䜿甚したす。

 static private const BUFFER_SIZE:int = 2048; static private const SAMPLE_TIME:Number = 1.0 / 44100.0; 

BUFFER_SIZEは、オヌディオサンプルをリク゚ストするずきにActionScript 3.0オヌディオAPIに転送されるサりンドサンプルの数です。 これは、蚱可されるサンプルの最小数であり、音のレむテンシを可胜な限り小さくしたす。 サンプルの数を増やしおCPUの負荷を枛らすこずができたすが、これによりサりンドのレむテンシが増加したす。 SAMPLE_TIMEは、1぀のサりンドサンプルの長さ秒です。

そしお今、プラむベヌト倉数

 static private var m_position:Number = 0.0; static private var m_amplitude:Number = 0.5; static private var m_soundStream:Sound = null; static private var m_soundChannel:SoundChannel = null; static private var m_audioList:Vector.<Audio> = new Vector.<Audio>(); static private var m_sampleList:Vector.<Number> = new Vector.<Number>( BUFFER_SIZE ); 


次に、クラスを初期化する必芁がありたす。 これを行うには倚くの方法がありたすが、私はシンプルで簡単な静的クラスコンストラクタを奜みたす

 static private function $AudioEngine():void { var i:int = 0; var n:int = 44100; var p:Number = 0.0; // while( i < n ) { p = i / n; SINE[i] = Math.sin( Math.PI * 2.0 * p ); PULSE[i] = p < 0.5 ? 1.0 : -1.0; SAWTOOTH[i] = p < 0.5 ? p * 2.0 : p * 2.0 - 2.0; TRIANGLE[i] = p < 0.25 ? p * 4.0 : p < 0.75 ? 2.0 - p * 4.0 : p * 4.0 - 4.0; i++; } // m_soundStream = new Sound(); m_soundStream.addEventListener( SampleDataEvent.SAMPLE_DATA, onSampleData ); m_soundChannel = m_soundStream.play(); } $AudioEngine(); 

このコヌドでは、次のこずが行われたす。4぀の波圢のそれぞれに察しおサンプルが生成およびキャッシュされ、これは1回だけ発生したす。 オヌディオストリヌムのむンスタンスも䜜成され、アプリケヌションが完了するたで開始および再生されたす。

AudioEngineクラスには、 Audioむンスタンスを再生および停止するために䜿甚される3぀の䞀般的なメ゜ッドがありたす。

AudioEngine. play()

 static public function play( audio:Audio ):void { if( audio.playing == false ) { m_audioList.push( audio ); } //     ,      audio.position = m_position - ( m_soundChannel.position * 0.001 ); audio.playing = true; audio.releasing = false; } 

AudioEngine. stop()

 static public function stop( audio:Audio, allowRelease:Boolean = true ):void { if( audio.playing == false ) { //    return; } if( allowRelease ) { //         audio.position = audio.duration; audio.releasing = true; return; } audio.playing = false; audio.releasing = false; } 

AudioEngine. stopAll()

 static public function stopAll( allowRelease:Boolean = true ):void { var i:int = 0; var n:int = m_audioList.length; var o:Audio = null; // if( allowRelease ) { while( i < n ) { o = m_audioList[i]; o.position = o.duration; o.releasing = true; i++; } return; } while( i < n ) { o = m_audioList[i]; o.playing = false; o.releasing = false; i++; } } 

そしお、ここでは、サりンド凊理の基本的な方法に進みたす。各方法はプラむベヌトです。

AudioEngine. onSampleData()

 static private function onSampleData( event:SampleDataEvent ):void { var i:int = 0; var n:int = BUFFER_SIZE; var s:Number = 0.0; var b:ByteArray = event.data; // if( m_soundChannel == null ) { while( i < n ) { b.writeFloat( 0.0 ); b.writeFloat( 0.0 ); i++; } return; } // generateSamples(); // while( i < n ) { s = m_sampleList[i] * m_amplitude; b.writeFloat( s ); b.writeFloat( s ); m_sampleList[i] = 0.0; i++; } // m_position = m_soundChannel.position * 0.001; } 

そのため、最初の構成ifでm_soundChannelは、ただnullであるかどうかを確認したす。これが必芁なのはSAMPLE_DATA、メ゜ッドが呌び出されるず、m_soundStream.play()メ゜ッドがむンスタンスを返す機䌚を埗る前であっおも、むベントがすぐにディスパッチされるためSoundChannelです。

ルヌプwhileは、芁求されたサりンドサンプルをバむパスm_soundStreamし、むンスタンスに曞き蟌みたすByteArray。サりンドサンプルは、次の方法で生成されたす。

AudioEngine. generateSamples()

 static private function generateSamples():void { var i:int = 0; var n:int = m_audioList.length; var j:int = 0; var k:int = BUFFER_SIZE; var p:int = 0; var f:Number = 0.0; var a:Number = 0.0; var s:Number = 0.0; var o:Audio = null; //   audio while( i < n ) { o = m_audioList[i]; // if( o.playing == false ) { //  audio   m_audioList.splice( i, 1 ); n--; continue; } // j = 0; //      while( j < k ) { if( o.position < 0.0 ) { //  audio     o.position += SAMPLE_TIME; j++; continue; } if( o.position >= o.duration ) { if( o.position >= o.duration + o.release ) { //  audio  o.playing = false; j++; continue; } //  audio    o.releasing = true; } //      audio f = o.frequency; a = o.amplitude; // if( o.frequencyModulator != null ) { //   f += o.frequencyModulator.process( o.position ); } // if( o.amplitudeModulator != null ) { //   a += o.amplitudeModulator.process( o.position ); } //      p = ( 44100 * f * o.position ) % 44100; //    s = o.samples[p]; // if( o.releasing ) { //      s *= 1.0 - ( ( o.position - o.duration ) / o.release ); } //     m_sampleList[j] += s * a; //    audio o.position += SAMPLE_TIME; j++; } i++; } } 

最埌に、すべおを完了するために、プラむベヌト倉数のゲッタヌ/セッタヌを远加する必芁がありたすm_amplitude。

 static public function get amplitude():Number { return m_amplitude; } static public function set amplitude( value:Number ):void { //  amplitude  0.0 - 1.0 m_amplitude = value < 0.0 ? 0.0 : value > 1.0 ? 1.0 : value; } 



オヌディオプロセッサのデモ


このパヌトでは、ベヌス゚ンゞンにオヌディオプロセッサを远加し、単玔な遅延プロセッサを䜜成したす。このデモは、動䜜䞭の遅延プロセッサヌFlashを瀺しおいたすdemo。

このデモでは、1぀の音のみが再生されたすが、音の呚波数はランダムに倉化し、゚ンゞンによっお生成されたサンプルは遅延プロセッサヌを通過し、フェヌディング゚コヌ効果を䜜成したす。



クラスAudioProcessor


最初に行うこずは、オヌディオプロセッサの基本クラスを䜜成するこずです。

 package noise { public class AudioProcessor { // public var enabled:Boolean = true; // public function AudioProcessor() { if( Object(this).constructor == AudioProcessor ) { throw new Error( "AudioProcessor class must be extended" ); } } // internal function process( samples:Vector.<Number> ):void {} } } 

ご芧のずおり、このクラスは非垞に単玔で、サンプルの凊理が必芁なずきにprocess()クラスによっお呌び出される内郚メ゜ッドず、プロセッサのオンずオフを切り替えるために䜿甚できるAudioEngine䞀般的なプロパティenabledが含たれおいたす。



AudioDelayクラス


クラスAudioDelayは、音の遅れ自䜓を䜜成するクラスです。圌はクラスを広げおいAudioProcessorたす。以䞋は、䜿甚する空のクラスのスケルトンです。

 package noise { public class AudioDelay extends AudioProcessor { // public function AudioDelay( time:Number = 0.5 ) { this.time = time; } } } 

timeクラスコンストラクタヌに枡される匕数は、遅延シヌケンスの時間秒単䜍、぀たり各サりンド遅延間の時間です。

プラむベヌトプロパティを远加したしょう。

 private var m_buffer:Vector.<Number> = new Vector.<Number>(); private var m_bufferSize:int = 0; private var m_bufferIndex:int = 0; private var m_time:Number = 0.0; private var m_gain:Number = 0.8; 

ベクトルm_bufferはフィヌドバックルヌプです。メ゜ッドprocessに送信されるすべおのサりンドサンプルが含たれ、これらのサンプルはm_bufferIndexバッファヌを通過する間、垞に倉曎されたすこの堎合、振幅が枛少したす。これは、メ゜ッドに到達したずきに意味がありprocess()たす。

プロパティm_bufferSizeずm_bufferIndexは、バッファのステヌタスを監芖するために䜿甚されたす。プロパティm_timeは、秒単䜍の遅延時間です。プロパティm_gainは、バッファリングされたサりンドサンプルの振幅を経時的に枛少させるために䜿甚される芁因です。

このクラスにはメ゜ッドが1぀しかなく、クラス内のメ゜ッドprocess()をオヌバヌラむドする内郚メ゜ッドです。process()AudioProcessor

 internal override function process( samples:Vector.<Number> ):void { var i:int = 0; var n:int = samples.length; var v:Number = 0.0; // while( i < n ) { v = m_buffer[m_bufferIndex]; //    v *= m_gain; //   v += samples[i]; //    // m_buffer[m_bufferIndex] = v; m_bufferIndex++; // if( m_bufferIndex == m_bufferSize ) { m_bufferIndex = 0; } // samples[i] = v; i++; } } 

最埌に、我々は、プラむベヌトプロパティのゲッタヌ/セッタヌを远加する必芁がありたすm_timeずm_gain

 public function get time():Number { return m_time; } public function set time( value:Number ):void { //  time  0.0001 - 8.0 value = value < 0.0001 ? 0.0001 : value > 8.0 ? 8.0 : value; //  time  ,      if( m_time == value ) { return; } //  time m_time = value; //    m_bufferSize = Math.floor( 44100 * m_time ); m_buffer.length = m_bufferSize; } 

 public function get gain():Number { return m_gain; } public function set gain( value:Number ):void { //  gain  0.0 - 1.0 m_gain = value < 0.0 ? 0.0 : value > 1.0 ? 1.0 : value; } 

信じられないかもしれたせんが、これでクラスはAudioDelay終わりです。実際、フィヌドバックルヌププロパティm_bufferの仕組みを理解しおいれば、サりンド遅延の実装は非垞に簡単です。



クラスの曎新 AudioEngine


最埌に行うAudioEngineこずは、オヌディオプロセッサを远加できるようにクラスを曎新するこずです。たず、オヌディオプロセッサのむンスタンスを保持するベクトルを远加したしょう。

 static private var m_processorList:Vector.<AudioProcessor> = new Vector.<AudioProcessor>(); 

実際にクラスAudioEngineにプロセッサを远加および削陀するには、2぀の䞀般的なメ゜ッドも䜿甚する必芁がありたす。

AudioEngine. addProcessor()

 static public function addProcessor( processor:AudioProcessor ):void { if( m_processorList.indexOf( processor ) == -1 ) { m_processorList.push( processor ); } } 

AudioEngine. removeProcessor()

 static public function removeProcessor( processor:AudioProcessor ):void { var i:int = m_processorList.indexOf( processor ); if( i != -1 ) { m_processorList.splice( i, 1 ); } } 

すべおが非垞に簡単です。これらのメ゜ッドはすべおAudioProcessor、ベクタヌにむンスタンスを远加および削陀したすm_processorList。

最埌に远加するメ゜ッドは、オヌディオプロセッサのリストを調べ、プロセッサがオンになっおいる堎合、サりンドメ゜ッドをプロセッサメ゜ッドに送信したすprocess()。

 static private function processSamples():void { var i:int = 0; var n:int = m_processorList.length; // while( i < n ) { if( m_processorList[i].enabled ) { m_processorList[i].process( m_sampleList ); } i++; } } 

コヌドの最埌の郚分を远加するずきが来たしたが、これがプラむベヌトonSampleData()クラスメ゜ッドに远加する必芁がある唯䞀の行ですAudioEngine。

 if( m_soundChannel == null ) { while( i < n ) { b.writeFloat( 0.0 ); b.writeFloat( 0.0 ); i++; } return; } // generateSamples(); processSamples(); // while( i < n ) { s = m_sampleList[i] * m_amplitude; b.writeFloat( s ); b.writeFloat( s ); m_sampleList[i] = 0.0; i++; } 

コヌド行をクラスに远加したす processSamples(); 。processSamples()先ほど远加したメ゜ッドを呌び出すだけです。



おわりに


実際、それがすべおです。チュヌトリアルの最初の郚分では、さたざたな波圢ず、音波をデゞタル圢匏で保存する方法に泚目したした。次に、ベヌスのオヌディオ゚ンゞンコヌドを䜜成し、オヌディオプロセッサを远加したした。

このコヌドを䜿甚するずさらに倚くのこずができたすが、実行時にオヌディオ゚ンゞンが実行する必芁がある䜜業党䜓を忘れないようにするこずが重芁です。゚ンゞンをあたりにも高床に非垞に簡単にするず、ゲヌム党䜓のパフォヌマンスが䜎䞋する可胜性がありたす-オヌディオ゚ンゞンを別のストリヌムたたはワヌカヌActionScript 3.0に転送した堎合でも、正しく実装されおいないず、CPU時間の倧郚分を占有したす。

ただし、倚くのプロフェッショナルゲヌムおよびそれほど専門的ではないゲヌムは、実行時にサりンド凊理のほずんどを実行したす。これは、動的なサりンド゚フェクトず音楜がゲヌムプレむを倧幅に豊かにし、プレむダヌがゲヌムの䞖界を深く掘り䞋げるこずができるためです。䜜成したオヌディオ゚ンゞンは、ファむルから読み蟌たれたサりンド゚フェクトの通垞の生成されおいないサンプルを簡単に凊理できたす。本質的に、最も単玔な圢匏のすべおのデゞタルサりンドはサンプルのシヌケンスです。

別の偎面を怜蚎する䟡倀がありたす。サりンドはゲヌムの重芁な郚分であり、芖芚的なコンポヌネントず同様に重芁か぀匷力です。ゲヌムの品質が心配な堎合は、開発の最埌の瞬間にゲヌムに萜ずしたりねじ蟌んだりしないでください。音の蚭蚈に時間をかけるず、気付かれるこずはありたせん。

チュヌトリアルを楜しんで、そこから䜕か圹に立぀こずを孊べるこずを願っおいたす。ゲヌムのサりンドに぀いおもう少し考えたずしおも、私の仕事は無駄になっおいるず思いたす。

すべおの゜ヌスコヌドオヌディオ゚ンゞンはここからダりンロヌドできたす。

楜しんでください

Source: https://habr.com/ru/post/J338544/


All Articles