2017-09-05 8 views
2

私は、C++やコンパイルされた言語では一般的に新しく、強力な解釈の背景を持っているので、コンパイル時に特定のものにアクセスできないという限界を克服しようとしています。現時点ではコードブロックをループに最適化する

は、私はこのようなコードの大きなブロックを持っている:

//New note, note36 

MemoryInputStream* input36 = new MemoryInputStream(BinaryData::C1hard1_wav, BinaryData::C1hard1_wavSize, false); 
auto reader36 = audioFormatManager.createReaderFor(input36); 

BigInteger note36; 
note36.setRange(36, 1, true); 

addSound(new SamplerSound("note36", *reader36, note36, 36, 0.001, 0.01, 26.0)); 

delete input36; 
delete reader36; 

//New note, note37 

MemoryInputStream* input37 = new MemoryInputStream(BinaryData::Csharp1hard1_wav, BinaryData::Csharp1hard1_wavSize, false); 
auto reader37 = audioFormatManager.createReaderFor(input37); 

BigInteger note37; 
note37.setRange(37, 1, true); 

addSound(new SamplerSound("note37", *reader37, note37, 37, 0.001, 0.01, 26.0)); 

delete input37; 
delete reader37; 

このコードは、この方法で48回繰り返し、これは良い方法ではありません。私はPHP、インタプリタ言語でこれを達成する方法の例は、この

$noteMap = array(36 => "C1", 37 => "Csharp1"); 

foreach($noteMap as $midiNumber => $note) 
{ 
    $name = $note . "hard1_wav"; 
    $size = $note . "hard1_wavSize"; 

    $input = new MemoryInputStream(BinaryData::$name, BinaryData::$size, false); 
    $reader = audioFormatManager->createReaderFor($input); 

    //I know this bit is bad PHP, no bigintegers in PHP but I can't think of a way to replicate it for arguments sake 
    $note = 0; 
    $note->setRange($midiNumber, 1, true); 

    addSound(new SamplerSound("note".$midiNumber, $reader36, $note, $midiNumber, 0.001, 0.01, 26.0)); 
} 

これは、はるかに管理し、再利用可能であるようになります。私が行った変更はファイル全体で慎重に繰り返す必要はなく、変更はすばやく行うことができます。私は関数名として変数を渡すことはコンパイルされた言語で行われるものではないことを知っていますが、それを考慮に入れても、大規模なコードブロックをきちんとしたループにまとめる方法が必要です。私にそれを。

+1

これをC++で行うことはできません。変数名は実行時には変更できません。読者とMIDIチャンネルには 'std :: vector'や別のコンテナを使い、代わりにそのチャンネルをループします。 – user0042

+1

C++では、マップの 'std :: map'を使うことができ、' foreach'の 'for'の範囲を使うことができます。そして、あなたは 'input'や' reader'に対して非効率な動的割り当てを使う必要はありません。 –

+1

@ user0042:彼のコードは実行時の変数名を必要としません。 –

答えて

1

BinaryDataがJUCEで生成されたリソースファイルであると仮定すると、次のアルゴリズムはPHPバージョンと同等である必要があります。これは動的変数名を使用せず、代わりにに表示されるBinaryData::getNamedResource関数を使用します。

std::map<int, std::string> note_map{{36, "C1"}, {37, "Csharp1"}}; 
for (const auto& note : note_map) { 
    BigInteger midi_bit; 
    midi_bit.setBit(note.first); 

    int size; 
    std::string note_resource = note.second + "hard1_wav"; 
    auto data = BinaryData::getNamedResource(note_resource.c_str(), size); 

    auto input = new MemoryInputStream(data, size, false); 
    auto reader = audioFormatManager->createReaderFor(input); 

    auto note_name = "note" + std::to_string(note.first); 
    addSound(new SamplerSound(note_name.c_str(), *reader, midi_bit, 
           note.first, 0.001, 0.01, 26.0)); 
} 

別の(悪い)溶液は、次のようなコードのものを生成するために、Cプリプロセッサを使用することである。

