この記事は機械翻訳されたものです。

快適な動作

Windows Phone のストリーミング オーディオ (機械翻訳)

Charles Petzold

コード サンプルをダウンロードします。

Charles Petzoldデスクトップ、Web、またはあなたの手で実行しているかどうか、コンピュータ プログラムは時々 音や音楽を再生する必要があります。 ほとんどの場合、このオーディオ完全 MP3 または WMA のファイルでエンコードされます。 このアプローチの大きな利点は、OS 自体は通常デコード、これらのファイルを再生する方法を知っています。 アプリケーションは、UI を提供する、一時停止、再開、おそらくトラック間を移動するための比較的簡単に仕事に集中できます。

しかし、人生が常にので便利ではないです。 時々、プログラム、OS によっては、サポートされていない形式のオーディオ ファイルを再生またはオーディオ データに動的に生成することも、おそらく電子音楽合成を実装するのにが必要です。

Silverlight と Windows Phone の用語では、このプロセスは「ストリーミング」オーディオとして知られています。実行時に、アプリケーションは、オーディオ データを構成するバイトのストリームを提供します。 MediaStreamSource は、オーディオ データは、OS のオーディオ プレーヤーの需要にフィードから派生したクラスで発生します。 Windows Phone OS 7.5 はバック グラウンドでのオーディオをストリームすることができます、私はそれをする方法を説明します。

MediaStreamSource からの派生

Windows Phone プログラムでオーディオ データを動的に生成、重要な最初のステップ MediaStreamSource の抽象クラスから派生しています。 最初から、コードを記述するのではなく、おそらく誰か他の人をコピーする必要があります関与のコード スポットで乱雑です。

この記事のダウンロード可能なソース コードの SimpleAudioStreaming プロジェクト 1 つの可能なアプローチを示しています。 このプロジェクトには、単に 440 Hz、正弦波を生成 Sine440AudioStreamSource という名前を MediaStreamSource の誘導体が含まれます。 これは、一般的なチューニングの標準として使用される中間 C 上に対応する周波数です。

MediaStreamSource 誘導体をオーバーライドする必要のある六つの抽象メソッドですがそれらの 2 つだけ重要であります。 最初 OpenMediaPlayer、カップルの辞書オブジェクトと、リスト オブジェクトを作成する、オーディオ データのクラスを提供し、このデータを記述するさまざまなパラメーターの種類を定義する必要があるです。 オーディオ パラメーターをリトル エンディアン形式でのすべてのマルチバイト番号 Win32 WAVEFORMATEX 構造体のフィールドとして表されます (最も重要なバイト最初) と、文字列に変換します。

私はオーディオ Cd と Windows WAV ファイル形式を含む、最も非圧縮のオーディオの使用は、パルス コード変調 (PCM) 形式の以外の MediaStreamSource を使ったことがないです。 PCM オーディオにはサンプル レートと呼ばれる一定の速度で一定サイズ サンプルが含まれます。 CD 品質のサウンドを 16 ビット サンプル、44,100 Hz のサンプル レートを使用します。 モノラル音のためのチャネルを 1 つまたは 2 つのチャンネルのステレオを選択することができます。

Sine440AudioStreamSource クラス ハードコーディングされています 1 つのチャンネル、16 ビット サンプル サイズしますが、サンプル レートは、コンス トラクター引数として指定することができます。

内部的には、オーディオのパイプラインのサイズの MediaStreamSource の AudioBufferLength プロパティで指定されたオーディオ データのバッファーを保持します。 既定の設定は 1,000 ms ですが 15 ms の低に設定できます。 このバッファーを維持するには、呼び出しを MediaStreamSource 誘導体の GetSampleAsync メソッドに行われます。 あなたの仕事は、オーディオ データの束、MemoryStream にシャベルし、ReportGetSampleCompleted を呼び出すことです。

Sine440AudioStreamSource クラスは 4,096 のサンプル呼び出しごとの提供にハードコードされています。 44,100 のサンプル レートは、オーディオ呼び出しごとの 2 番目の 10 分の 1 はではないです。 この値と、AudioBufferLength で遊んでプロパティはユーザー入力にすぐに応答する必要があります、ユーザー制御のシンセサイザーを実装している場合に必要です。 最小待機時間の再生のギャップが発生するようにバッファー サイズがあまりにも小さくない小さくします。

