テンポとピッチの変更について
こうじろう  2014/11/19(Wed) 00:13
お世話になっております。

「テンポとピッチの変更」に関してお伺いしたいのですが,
今後のアップデートの中でリアルタイムにテンポとピッチの変更が可能になることはございますでしょうか?

今のところsetPosSec()で無理やりテンポの変更を行っているのですが,方法上ノイズが大きくなってしまうので
タイムストレッチのアルゴリズムを1から勉強しようか迷っています。

もし実装が可能であればご検討いただけないでしょうか。
また,現段階で参考となる手段があればご助言頂けると幸いです。

宜しくお願い致します。
Reputeless  2014/11/19(Wed) 07:05
再生中のテンポ・ピッチ変更は将来実装予定です。優先度を高くして対応します。
現時点では、再生している Wave の編集には対応していないため、setPos を使うのが簡単だと思います。

ノイズを低減するには、同じ曲の Sound を 2 つ以上用意し、
setPos & play を交互の Sound で行い、切り替えの際にボリュームのフェードイン・フェードアウトをすると良いかもしれません。
こうじろう  2014/11/19(Wed) 14:34
ご返答頂きありがとうござます。
私のほうでも少しずつ勉強してみたいと思います。

関連して基礎的な質問になってしまい大変恐縮なのですが、
先日「Windows SDK内のMediaPlayerクラスでタイムストレッチが可能」という情報を見つけて
試しにやってみたところ「'/clr' と '/MTd' は同時に指定できません」とのエラーでした。
CLRとの組み合わせは基本的に出来ないという認識で宜しいでしょうか?
Reputeless  2014/11/19(Wed) 23:04
CLR は Siv3D では使用できません。

Windows Media Player SDK のタイムストレッチ機能はこれでしょうか。
http://blogs.msdn.com/b/windows_multimedia_jp/archive/2009/03/04/9458418.aspx

Siv3D ではオーディオファイルの形式を問わない実装を目指しています。
こうじろう  2014/11/19(Wed) 23:44
ありがとうございます。
勉強になりました。
今のところは、setPosを使う際にwave波形を手掛かりにして接続位置を調整するようにしてみます。

ご対応頂き、ありがとうございました。
実装のほど宜しくお願い致します。
こうじろう  2014/11/22(Sat) 03:42
三度失礼致します。

同じ曲の Soundを用いて切り替えを行う際に、
ボリュームのフェードイン・フェードアウトをマルチスレッドで行うことは可能でしょうか?
具体的には以下の部分を並列処理できないかと考えています。
方法があればご教示いただけると幸いです。

宜しくお願い致します。


while (System::Update())
{
int i = System::FrameCount() % 2;
double soundPos = sound[i].posSec + (timer.elapsed() / 1000.0 - beforeTime) * (soundRate - 1);
beforeTime = timer.elapsed() / 1000.0;
sound[1 - i].setVolume(0.0);
sound[1 - i].setPosSec(soundPos);

// ↓↓↓↓↓↓↓↓↓↓ ここから ↓↓↓↓↓↓↓↓↓↓
double j = 0;
while (j < 3.0)
{
j += 0.001;
System::Sleep(0.001);
sound[i].setVolume(1.0 - j / 3.0);
sound[1 - i].setVolume(j / 3.0);
}
// ↑↑↑↑↑↑↑↑↑↑ ここまで ↑↑↑↑↑↑↑↑↑↑
}
こうじろう  2014/11/27(Thu) 13:53
お世話になっております。
マルチスレッドではないですが、自己解決しました。
もっと効率的で音質がいい方法があればご教示いただけると幸いです。


class PlaySound
{
private:
double fade = 30.0;
double resolution = 0.001;
double time = 0;
public:
Sound sound[3];
TimerMicrosec tm;
void Update(double pos, double vol)
{
if (sound[2].isPlaying)
{
if ((System::FrameCount() % 10) % 5 == 0)
{
int i = 1;
if (System::FrameCount() % 10 < 5)
{
i = 0;
}

sound[1 - i].setPosSec(pos);
sound[2].setPosSec(pos);

time = 0;
double s = (double)tm.elapsed() / 1000.0;
while (time < fade / 5.0)
{
System::Sleep(resolution);
time = (double)tm.elapsed() / 1000 - s;
sound[i].setVolume((fade - time) / fade * vol);
sound[1 - i].setVolume(time / fade * vol);
}
}
else if ((System::FrameCount() % 10) % 5 == 1)
{
int i = 1;
if (System::FrameCount() % 10 < 5)
{
i = 0;
}
sound[2].setPosSec(pos);
double time2 = time;
double s = (double)tm.elapsed() / 1000.0;
while (time < fade * 2.0 / 5.0)
{
System::Sleep(resolution);
time = time2 + (double)tm.elapsed() / 1000 - s;
sound[i].setVolume((fade - time) / fade * vol);
sound[1 - i].setVolume(time / fade * vol);
}
}
else if ((System::FrameCount() % 10) % 5 == 2)
{
int i = 1;
if (System::FrameCount() % 10 < 5)
{
i = 0;
}
sound[2].setPosSec(pos);
double time2 = time;
double s = (double)tm.elapsed() / 1000.0;
while (time < fade * 3.0 / 5.0)
{
System::Sleep(resolution);
time = time2 + (double)tm.elapsed() / 1000 - s;
sound[i].setVolume((fade - time) / fade * vol);
sound[1 - i].setVolume(time / fade * vol);
}
}
else if ((System::FrameCount() % 10) % 5 == 3)
{
int i = 1;
if (System::FrameCount() % 10 < 5)
{
i = 0;
}
sound[2].setPosSec(pos);
double time2 = time;
double s = (double)tm.elapsed() / 1000.0;
while (time < fade * 4.0 / 5.0)
{
System::Sleep(resolution);
time = time2 + (double)tm.elapsed() / 1000 - s;
sound[i].setVolume((fade - time) / fade * vol);
sound[1 - i].setVolume(time / fade * vol);
}
}
else
{
int i = 1;
if (System::FrameCount() % 10 < 5)
{
i = 0;
}
sound[2].setPosSec(pos);

double time2 = time;
double s = (double)tm.elapsed() / 1000.0;
while (time < fade)
{
System::Sleep(resolution);
time = time2 + (double)tm.elapsed() / 1000 - s;
sound[i].setVolume((fade - time) / fade * vol);
sound[1 - i].setVolume(time / fade * vol);
}
sound[i].setVolume(0);
sound[1 - i].setVolume(vol);
}
}
}
};

void Main()
{
PlaySound ps;
// DoInitialization();
// ・・・・・
// ・・・・・

while (System::Update())
{
// DoSomething();
// ・・・・・
// ・・・・・

double pos = ps.sound[2].posSec + (timer.elapsed() / 1000.0 - beforeTime) * (ratio - 1);
beforeTime = timer.elapsed() / 1000.0;
ps.Update(pos, volume);
}
}
Reputeless  2014/11/28(Fri) 13:44
回答が遅くなました。

細かいところまでは追えていませんが、上記の実装に大きな問題はないように思えます。
ただ、10 ミリ秒より小さい Resolution はパフォーマンスを低下させるだけで、音質には寄与しないと思われます。

近い将来のバージョンで、Sound のフェードイン・フェードアウトを機能として実装することにしました。
現時点で Sound に対してマルチスレッドのコードを書くと、将来互換性の問題が生じる恐れがある点、ご注意ください。

- WEB PATIO -