#define note(num, name)                        \ 
    MemoryInputStream* input##num = new MemoryInputStream(BinaryData::name##_wav, BinaryData::name##_wavSize, false); \ 
    auto reader##num = audioFormatManager.createReaderFor(input##num);            \ 
    BigInteger note##num;                        \ 
    note##num.setBit(num);                       \ 
    addSound(new SamplerSound("note" #num, *reader##num, note##num, num, 0.001, 0.01, 26.0));       \ 
    delete input##num;                        \ 
    delete reader##num 
note(36, C1); 
note(37, Csharp1); 

次のコードは、前処理段階によって生成される:

MemoryInputStream* input36 = new MemoryInputStream(BinaryData::C1_wav, BinaryData::C1_wavSize, false); auto reader36 = audioFormatManager.createReaderFor(input36); BigInteger note36; note36.setBit(36); addSound(new SamplerSound("note" "36", *reader36, note36, 36, 0.001, 0.01, 26.0)); delete input36; delete reader36; 
MemoryInputStream* input37 = new MemoryInputStream(BinaryData::Csharp1_wav, BinaryData::Csharp1_wavSize, false); auto reader37 = audioFormatManager.createReaderFor(input37); BigInteger note37; note37.setBit(37); addSound(new SamplerSound("note" "37", *reader37, note37, 37, 0.001, 0.01, 26.0)); delete input37; delete reader37; 

プリプロセッサソリューションは、現在のソリューションと同等のコードでなければなりませんが、一般に、このようにマクロを使用して多数の変数を生成するのはあまり良い方法ではありません。上記のランタイムソリューションは、プリプロセッサを使用するよりも優先されるべきです。

+0

JUCE Frameworkのコードであることがよく分かります。私はJUCEの特定の答えがあるとは思わなかったので、私は元の質問に言及しなかった。あなたの答えは私が必要としているもののように見えますが、現状ではホストアプリケーションがうまくコンパイルされてもクラッシュする原因になります! – Richie

+1

ノート名の "_wav"部分を忘れたからだと思います。私はそれを含めるように私の答えを編集します。 '#include 'と 'assert(data)'を使って 'getNamedResource'によって返されたポインタが' nullptr'でないことを確認できます。 – Jonesinator

+1

私はJUCEがメモリ管理を行う方法に慣れていません。 JUCEがメモリの所有権を持っていない場合、ループ内で 'new'で作成された項目を'削除 'する必要があるかもしれません。私は 'delete'ステートメントをループに含めませんでしたが、元のコードにあります。 – Jonesinator

0

はないこと、あなたが新しい呼び出し、すべてのノートに削除リソース、のような無駄を行います。

は、std::vectorまたはstd::mapとして、代わりにデータ構造を使用します。

あなたはその要素を反復処理することができ、あなたのデータ構造を記入したら。

+0

これは単なる配列なので、これらの値には文字列だけのデータはありません。これらの文字列はメソッド名として解釈され、C++では全く不可能なものだと私は思っていますので、その解決策が何であるか分かりません。 – Richie

+0

@ Richie、u r right! – gsamaras

1

あなたはこのような何かを行うことができます。

typedef void (FuncPtr)(int x); 
void C1Func(int x); 
void CSharpFunc(int x); 

void someFunc() { 
    const Input input = new MemoryInputStream(name, size, false); 
    const Reader reader = audioFormatManager->createReaderFor(input); 

    // note: gxx syntax here, may not be supported in other versions...  
    Note noteMap[48] = { [36]=Note(36,C1Func), [37]=Note(37,CSharpFunc) }; 
    String name, size; 

    for (int i = 0; i < arraySizeOf(noteMap); i++) { 
     Note * note = noteMap[i]; 
     if (!note->isInitialized()) 
      continue; 
     name = note + "hard1_wav"; 
     size = note + "hard1_wavSize"; 
     note->setRange(i,1,true); 
     std::string name = "note"+i; 
     addSound(new SamplerSound(name, reader, note[i], i, 0.001, 0.01, 26.0)); 
    } 
    delete input; 
    delete reader; 
} 

あなたは、コンストラクタ(Note::Note(int idx,FuncPtr fn))とNoteクラスが必要になります。また、配列の初期化はgnuに固有なので、代わりにstd::mapまたは同等のものを使用する必要があります(またはINVALID_NOTEを無効として定義し、INVALID_NOTE,の束を追加して他の配列メンバーを空とマークします)。