図 1 GetSampleAsync オーバーライドの Sine440AudioStreamSource の実装を示しています。 ループ内で、16 ビットの正弦値は以下の短いに拡大、Math.Sin メソッドへの呼び出しから取得されます。

short amplitude = (short)(short.MaxValue * Math.Sin(angle));

図 1 Sine440AudioStreamSource で GetSampleAsync メソッド

protected override void GetSampleAsync(MediaStreamType mediaStreamType)
{
  // Reset MemoryStream object
  memoryStream.Seek(0, SeekOrigin.Begin);
  for (int sample = 0; sample < BufferSamples; sample++)
  {
    short amplitude = (short)(short.MaxValue * Math.Sin(angle)); 
    memoryStream.WriteByte((byte)(amplitude & 0xFF));
    memoryStream.WriteByte((byte)(amplitude >> 8));
    angle = (angle + angleIncrement) % (2 * Math.PI);
  }
  // Send out the sample
  ReportGetSampleCompleted(new MediaStreamSample(mediaStreamDescription,
    memoryStream,
    0,
    BufferSize,
    timestamp,
    mediaSampleAttributes));
  // Prepare for next sample
  timestamp += BufferSamples * 10000000L / sampleRate;
}

振幅、2 バイトに分割し、MemoryStream で、低位バイトを最初に保存します。 ステレオの各サンプルには左と右を交互、2 つの 16 ビット値が必要です。

その他の計算が可能です。 このような振幅を定義することによって、のこぎり波、正弦波からを切り替えることができます。

short amplitude = (short)(short.MaxValue * angle / Math.PI + short.MinValue);

両方のケースでは、変数に「角度」範囲 0 から 2 π ラジアン (360 度) 名前が 1 つサイクルは特定波形の参照。 各サンプルの実行後、角度増加 angleIncrement では、変数はここでハードコード 440 Hz として、サンプル ・ レートの周波数を生成するには、波形の周波数に基づく以前クラス計算されます。

angleIncrement = 2 * Math.PI * 440 / sampleRate;

周波数生成された波形のサンプル レートを半分に近づくと、angleIncrement が π または 180 度で近づくことに注意してください。 サンプル レートを半分に生成された波形サイクルあたりのちょうど 2 つのサンプルに基づいており、スムーズな正弦曲線ではなく、方形波になります。 ただし、この矩形波の高調波の上の半分のサンプル レートです。

また、サンプルの半分のレートよりも高い周波数を生成できないことにも注意してください。 場合、実際に「エイリアス」を生成しますが以下のサンプル レートを半分。 サンプル レートの半分は、ハリー ・ ナイキスト、勤務、技術者にちなんで、ナイキスト周波数として知られている AT & T のときに彼は、初期の紙情報理論のオーディオ サンプリング技術基礎 1928 年公開します。

44,100 の半分である 20,000 Hz としてよく考え、人間の聴覚の上限を超える音楽 CD を 44,100 Hz のサンプル レート部分的選ばれました。

Sine440AudioStreamSource クラス以外からは、SimpleAudioStreaming プロジェクトの残りの部分はかなり簡単です。MainPage.xaml ファイルには、mediaElement、および MediaStreamSource 誘導体のインスタンスをこのオブジェクトの MainPage OnNavigatedTo オーバーライド呼び出し SetSource という、MediaElement が含まれます。

mediaElement.SetSource(new Sine440AudioStreamSource(44100));

プログラムのコンス トラクターでは、この呼び出し元があったからプログラムを移動ときに廃棄されてプログラムなしをバックアップすると音楽再生を再開することができなかったことを発見しました。

MediaElement の SetSource メソッドは、ストリーム オブジェクトと参照される音楽ファイルの再生に MediaElement をする場合は、同じメソッドです。 SetSource を呼び出して通常、サウンド再生を開始するが、この特定の MediaElement 再生への呼び出しも必要には false には、自動設定されています。 プログラムにはこれら操作を実行するは、アプリケーション バーでの再生と一時停止ボタンが含まれています。

プログラムの実行中は、ボリュームから、携帯電話のユニバーサル ボリューム コントロール (UVC) を制御することができますが、プログラムを終了した場合に、離れてから移動するか、サウンドを停止します。

バック グラウンドに移す

この同じ MediaStreamSource 誘導体を使用して、サウンドや音楽がバック グラウンドで再生することもできます。 バック グラウンド ミュージック プログラムから離れて移動ときにもそれを終了するか、電話での再生を続行します。 バック グラウンド音声を携帯電話の UVC だけでなく、ボリュームを制御するが、また一時停止し、オーディオを再起動できます (該当する場合) 前または戻る他のトラックにジャンプします。

