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

快適な動作

Windows Phone 用の楽器 (機械翻訳)

Charles Petzold

コード サンプルのダウンロード

Charles Petzold内蔵スピーカーとヘッドフォン ジャック、すべて Windows Phone をしているし、その使用は電話の呼び出しに限られていた場合、確かにはもったいない。 幸いにも、Windows Phone アプリケーションも、電話のオーディオ設備音楽またはその他のサウンドを再生するため使用できます。 私はこのコラムの最近の記事で説明したように、Windows Phone アプリケーション ユーザーの音楽ライブラリでは、格納されている MP3 または WMA のファイル再生したりファイルをダウンロードした上、インターネット。

Windows Phone アプリケーションも動的にオーディオ波形、「オーディオをストリーミングします」という手法を生成することができますこれは非常にデータ量の多いアクティビティです。CD 品質のサウンドを左と右の両方のチャンネルの 1 秒あたり 44,100 サンプルまたは、なんと 176,400 バイト 1 秒あたりのレートで 16 ビット サンプルを生成する必要があります !

しかし、オーディオのストリーミング、強力な手法です。 あなたはマルチタッチを組み合わせる場合は、電子音楽楽器には、あなたの携帯電話を有効にすることができよりももっと楽しいことができる何か。

テルミンを妊娠

非常に初期の電子楽器のロシアの発明者レフ ・ テルミン、1920 年代に作成されました。 テルミンのプレーヤーは実際に楽器をタッチしていません。 代わりに、プレーヤーの手は、ボリュームとピッチの音を個別に制御する 2 つのアンテナを基準に移動します。 注意の注意を滑空、幽霊の震える慟哭になります — おなじみ「白い恐怖」と"日は地球の静止」などの映画から、時折ロックバンド、シーズン 4、エピソード 12「ビッグバン理論」の(人気の信念に反して、テルミン「スタートレック」テーマは使用されていますいません。)

Windows Phone、ハンドヘルドのテルミンになってすることができますか? それは私の目標だった。

古典的なテルミン サウンドで 2 つの高周波波形を結合してオーディオ範囲の違いトーンを生成する heterodyning テクニックを生成します。 しかし、波形がコンピュータ ソフトウェアで生成される場合は、この方法は実用的ではありません。 オーディオの波形を直接生成することを多く意味します。

簡単に携帯電話の方向を使用して、サウンドを制御するまたはプログラムを表示し、携帯電話のカメラ à la Kinect を通じて手の動きを解釈するためのアイデアをいじる後、私に多くの解決より平凡なアプローチ。指、携帯電話の画面では、周波数と振幅の 1 つの軸を使用するプログラムをできる、2 次元の座標の点です。

これをインテリジェントに音楽の音を認識する方法についての少しの知識が必要です。

ピクセル、ピッチと振幅

エルンスト ・ ヴェーバーとグスタフ ・ フェヒナーの作品は 19 世紀の開拓のおかげで、私たち人間の知覚が線形ではなく対数であることを知っています。 線形の増分の変更を刺激の大きさには、できるだけ等しくを認められていません。 私たちが認めるものを平等の代わりにしばしば便利な小数の増加または減少として表現の大きさに比例する変更です。 (この現象の感覚器官を超えて拡張します。 たとえば、私たちは $1 と $2 の違いがより $100 と $101 の違いであること感じる)。

人間は約 20 Hz ~ 20、000 Hz、オーディオ周波数に敏感が周波数の私たちの知覚が線形ではありません。 多くの文化では、音楽のピッチ周波数の 2 倍は、オクターブ周辺構造化されます。 「どこか虹の彼方」を歌うときは、最初単語の 2 つの音節飛躍 ~ 200 Hz、100 Hz から 2、000 Hz 1,000 Hz からどうかに関係なく離れてオクターブです。 人間の可聴範囲は約 10 のオクターブそのためです。

西洋の音楽には 8 文字のメモ、スケールの含まれているので、オクターブ最後の注 1 オクターブ、最初のより高いが 1 オクターブを呼び出されます。A、B、C、D、E、F、G、(これは、マイナー ・ スケールと呼ばれる)、または C、D、E、F、G、A、B、C (メジャー スケール)。

