4

それで、私は長い休止の後にC ++を手に入れ、実行時に数字の文字列に基づいて音楽を生成できるプログラムを作成するというアイデアを思いつきました(一部の人々によって行われたPiの構成に触発されました)。一種の手続き型音楽生成ソフトウェア。

これまでのところ、Beep()関数を使用してこれの本当に原始的なバージョンを作成し、テストとしてPiの最初の桁をフィードすることができました。チャームのように機能します。

私が今探しているのは、それをワンランク上に上げて、より高品質のサウンドを作成する方法です(Beep()は文字通り最も原始的なサウンドであるため...)そして私はどうすればよいかまったくわからないことに気づきましたこれを行う。私が必要としているのは、次のことができるライブラリまたはある種のAPIです。

1)既存のファイルなしでサウンドを生成します。最適には、結果をコードによって100%生成し、サンプルに依存しないようにします。

2)コードやビートのあるメロディーを演奏できるなど、一度に複数の音を演奏できるようなことができれば、それは素晴らしいことです。

3)そして、方程式や他の種類のデータを介して、それが再生する波を何らかの方法で制御できれば(チップチューンミキサーのように)、それは非常に役立ちます。

これが奇妙なリクエストなのか、間違った用語を使用して調査しただけなのかはわかりませんが、これらの線に沿って何も見つからなかったか、少なくとも十分に文書化されたものは何も見つかりませんでした。:/

誰か助けていただければ幸いです。

編集:また、どうやら私はフォーラムで何かを尋ねるのに慣れていないようです。私のターゲットプラットフォームはWindowsです(具体的には、7、それは重要ではないと思いますが)。

4

2 に答える 2

2

私はportaudio(http://www.portaudio.com/)を使用しています。ポータブルな方法でPCMストリームを作成できます。次に、サンプルをストリームにプッシュするだけで、サンプルが再生されます。

@edit:PortAudioの使用はとても簡単です。ライブラリを初期化します。浮動小数点サンプルを使用して、非常に簡単にします。私はこのようにします:

PaError err = Pa_Initialize();
if ( err != paNoError ) 
   return false;

mPaParams.device = Pa_GetDefaultOutputDevice();
if ( mPaParams.device == paNoDevice ) 
   return false;

mPaParams.channelCount = NUM_CHANNELS;
mPaParams.sampleFormat = paFloat32;
mPaParams.suggestedLatency = 
   Pa_GetDeviceInfo( mPaParams.device )->defaultLowOutputLatency;
mPaParams.hostApiSpecificStreamInfo = NULL;

その後、サウンドを再生したいときに、ステレオ用に2チャンネル、44kHzで、mp3オーディオに適したストリームを作成します。

PaError err = Pa_OpenStream( &mPaStream,
                             NULL, // no input
                             &mPaParams,
                             44100, // params
                             NUM_FRAMES, // frames per buffer
                             0,
                             sndCallback,
                             this
                           );

次に、コールバックを実装してPCMオーディオストリームを満たします。コールバックはac関数ですが、オーディオを処理するためにC++クラスを呼び出すだけです。これをコードからリッピングしましたが、気にしないものを大量に削除したため、100%正しくない可能性があります。しかし、その動作は次のようになります。

static int sndCallback( const void*                     inputBuffer, 
                        void*                           outputBuffer,
                        unsigned long                   framesPerBuffer,
                        const PaStreamCallbackTimeInfo* timeInfo,
                        PaStreamCallbackFlags           statusFlags,
                        void*                           userData )
{
  Snd* snd = (Snd*)userData;
  return snd->callback( (float*)outputBuffer, framesPerBuffer );
}

u32 Snd::callback( float* outbuf, u32 nFrames )
{
   mPlayMutex.lock(); // use mutexes because this is asyc code!

   // clear the output buffer
   memset( outbuf, 0, nFrames * NUM_CHANNELS * sizeof( float ));

   // mix all the sounds.
   if ( mChannels.size() ) 
   {   
      // I have multiple audio sources I'm mixing. That's what mChannels is.
      for ( s32 i = mChannels.size(); i > 0; i-- ) 
      {
         for ( u32 j = 0; j < frameCount * NUM_CHANNELS; j++ ) 
         {
             float f = outbuf[j] + getNextSample( i ) // <------------------- your code here!!!
             if ( f >  1.0 ) f = 1.0;     // clamp it so you don't get clipping.
             if ( f < -1.0 ) f = -1.0;
             outbuf[j] = f;
         }
      }
   }
   mPlayMutex.unlock_p();
   return 1; // when you are done playing audio return zero.
}
于 2012-07-26T21:24:13.530 に答える
0

私は今週初めにこれについて非常によく似た質問に答えました:ノートシンセシス、ハーモニクス(バイオリン、ピアノ、ギター、ベース)、周波数、MIDI。あなたの場合、サンプルに頼りたくないのなら、ウェーブテーブルメソッドは出ています。したがって、最も簡単なオプションは、正弦波の周波数と振幅を時間の経過とともに動的に変化させることです。これは簡単ですが、かなりひどい音になります(安価なテルミンのように)。唯一の現実的なオプションは、物理モデリングアルゴリズム(Karplus-Strongなど)のような、より洗練された合成アルゴリズムです。これは興味深いプロジェクトですが、数学的な背景が必要になることに注意してください。

RafaelがPCからサウンドを物理的に取り出すために言及したように、Portaudioのようなものを実際に使用できます。実際、Portaudioがそのための最良のオプションだと思います。しかし、音楽的に聞こえるようにデータを生成することは、はるかに最大の課題です。

于 2012-07-26T22:48:34.610 に答える