この列の最後の月の分割払いで学んだは、多くの発見いただきます (msdn.microsoft.com/magazine/hh781030)、引き続きバック グラウンド オーディオのストリーミングに適用されます。 その列には、バック グラウンドで音楽ファイルを再生する方法を説明しました。AudioPlayerAgent から派生するクラスが含まれているライブラリ プロジェクトを作成します。 Windows Phone オーディオ再生エージェントの種類の新しいプロジェクトを追加する場合 visual Studio このクラスが生成されます。

アプリケーションは、AudioPlayerAgent を含む DLL への参照をする必要がありますが、このクラスに直接アクセスしません。 代わりに、アプリケーションは BackgroundAudioPlayer クラスは、最初の AudioTrack オブジェクトを設定するには、再生と一時停止を呼び出すアクセスします。 AudioTrack クラスと同様に UVC どのボタンを有効にするかを指定、トラック タイトル、アーティスト、アルバム名を指定できるコンス トラクターがあることをリコールします。

通常、AudioTrack コンス トラクターに最初の引数は、再生したい音楽ファイルのソースを示す Uri オブジェクトです。 この AudioTrack のインスタンスを音楽ファイルではなく、オーディオのストリーミングを再生する場合は、この最初のコンス トラクターの引数を null に設定します。 その場合はプログラムから参照される DLL で AudioStreamingAgent から派生するクラスは BackgroundAudioPlayer を探します。 Windows Phone オーディオ ・ ストリーミング ・ エージェントの種類のプロジェクトを追加することによって、Visual Studio でこのような DLL を作成できます。

SimpleBackgroundAudioStreaming ソリューションこの記事のダウンロード可能なコードでは、これを行う方法を示しています。 ソリューションには、アプリケーション プロジェクトと 2 つのライブラリのプロジェクトは、AudioPlayerAgent、および AudioStreamingAgent から派生する AudioTrackStreamer クラスを含む、他の名前付きの AudioStreamAgent から派生した、オーディオ クラスを含む 1 つの名前付き AudioPlaybackAgent が含まれています。 アプリケーションのプロジェクトが含まれていますを参照してください­相違が両方ライブラリ プロジェクト、それの実際のクラスにアクセスするには試みない。 私は前回のコラムで説明した理由から、ことが無駄には。

また、アプリケーションがバック グラウンド エージェント Dll への参照を含める必要があることを強調しておきます。 すべてのエラーを表示されませんが、音楽が再生されませんのでこれらの参照を省略するは簡単です。

多くの SimpleBackgroundAudioStreaming のロジックはバック グラウンドで音楽ファイルを再生するプログラムの同じ BackgroundAudioPlayer、トラック、null の Uri オブジェクトを再生しようとするたびに、AudioStreamingAgent 誘導体の OnBeginStreaming メソッドが呼び出されますにです。 ここではその呼び出しを処理、非常に簡単な方法です:

protected override void OnBeginStreaming(AudioTrack track, AudioStreamer streamer)
{
  streamer.SetSource(new Sine440AudioStreamSource(44100));
}

それはある! それは前に説明したけど今で AudioStreamAgent プロジェクトを含まれて同じ Sine440AudioStreamSource クラスです。

SimpleBackgroundAudioStreaming プログラムは 1 つだけのトラックが作成されますが、複数のオブジェクトをトラックを持つことができます、音楽ファイル、ストリーミングを使用するを参照する AudioTrack オブジェクトをミックスすることができます。 AudioTrack オブジェクトは、引数 OnBeginStreaming オーバーライドするそのトラックに使用する情報を使用して特定の MediaStreamSource をカスタマイズすることができますので、お知らせします。 多くの情報を提供するには、AudioTrack は任意の文字列に設定することができますタグ プロパティがあります。

シンセサイザーの構築

安定した正弦曲線 440 hz かなり退屈、それでは、電子音楽シンセサイザーを構築することができます。 私は 12 のクラスと 2 つのインターフェイスで、SynthesizerDemos ソリューションの Petzold.MusicSynthesis ライブラリ プロジェクトで構成される非常に初歩的なシンセサイザーをまとめた。 (これらのクラスのいくつかが書いた登場する Silverlight 3 の私のブログで 2007 年 7 月のコードに似ています — アクセスから charlespetzold.com.)