これらのメモを派生する方法のために、見た目で等距離互いからは。 すべてのノートも同様に遠いが、規模 5 その他のメモ (最初の注 2 回カウントされません) 12 の合計の必要があります。C、c#、D、D #、E、F、F #、G、G #、A、A および B. これらの各手順を半音として知られているし、(律一般的なチューニングはなど、等間隔している場合は、各メモは 12 のルート 2 つ (または約 1.059) 注下の周波数回周波数があります。

半音は 100 セントにさらに分割することができます。 オクターブ 1,200 セントです。 セントと乗算のステップ 2、または 1.000578 の 1,200th のルートです。 頻度の変化に人間の感度は、広く、もちろん、異なりますが、一般的に約 5 セントに引用されています。

この背景音楽の数学と物理学にテルミン プログラム、指のピクセル位置を周波数に変換する必要があるためにです。 各オクターブ、ピクセルの数と同じ数に対応するため、この変換を行う必要があります。 我々 はテルミン 800 ピクセル長 Windows Phone 画面の風景モードでの対応、4 オクターブの範囲を持つことだ場合は、オクターブ、200 ピクセルまたは素敵な人間の知覚の限界を対応するピクセルあたり 6 セントは。

ボリュームを認識する方法、波形の振幅を決定し、これは、あまりにも、対数であります。 デシベルは、10 回、底 10 の対数比の 2 つの電源のレベルとして定義されています。 電力波形の振幅の 2乗であるため、2 つの振幅のデシベルの違いです。

CD オーディオを 65,536 にする間の最大および最小振幅をその比率を可能 16 ビット サンプルを使用します。 65,536 の 10 を底とする対数を取るし、乗算 20 と 96 デシベル範囲を取得します。

1 つのデシベルは振幅が 12% 増加についてです。 人間の知覚の振幅の変化の周波数よりもはるかに敏感です。 この Windows Phone 画面の 480 ピクセル ディメンションに簡単に対応できますので人々 のボリュームの変更通知前にいくつかのデシベルは必要があります。

実現に向けて

この記事でダウンロードできるコードは、MusicalInstruments という名前の単一の Visual Studio ソリューションです。 Petzold.MusicSynthesis プロジェクトはほとんどこのコラムの最後の月の分割払いで前述のファイルを含む、DLL です (msdn.microsoft.com/magazine/hh852599)。 テルミン アプリケーション プロジェクトの 1 つの風景ページで構成されています。

波形の種類、テルミンを生成する必要がありますか? 理論的には、正弦波は、現実には、やや歪曲の正弦波、インターネットのこの質問を研究しようには、多くの一致を見つけることができません。 私のバージョンでは、私はストレートの正弦波では、スタックし、音に合理的なように見えた。

示すように図 1、MainPage.xaml.cs ファイルいくつかの定数値を定義します、どのように表示のピクセルへの対応を制御する 2 つの整数を計算します。

図 1 の振幅と周波数計算のテルミン

public partial class MainPage : PhoneApplicationPage
{
  static readonly Pitch MIN_PITCH = new Pitch(Note.C, 3);
  static readonly Pitch MAX_PITCH = new Pitch(Note.C, 7);
  static readonly double MIN_FREQ = MIN_PITCH.Frequency;
  static readonly double MAX_FREQ = MAX_PITCH.Frequency;
  static readonly double MIN_FREQ_LOG2 = Math.Log(MIN_FREQ) / Math.Log(2);
  static readonly double MAX_FREQ_LOG2 = Math.Log(MAX_FREQ) / Math.Log(2);
  ...
double xStart;      // The X coordinate corresponding to MIN_PITCH
  int xDelta;         // The number of pixels per semitone
  void OnLoaded(object sender, EventArgs args)
  {
    int count = MAX_PITCH.MidiNumber - MIN_PITCH.MidiNumber;
    xDelta = (int)((ContentPanel.ActualWidth - 4) / count);
    xStart = (int)((ContentPanel.ActualWidth - count * xDelta) / 2);
    ...
}
  ...
double CalculateAmplitude(double y)
  {
    return Math.Min(1, Math.Pow(10, -4 * (1 - y / ContentPanel.ActualHeight)));
  }
  double CalculateFrequency(double x)
  {
    return Math.Pow(2, MIN_FREQ_LOG2 + (x - xStart) / xDelta / 12);
  }
  ...
}

範囲 C 中間 C (の周波数について 130.8 Hz) の下から、C の 3 オクターブ中間 C、約 2, 093 Hz の上にです。 2 つの方法は周波数を計算し、Touch.FrameReported イベントからタッチ ポイントの座標に基づいて、相対的な振幅 (0 から 1 まで) を取得します。

だけにこれらの値は正弦波発振を制御する使用する場合は、それ、テルミンのようにまったく音がされません。 画面上で指を移動すると、プログラム イベント途中のすべての単一のピクセルを取得していません。 スムーズな周波数滑空ではなく、非常にステップを聞きます。 この問題を解決するに示すように、特別な発振器クラスを作成した図 2。 この発振器周波数プロパティを継承が 3 つ以上のプロパティを定義します。振幅、DestinationAmplitude と DestinationFrequency。 乗算係数を使用して、グライダー、発振回路そのものを提供します。 コードは実際にどのように高速指移動、予測することはできませんが、ほとんどの場合、[ok] を動作するようです。

図 2 ThereminOscillator クラス

public class ThereminOscillator : Oscillator
{
  readonly double ampStep;
  readonly double freqStep;
  public const double MIN_AMPLITUDE = 0.0001;
  public ThereminOscillator(int sampleRate)
    : base(sampleRate)
  {
    ampStep = 1 + 0.12 * 1000 / sampleRate;     // ~1 db per msec
    freqStep = 1 + 0.005 * 1000 / sampleRate;   // ~10 cents per msec
  }
  public double Amplitude { set; get; }
  public double DestinationAmplitude { get; set; }
  public double DestinationFrequency { set; get; }
  public override short GetNextSample(double angle)
  {
    this.Frequency *= this.Frequency < this.DestinationFrequency ?
freqStep : 1 / freqStep;
    this.Amplitude *= this.Amplitude < this.DestinationAmplitude ?
ampStep : 1 / ampStep;
    this.Amplitude = Math.Max(MIN_AMPLITUDE, Math.Min(1, this.Amplitude));
    return (short)(short.MaxValue * this.Amplitude * Math.Sin(angle));
  }
}

図 3 Touch.FrameReported イベントのハンドラーを Page クラスに示します。 指は最初、画面に触れると、サウンドにボリューム上昇ので振幅を最小値に設定されます。 指を離すと、音がフェードアウトします。

図 3 でテルミン Touch.FrameReported ハンドラー

void OnTouchFrameReported(object sender, TouchFrameEventArgs args)
{
  TouchPointCollection touchPoints = args.GetTouchPoints(ContentPanel);
  foreach (TouchPoint touchPoint in touchPoints)
  {
    Point pt = touchPoint.Position;
    int id = touchPoint.TouchDevice.Id;
    switch (touchPoint.Action)
    {
      case TouchAction.Down:
        oscillator.Amplitude = ThereminOscillator.MIN_AMPLITUDE;
        oscillator.DestinationAmplitude = CalculateAmplitude(pt.Y);
        oscillator.Frequency = CalculateFrequency(pt.X);
        oscillator.DestinationFrequency = oscillator.Frequency;
        HighlightLines(pt.X, true);
        touchID = id;
        break;
      case TouchAction.Move:
        if (id == touchID)
        {
           oscillator.DestinationFrequency = CalculateFrequency(pt.X);
           oscillator.DestinationAmplitude = CalculateAmplitude(pt.Y);
           HighlightLines(pt.X, true);
        }
        break;
      case TouchAction.Up:
        if (id == touchID)
        {
          oscillator.DestinationAmplitude = 0;
          touchID = Int32.MinValue;
          // Remove highlighting
          HighlightLines(0, false);
        }
        break;
      }
    }
}

コードを見ることができます、テルミン プログラムだけ、1 つのトーンを生成し、複数の指を無視します。