このシンセサイザーのセンターで定義されている SampleProvider、という名前のプロパティを持つ DynamicPcmStreamSource という名前の MediaStreamSource 誘導体のように。

public IStereoSampleProvider SampleProvider { get; set; }
The IStereoSampleProvider interface is simple:
public interface IStereoSampleProvider
{
  AudioSample GetNextSample();
}

AudioSample 型短いという名前の左と右の 2 つのパブリック フィールドがあります。 その GetSampleAsync メソッドでは、DynamicPcmStreamSource、16 ビット サンプルのペアを取得するには、GetNextSample メソッドを呼び出します。

AudioSample audioSample = SampleProvider.GetNextSample();

IStereoSampleProvider を実装する 1 つのクラスは、ミキサーという名前です。 ミキサー型 MixerInput のオブジェクトのコレクションでは、入力プロパティを備えています。 各 MixerInput は、入力プロパティの定義型 IMonoSampleProvider がましょう。

public interface IMonoSampleProvider
{
  short GetNextSample();
}

IMonoSampleProvider を実装する 1 つのクラスは、一連の同じ期間のノートは、特定のテンポで再生できる抽象クラスです SteadyNoteDurationPlayer、名前です。 また IMonoSample を実装する発振器という名前のプロパティが­実際の波形を生成するプロバイダー。 2 つのクラスは、SteadyNoteDurationPlayer から派生します。シーケンサーでは、一連のノートが繰り返し再生されます。 とりとめ、ノートのランダムなストリーム再生します。 これら 2 つのクラスを使用して、2 つの異なるアプリケーションで、SynthesizerDemos ソリューション、フォア グラウンドで実行されてとは、バック グラウンドで音楽を再生します。

フォア グラウンド専用アプリケーション WaveformManipulator と呼ばれ、インタラクティブ、音楽の再生のように使用する波形を定義することができますコントロール機能図 2

The WaveformManipulator Program
図 2 WaveformManipulator プログラム

波形を定義するポイントを Oscil に転送されます­VariableWaveformOscillator という抽出から派生します。 ラウンドのタッチ ポイントを上下に移動すると、実際には、音楽の音色の変化を聞く前に、1 秒の遅延についてがわかります。 これは MediaStreamSource で定義されている既定の 1,000 ms バッファー サイズになります。

WaveformManipulator プログラムのメモは、ホ短調、イ短調、ニ短調 G 主要アルペジオは同じシリーズで読み込まれている 2 つのシーケンサー オブジェクトを使用します。 同期のうちは、まず、リバーブの種類とドリフト効果、エコーや、対位法のように、tempo の複数形の 2 つのシーケンサー オブジェクトただし、若干異なるのでください。 (この「音楽・ プロセス」の一種であるアメリカの作曲家スティーヴ ・ ライヒの初期の作品に触発。)初期化コード」をシンセサイザー コンポーネント ワイヤ「MainPage.xaml.cs から表示されます図 3.

図 3 シンセサイザー初期化コード WaveformManipulator で

// Initialize Waveformer control
for (int i = 0; i < waveformer.Points.Count; i++)
{
  double angle = (i + 1) * 2 * Math.PI / (waveformer.Points.Count + 1);
  waveformer.Points[i] = new Point(angle, Math.Sin(angle));
}
// Create two Sequencers with slightly different tempi
Sequencer sequencer1 = new Sequencer(SAMPLE_RATE)
{
  Oscillator = new VariableWaveformOscillator(SAMPLE_RATE)
  {
    Points = waveformer.Points
  },
  Tempo = 480
};
Sequencer sequencer2 = new Sequencer(SAMPLE_RATE)
{
  Oscillator = new VariableWaveformOscillator(SAMPLE_RATE)
  {
    Points = waveformer.Points
  },
  Tempo = 470
};
// Set the same Pitch objects in the Sequencer objects
Pitch[] pitches =
{
  ...
};
foreach (Pitch pitch in pitches)
{
  sequencer1.Pitches.Add(pitch);
  sequencer2.Pitches.Add(pitch);
}
// Create Mixer and MixerInput objects
mixer = new Mixer();
mixer.Inputs.Add(new MixerInput(sequencer1) { Space = -0.5 });
mixer.Inputs.Add(new MixerInput(sequencer2) { Space = 0.5 });

OnNavigatedTo オーバーライドで、ミキサー、DynamicPcmStreamSource および MediaElement オブジェクトが接続されています。