テルミン周波数を継続的に異なりますが、画面ではそれにもかかわらず離散ノートを示す行が表示されます。 これらの行は赤 C と F (ハープの文字列を使用されている色) のブルー ・ ナチュラルの白とグレーの小節 (シャープ)。 プログラムをしばらくプレイした後、私は、タッチ ポイントからの距離を広げる行はように実際に指の位置がどのようなメモをに基づいてを示すいくつかの視覚的フィードバックを必要なことを決めた。 図 4、指が C と c# が近い ~ C が表示されます

The Theremin Display
図 4 は、テルミンの表示

遅延、歪み

1 つの大きな問題のソフトウェア ベースの音楽合成の遅延のある — ユーザー入力と、後続の変更で音の間隔。 これはほとんど避けられない。Silverlight でオーディオのストリーミングとアプリケーションは MediaStreamSource から派生して、メモリを通じてオーディオ データを提供する GetSampleAsync メソッドをオーバーライドが必要です­ストリーム オブジェクト。 内部的には、このオーディオ データをバッファーに保持されます。 このバッファーの存在は当惑のギャップなしサウンドの再生が、もちろん、バッファーの再生は常にバッファーの充填の背後にある歩道はことができます。

幸いにも、MediaStreamSource ミリ秒のサウンド バッファーのサイズを示す AudioBufferLength という名前のプロパティを定義します。 (このプロパティは保護されており、メディアを開く前に MediaStreamSource 派生のみに設定することができます。)既定値は 1,000 です (1 秒) が、低 15 として設定することができます。 低い設定、OS と MediaStreamSource 誘導体の相互作用を増加し、音のギャップがあります。 しかし、私は 15 の最小設定が満足するように.

別の潜在的な問題だけデータをクランクことができないです。 プログラムを数十または何百もの何千もの 1 秒あたりのバイトを生成する必要があり、これを効率的に行うことはできません分割、サウンドを開始して、多くの音を聞きます。

この問題を解決するには、数とおりの方法があります。あなたのオーディオの世代のパイプライン (後に説明するように) より効率的なことができます。 またはサンプリング率を減らすことができます。 見つけた 44,100 の CD サンプリング レートは、あまりにも多くの私のプログラムでは、され、私は 22,050 にかかった。 さらに 11,025 削減も必要があります。 常に、いくつかの異なる Windows Phone デバイス上のオーディオ プログラムをテストする良いです。 商用製品では、おそらくサンプリング レートを減らすオプション、ユーザーする必要があります。

複数の発振器

ミキサー コンポーネント シンセサイザー ライブラリの複合の左と右のチャネルに複数の入力を組立の仕事があります。 これは非常に簡単な仕事ですが、各入力、16 ビットの振幅と波形は入力アッテネータをする必要がありますので、出力、16 ビットの振幅と波形もことに注意してください­どのように多くのそこに基づく uated。 たとえば、10 の入力ミキサー コンポーネントがある場合は、各入力が元の値の 10 分の 1 に減衰する必要があります。

これは深遠な意味があります。ミキサー入力を追加または増加または、残りの入力量を減らすことがなく音楽の再生中は削除できません。 25 の異なる音が一度に再生することができます可能性のあるプログラムをする場合は、25 の定数ミキサー入力必要があります。

これは、ハープ アプリケーションで、MusicalInstruments ソリューションの場合です。 私は私の指先を抜く可能性がある文字列の楽器を想定が、私はまた、共通のハープ グリッサンド音を演奏しながらでした。

見ることができます図 5、視覚的に非常に似ています、テルミンが 4 ではなく、唯一の 2 つのオクターブ。 ナチュラル下部はややクロス神経質ハープとして知られているハープの種類を模倣が小節 (シャープ) の文字列は、上部には、配置されます。 ペンタトニック グリッサンド (上部)、波長のグリッサンド (真ん中) または、音階グリッサンド (底面) を実行できます。

The Harp Program
図 5 ハープ プログラム