DynamicPcmStreamSource dynamicPcmStreamSource =
  new DynamicPcmStreamSource(SAMPLE_RATE);
dynamicPcmStreamSource.SampleProvider = mixer;
mediaElement.SetSource(dynamicPcmStreamSource);

音楽を再生するために MediaElement WaveformManipulator を使用するため、プログラムをフォア グラウンドで実行されている場合にのみ再生されます。

背景の制限

BackgroundAudioPlayer を使用して、バック グラウンドで音楽を再生する WaveformManipulator のバージョンに思考の多くを与えた。 明らかに、のみ、プログラムをフォア グラウンドでだったが、私は先月のコラムで説明した、障害過去を得ることができなかった、波形を操作できるようになります。分離ストレージを使用これら 2 つのタスクが任意のデータを交換できることを見ることができる唯一の方法バック グラウンド エージェント Dll プログラムをバック グラウンド処理のプログラム自体よりも異なるタスクの実行を処理するために提供され。

私は良いアイデアをバック グラウンドでのオーディオをストリーミング再生するプログラムをしていたのでこの仕事を追求していない部分的決めました。 これはランダムな曲を再生するプログラムだったが少しとき、加速度計、変更電話向きの登録を変更するメモ。 電話を振動新しい曲を完全に作成します。

このプロジェクトは、Microsoft.Devices.Sensors アセンブリへの参照を AudioStreamAgent プロジェクトに追加する私の試みとして得た。 赤い X と、メッセージ「しようと、バック グラウンド エージェントによってサポートされていない参照を追加するしました」メッセージ ボックス移動を呼び出すどうやらバック グラウンド エージェント、加速度計を使用できません。 そんなにそのプログラムのアイデアを !

代わりに、バック グラウンド ストリーミングのみ 5 黒のピアノのノートから成る五音音階の終わることのないメロディを使用する PentatonicRambler と呼ばれるプログラムを書いた。 ノートをいずれか 1 つのステップを各連続のメモを制限とりとめと呼ばれる、シンセサイザー コンポーネントでランダムに選択または 1 つが、以前のメモから降りる。 大きなジャンプの欠如、結果のストリームは、単にランダムなものではなくノート音、構成 (や即興) のメロディーのような多くのです。

図 4 AudioStreamingAgent 誘導体の OnBeginStreaming のオーバーライドを示します。

図 4 PentatonicRambler のシンセサイザー セットアップ

protected override void OnBeginStreaming(AudioTrack track, AudioStreamer streamer)
{
  // Create a Rambler
  Rambler rambler = new Rambler(SAMPLE_RATE,
  new Pitch(Note.Csharp, 4), // Start
  new Pitch(Note.Csharp, 2), // Minimum
  new Pitch(Note.Csharp, 6)) // Maximum
  {
    Oscillator = new AlmostSquareWave(SAMPLE_RATE),
    Tempo = 480
  };
  // Set allowable note values
  rambler.Notes.Add(Note.Csharp);
  rambler.Notes.Add(Note.Dsharp);
  rambler.Notes.Add(Note.Fsharp);
  rambler.Notes.Add(Note.Gsharp);
  rambler.Notes.Add(Note.Asharp);
  // Create Mixer and MixerInput objects
  Mixer mixer = new Mixer();
  mixer.Inputs.Add(new MixerInput(rambler));
  DynamicPcmStreamSource audioStreamSource =
    new DynamicPcmStreamSource(SAMPLE_RATE);
  audioStreamSource.SampleProvider = mixer;
  streamer.SetSource(audioStreamSource);
}

私とシンセサイザー コンポーネントの群集、プログラム自体で定義し、バック グラウンド エージェントには、このセットアップを転送する優先しますが、プログラム タスクとバック グラウンド エージェント間のプロセス分離の作業が必要とするタスクを指定します。 シンセサイザー セットアップ文字列で完全に定義する必要があります (おそらく XML ベース) し、プログラムから、AudioStreamingAgent から派生する AudioTrack のタグ プロパティを通じて渡さ。

一方、私のしい物のリスト Windows Phone に将来の機能拡張のプログラムの彼らを呼び出すバック グラウンド エージェントと通信することができます施設が含まれます。

Charles Petzold に MSDN Magazine に長年貢献しています。 彼の Web サイト charlespetzold.com

この記事のレビュー、次の技術的な専門家のおかげでに: Eric BieMark HopkinsChris Pearson