実際の音を私は肉眼、文字列の音に近い単純な鋸歯状波形を生成、SawtoothOscillator クラスの 25 のインスタンスを使用しました。 それも、初歩的なエンベロープ発電機を作る必要があります。 実際の生活では、音楽の音はありません開始し、瞬時に停止。 音予定を取得するは時間がかかると、それ自体でフェードアウトがあります (などピアノやハープ)、または、ミュージシャンのそれを再生を停止した後にフェードアウトがあります。 エンベロープ ジェネレーターは、これらの変更を制御します。 単純な AttackDecayEnvelope クラスを作成は何か、本格的な攻撃崩壊維持リリース (ADSR) エンベロープとして高度な必要はなかった。 (実際の生活、音の音色 — その高調波成分が支配 —、音色は、エンベロープ ジェネレーターによっても制御する必要がありますまた、シングル トーンの期間にわたって変更します)。

視覚的なフィードバックを私は振動する文字列と思ったことを決めた。 各文字列は、実際には、二次ベジエ セグメント、中央制御ポイント、2 つの端点と共にです。 繰り返し PointAnimation をコントロール ポイントに適用することによって、振動文字列はことができます。

実際には、これは、災害だった。 振動が素晴らしい見たがサウンド極端なパチパチ醜さに転落しました。 私は何か、もう少し深刻なスイッチ。DispatcherTimer を使用し、手動で、実際のアニメーションよりもはるかに遅い速度でポイントのオフセットします。

文字列を摘採のために必要な素早く動かすジェスチャで不幸だったが、ハープ プログラムで少し遊んで後、だから私はちょうど軽く叩くことで、サウンドをトリガーするには、いくつかコードを追加しました。 この時点で、私はおそらく、プログラムの名前ハープから HammeredDulcimer に変更する必要がありますが、私は行くことができます。

浮動小数点の回避

私はほとんど私の開発のため使用していた、Windows Phone デバイス上でハープを見事に働きました。 別の Windows Phone には非常にパチパチ音を立てて、バッファーを迅速に十分な入力いないことを示します。 この分析は、サンプリング レートを半減することによって確認されました。 パチパチ 11、025 Hz のサンプリング レートを停止が、私は、サウンドの品質を犠牲にする準備ができていません。

代わりに、パイプラインをよく見て、撮影を開始したこれらの何千もの 1 秒あたりのサンプルを提供します。 これらのクラス-ミキサー、MixerInput、SawtoothOscillator、AttackDecayEnvelope — すべて共通の 1 つの事をしていた。彼らはすべてこれらのサンプルを計算するためにいくつかの方法で浮動小数点演算を使用しました。 これを高速化計算に役立つ整数に切り替え、違いを作るのに十分なパイプラインでしたか?

整数の算術演算子を使用する私の AttackDecayEnvelope のクラスを書き直し、同じものが表示されます、SawtoothOscillator は、 図 6。 これらの変更は、パフォーマンスを大幅に向上します。

図 6 SawtoothOscillator の整数バージョン

public class SawtoothOscillator : IMonoSampleProvider
{
  int sampleRate;
  uint angle;
  uint angleIncrement;
  public SawtoothOscillator(int sampleRate)
  {
    this.sampleRate = sampleRate;
  }
  public double Frequency
  {
    set
    {
      angleIncrement = (uint)(UInt32.MaxValue * value / sampleRate);
    }
    get
    {
      return (double)angleIncrement * sampleRate / UInt32.MaxValue;
    }
  }
  public short GetNextSample()
  {
    angle += angleIncrement;
    return (short)((angle >> 16) + short.MinValue);
  }
}

浮動ポイント、角度と角度を使用して、発振器の­変数は、角度範囲 0 から 2 π に angleIncrement の計算タイプのダブル インクリメントましょう。

各サンプルについては、角度によって angleIncrement になりました。

SawtoothOscillator から完全浮動小数点を排除しなかった。 公共の周波数特性がまだは double として定義されていますが、発振器の周波数が設定されている場合にのみ使用されます。 角度と angleIncrement の両方は、符号なし 32 ビット整数です。 フルの 32 ビット値は angleIncrement の角度の値が増加が最上部の 16 ビットのみ波形を計算するため、値として使用するときに使用されます。

これらの変更をプログラムまだも今の私」低速電話」私「高速電話と比較すると」思うに動作しない全体の画面上で指を掃除いくつかパチパチまだが発生します。

楽器の真実であるものも電子音楽楽器を true:楽器と身近になるし、その力だけでなくその限界を知っている必要があります。

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

この記事のレビュー、次の技術的な専門家のおかげでに: Mark Hopkins