新しく発言する EXIT インデックスへ
再び質問です

  再び質問です たかし 2005/02/21 16:09:40 
  >letlch=int(sgn(sin(i*k))*al+0.5)! 青木太一 2005/02/22 07:36:46 
   └詳しい説明ありがとうございます たかし 2005/02/25 17:19:43 
    └・どのくらいの詳しさが必要なのか? 青木太一 2005/02/28 01:41:43 
     └返事ありがとうございます。 たかし 2005/02/28 14:29:37 
      └時間がないのでざっと回答してみると、 青木太一 2005/03/01 14:33:11 
       └ご丁寧な説明ありがとうございます たかし 2005/03/02 23:15:21 
        └410行目のFOR文でなぜ1からd*fsまで処理... 青木太一 2005/03/03 07:55:30 
         └for文の部分もだいたいわかってきました たかし 2005/03/03 15:15:49 
          └基本的には間違っていないと思います。 青木太一 2005/03/03 22:04:03 
           └ありがとうございます たかし 2005/03/05 12:37:12 
            └質問の答えになってませんが ニコール・パックマン 2005/07/19 18:30:00 

  再び質問です たかし 2005/02/21 16:09:40  ツリーへ

再び質問です 返事を書く
たかし 2005/02/21 16:09:40
以前お世話になったたかしです。青木さん覚えてますか?
何度も質問して本当にすいませんm(__)m
以前質問した音声ファイルを生成するプログラム(以下に示します)のアルゴリズムを卒論で書かなければならなくなり、ほとんどわからないのでアドバイスよろしくお願いします。おおまかには、わかるのですが特に

let lch=int(sgn(sin(i*k))*al+0.5)!

上の式がどうしてsin関数の中がi*kで最後にalをかけて0.5を足すのかなど全くわかりません

LET audio$=audio$&chr$(mod(lch,256))&chr$(int(lch/256))&chr$(mod(rch,256))&chr$(int(rch/256))

また、上のプログラムの意味は全くわかりません
全体的なアルゴリズムを含めて説明、宜しくお願いいたします
(以下にプログラムを示します)


REM 矩形波の音声ファイル生成プログラム
REM (L、R: 矩形波)
OPTION CHARACTER BYTE
let d=10 !継続時間(秒)
let f0=1000 !正弦波周波数(Hz)
let db=-10 !生成波形の最大値(±32767を0dBとする)
let fs=44100 !標本化周波数(Hz)
let bps=fs*4 !1秒当りのデータ量(ステレオ16ビット量子化)
let dsize=d*fs*4 !オーディオデータサイズ
let fsize=dsize+36 !ファイルサイズ(先頭8Bを除く)
let fmtsize=16 !フォーマットサイズ
let channel=2^17+1 !ステレオPCMデータの指定
let reso=2^20+4 !16ビットの指定
let a=10^(db/20)
open #6 : name "test.wav" !ファイルを開き、この名前のファイルが
erase #6 !既に存在していた場合には上書きを指定
let t0=time
print #6 : "RIFF"; !以下、wavファイルのヘッダーを作成
call out4(fsize) !
print #6 : "WAVEfmt "; !
call out4(fmtsize) !
call out4(channel) !
call out4(fs) !
call out4(bps) !
call out4(reso) !
print #6 : "data"; !
call out4(dsize) !ここまでがヘッダー用の出力
let al=a*32767 !左チャネル係数
let k=f0/fs*pi*2 !引数の刻み
let audio$="" !オーディオデータバッファを初期化
let count=0 !カウンタをリセット
for i=1 to d*fs
let lch=int(sgn(sin(i*k))*al+0.5)!
if lch<0 then let lch=lch+65536 !負の数は補数表現
rch=lch
LET audio$=audio$&chr$(mod(lch,256))&chr$(int(lch/256))&chr$(mod(rch,256))&chr$(int(rch/256))
LET count=count+1
if count=64 then !バッファデータが所定の長さ(64サンプル256Bがほぼ最適)に達したら
print #6 : audio$; !データをファイルに出力して
let audio$="" !バッファを初期化し
let count=0 !カウンタをリセット
end if
next i
print #6 : audio$; !バッファに残ったデータを出力して
close #6 !ファイルを閉じる
print "elapsed time = ";time-t0;"seconds"
sub out4(i4) !4バイト整数の出力(little endian)
LET j4=i4
for m=0 to 3
print #6 : chr$(mod(j4,256));
LET j4=int(j4/256)
next m
end sub
END


  >letlch=int(sgn(sin(i*k))*al+0.5)! 青木太一 2005/02/22 07:36:46  ツリーへ

Re: 再び質問です 返事を書く
青木太一 2005/02/22 07:36:46
>let lch=int(sgn(sin(i*k))*al+0.5)!
>上の式がどうしてsin関数の中がi*kで最後にalをかけて0.5を足すのかなど全くわかりません

0.5足すのは、四捨五入にしたかったからじゃないかな。
int関数だけだと小数部切捨てなので。
最大レンジが±32767なので、0.5くらい違ったところでそう音が変わるとも思わないけど...私が気づかない理由があるのかもしれないです。

alは音量調節です。かけなかったら、sgn関数の出力は-1から1なので、レンジが±32767もあるなかで-1から1しか波形がうごかなかったらほとんど音が聞こえないでしょう。
alが前の方でどうつくられているかに注目すればわkると思います。
>let a=10^(db/20)
>let al=a*32767 !左チャネル係数

sinの中がi*kなのは...
ここには「周波数×時刻」となる値がくるはずです。(よく教科書で「sin(ωt)」とか「sin(2πft)」ってなってますよね)
iはまあ時刻みたいなものです。正確には一標本化するごとに値が一増えるので一秒間に標本化周波数(fs)のぶんの値だけ増える変数です。
kは一定値で、
>let k=f0/fs*pi*2 !引数の刻み
と作られるわけですから、「音の周波数/標本化周波数*2π」です。
よって、i*kと掛け合わせると標本化周波数が相殺されて2πftになるわけです。


>LET audio$=audio$&chr$(mod(lch,256))&chr$(int(lch/256))&chr$(mod(rch,256))&chr$(int(rch/256))
それぞれの関数(mod,int)の役割、文字列連結(&)の意味はヘルプで見ましたか?
audio$という文字列にどんどんあとから文字(ここではwavとして出力したい値に文字コードが相当する文字)を追加している処理です。
>chr$(mod(lch,256))&chr$(int(lch/256))
今回は16bit量子化のwavファイルなので、上8bitと下8bitを分けて出力してますね。(一文字が8bitなので)


全体的なアルゴリズムは、まずたかしさんが自分なりに(あいまいでもいいので)説明してみてください。

それぞれの変数の果たす役割、関数のとりうる値の範囲に注意しながらソースコードを読めばわかってくると思います。

   └詳しい説明ありがとうございます たかし 2005/02/25 17:19:43  ツリーへ

Re: >letlch=int(sgn(sin(i*k))*al+0.5)! 返事を書く
たかし 2005/02/25 17:19:43
詳しい説明ありがとうございます
返事遅れてすいません卒論発表会が先日あって、そっちの方が忙しかったもので
卒論発表会では、音声ファイルを生成するプログラムのアルゴリズムについては、触れずにすみました

全体的なアルゴリズムとしては、「WAVファイルのヘッダーを作成して音を生成して、最後に経過時間を出力する」程度の事しかわかりません。十進BASICの構文としては、ある程度理解できますがそれが音声ファイルを生成するのにどのように関係しているのかはわからない状態です。来週の水曜辺りには卒論を提出しないとまずいので自分で考えている時間もほとんどありません。本当にこうゆう状況にした自分が悪いのは分かっていますが…。ですから先に全体的なアルゴリズムを詳しく教えてくれませんか?卒論を仕上げてからどうしてそうゆうアルゴリズムになったのか考えたいと思います。よろしくお願いしますm(__)m

    └・どのくらいの詳しさが必要なのか? 青木太一 2005/02/28 01:41:43  ツリーへ

Re: 詳しい説明ありがとうございます 返事を書く
青木太一 2005/02/28 01:41:43
・どのくらいの詳しさが必要なのか?
・たかしさんはどこがわからないのか?
この二つがわからないことには有効なアドバイスができません。というか、
>「WAVファイルのヘッダーを作成して音を生成して、
> 最後に経過時間を出力する」
でいいと思うのですが...もっと分量がほしいのでしょうか?

一行一行について、ヘルプを読めばわかるようなことまで含めて、こと細かに解説されることをご希望なのでしょうか?
それは面倒なので私は遠慮しておきます。

もともとのコードにも豊富にコメントがつけてあるので、これ以上はあまり付け加えるところがないのです。
100 REM 矩形波の音声ファイル生成プログラム
110 REM (L、R: 矩形波)
!--------------- 各種設定
120 OPTION CHARACTER BYTE
130 let d=10 !継続時間(秒)
140 let f0=1000 !正弦波周波数(Hz)
150 let db=-10 !生成波形の最大値(±32767を0dBとする)
160 let fs=44100 !標本化周波数(Hz)
170 let bps=fs*4 !1秒当りのデータ量(ステレオ16ビット量子化)
180 let dsize=d*fs*4 !オーディオデータサイズ
190 let fsize=dsize+36 !ファイルサイズ(先頭8Bを除く)
200 let fmtsize=16 !フォーマットサイズ
210 let channel=2^17+1 !ステレオPCMデータの指定
220 let reso=2^20+4 !16ビットの指定
230 let a=10^(db/20)
240 open #6 : name "test.wav" !ファイルを開き、この名前のファイルが
250 erase #6 !既に存在していた場合には上書きを指定
260 let t0=time
!--------------- ヘッダ生成
270 print #6 : "RIFF"; !以下、wavファイルのヘッダーを作成
280 call out4(fsize) !
290 print #6 : "WAVEfmt "; !
300 call out4(fmtsize) !
310 call out4(channel) !
320 call out4(fs) !
330 call out4(bps) !
340 call out4(reso) !
350 print #6 : "data"; !
360 call out4(dsize) !ここまでがヘッダー用の出力
!--------------- オーディオデータ生成
370 let al=a*32767 !左チャネル係数
380 let k=f0/fs*pi*2 !引数の刻み
390 let audio$="" !オーディオデータバッファを初期化
400 let count=0 !カウンタをリセット
410 for i=1 to d*fs
420 let lch=int(sgn(sin(i*k))*al+0.5)!
430 if lch<0 then let lch=lch+65536 !負の数は補数表現
440 LET rch=lch
450 LET audio$=audio$&chr$(mod(lch,256))&chr$(int(lch/256))&chr$(mod(rch,256))&chr$(int(rch/256))
460 LET count=count+1
470 if count=64 then !バッファデータが所定の長さ(64サンプル256Bがほぼ最適)に達したら
480 print #6 : audio$; !データをファイルに出力して
490 let audio$="" !バッファを初期化し
500 let count=0 !カウンタをリセット
510 end if
520 next i
530 print #6 : audio$; !バッファに残ったデータを出力して
540 close #6 !ファイルを閉じる
550 print "elapsed time = ";time-t0;"seconds"

!-----副プログラム
560 sub out4(i4) !4バイト整数の出力(little endian)
570 LET j4=i4
580 for m=0 to 3
590 print #6 : chr$(mod(j4,256));
600 LET j4=int(j4/256)
610 next m
620 end sub
630 END


最初の発言のように個々の要素について御質問いただけると解説しやすいです。まあ、いま読み返す私の回答は乱暴な説明だったので、たかしさんにわかっていただけたか不安ですが...。

     └返事ありがとうございます。 たかし 2005/02/28 14:29:37  ツリーへ

Re: ・どのくらいの詳しさが必要なのか? 返事を書く
たかし 2005/02/28 14:29:37
返事ありがとうございます。
詳しさとしては、音声ファイルを生成するプログラムの概念を理解しているとみなされる程度の詳しさでお願いします(青木さんの返事をそのまま卒論にコピーするような事は決してしません)やはりさっき自分が示したアルゴリズムでは、分量的にもあまりにも少なすぎると思いますので。よろしくお願いします。

自分としては360行目あたりまでは、だいたいわかります。410行目のFOR文からからいまいちわかりません
具体的に説明しますと410行目のFOR文でなぜ1からd*fsまで処理を行うかや、なぜ64サンプルごとにデータをファイルに出力するかなどがわかりません。
あと、音声ファイルを生成する基礎的な事が理解できていない状態です。よろしくお願いします

      └時間がないのでざっと回答してみると、 青木太一 2005/03/01 14:33:11  ツリーへ

Re: 返事ありがとうございます。 返事を書く
青木太一 2005/03/01 14:33:11
時間がないのでざっと回答してみると、

>410行目のFOR文でなぜ1からd*fsまで処理を行うか
うーん、これが一番基本となるwavファイル生成のループなんだけど...
これがひとつひとつ進むごとにひとつのサンプリングぶんのデータを出力するのです。
「標本化」とか「量子化」ってわかりますか?わからなかったらWebや本で調べてください。

>なぜ64サンプルごとにデータをファイルに出力するか
これはわかりにくいですよね。論理的には1サンプルごとにファイル出力してもなんの問題もありません。
ではなぜわざわざ64サンプルぶんいったん文字列につなげてからファイル出力しているかと言えば、高速化のためだと思います。
ファイル入出力はハードディスクへのアクセスが必要です。
ハードディスクへのアクセスなんて人間にとっては一瞬のように感じられますが、
1・書き込み開始準備処理
2・書き込み
3・書き込み終了処理
にそれぞれ時間がかかります。とくに1と3にかかる時間が大きいなら、ある程度書き込むべき内容がたまってから一気に書き込んだほうが、全体的な書き込み処理が高速になります。
文字列連結の方は、ハードディスクより高速にアクセスできるメモリとのアクセスだけで済むので、とりあえず文字列連結でいったん書き込むべき内容をためているのです。
しかし、あまり長い文字列になってくると連結処理も大変になってくるので、ちょうどバランスがよい64サンプルにしているのです。
...と断定口調で書きましたが、きっとそうなんだと私は推測しています。
「バッファリング」という単語で調べてみてください。
(64という値が最適かどうかは環境によって違うと思います。
これは十進BASIC、Windows、ハードディスクやメモリの構成などシステムのいろんな要素がきいてきますので)

>音声ファイルを生成する基礎的な事
デジタル音声に関することは図書館に行くなりWebで調べてもらうなりして、
ファイルの生成に関しては、今回で言えばwavファイルの規格(フォーマット)のとおりにファイルを出力したとしか言えないです。
私は規格を読んだことがないのでなんともいえません。

せっかく具体的に聞いていただけたのに、いいかげんな回答しかできずすいません。

       └ご丁寧な説明ありがとうございます たかし 2005/03/02 23:15:21  ツリーへ

Re: 時間がないのでざっと回答してみると、 返事を書く
たかし 2005/03/02 23:15:21
ご丁寧な説明ありがとうございます
卒論の方は、予定を延期して今週中までに、出そうと思っています
これ以上延ばすと危なくなります

なぜ64サンプルごとにデータをファイルに出力するかは、青木さんの説明でだいたい理解できましたがやはり410行目のFOR文がわかりません。本やWebで標本化や量子化の事を調べましたがわかりません。自分としても410行目のFOR文が理解できればこのプログラムのアルゴリズムを書いても形にはなると思うので。面倒かもしれませんが説明よろしくお願いしますm(__)m本当にこの分野に詳しい友達は自分にはいないし、担当の教授は、すぐにキレるので恐くて質問できません、自分にとって分からない事を質問できるところはここしかないのでどうかよろしくお願いします

        └410行目のFOR文でなぜ1からd*fsまで処理... 青木太一 2005/03/03 07:55:30  ツリーへ

Re: ご丁寧な説明ありがとうございます 返事を書く
青木太一 2005/03/03 07:55:30
>>410行目のFOR文でなぜ1からd*fsまで処理を行うか
>うーん、これが一番基本となるwavファイル生成のループなんだけど...
>これがひとつひとつ進むごとにひとつのサンプリングぶんのデータを出力するのです。
>「標本化」とか「量子化」ってわかりますか?わからなかったらWebや本で調べてください。

これを詳しく書けばいいかな。
変数iは何回目のサンプリングかを表します。
では実際のところ何回サンプリングしたいのでしょう?

何秒間サンプリングしつづけるのですか?
>130 let d=10 !継続時間(秒)

一秒間に何回サンプリングするのですか?
>160 let fs=44100 !標本化周波数(Hz)

ということは、総サンプリング回数はd*fsで求まりますね。

         └for文の部分もだいたいわかってきました たかし 2005/03/03 15:15:49  ツリーへ

Re: 410行目のFOR文でなぜ1からd*fsまで処理... 返事を書く
たかし 2005/03/03 15:15:49
for文の部分もだいたいわかってきました
自分なりにこのプログラムのアルゴリズムを考えてみたので間違っていないかどうかチェックしてもらえませんか?よろしくお願いします。

音声ファイルを生成するプログラムのアルゴリズムとしては、最初に継続時間、正弦波周波数、生成波形の最大値、標本化周波数、1秒あたりのデータ量、オーディオデータサイズ、ファイルサイズ、フォーマットサイズなどの各種設定を定義する。次にWAVファイルのヘッダーを作成する。次にオーディオデータを生成する。その手順としては、最初にオーディオデータバッファを初期化し、1から44100(標本化周波数)×10(継続時間)までサンプリングする。ただし負の数は、補数表現として、オーディオデータを生成し、64サンプルごとにファイルに出力する。最後に経過時間を出力する。

どうでしょうか?

          └基本的には間違っていないと思います。 青木太一 2005/03/03 22:04:03  ツリーへ

Re: for文の部分もだいたいわかってきました 返事を書く
青木太一 2005/03/03 22:04:03
基本的には間違っていないと思います。
あくまでも私見ですが気になった点を書けば

「アルゴリズム」という言葉はもっと抽象的で核心部分の処理手順を示すイメージがあります。音声ファイルを生成するプログラムとしては他の手順も考えられるので、「音声ファイルを生成するプログラムのアルゴリズム」というよりは、「今回実験に使用したプログラムの簡単な説明」とでもした方がしっくりするような気がします。

最初に
・継続時間
・正弦波周波
・生成波形の最大値
・標本化周波数
・1秒あたりのデータ量
・オーディオデータサイズ
・ファイルサイズ
・フォーマットサイズ
などの各種設定を定義する。

と書いていますが、「オーディオデータサイズ」は
>180 let dsize=d*fs*4 !オーディオデータサイズ
と、dとfsによって決まるものなので、定義しているというのは違うような気もします。でもまあこういう書き方もありなのかもしれません。
ファイルサイズとフォーマットサイズはどうやって決められるものなのかわからないのですが、これらも先に決めたパラメータによって自動的に定まる値のような気がします。

           └ありがとうございます たかし 2005/03/05 12:37:12  ツリーへ

Re: 基本的には間違っていないと思います。 返事を書く
たかし 2005/03/05 12:37:12
ありがとうございます
これで何とか卒論は提出できそうです
本当に今までありがとうございました

            └質問の答えになってませんが ニコール・パックマン 2005/07/19 18:30:00  ツリーへ

Re: ありがとうございます 返事を書く
ニコール・パックマン 2005/07/19 18:30:00
質問の答えになってませんが

PRINT "最初の音の周波数は?"
INPUT OLDSOUND
LET A=2^(1/12)
PRINT "シャープはいくつですか?"
INPUT SHARP
LET B=A^SHARP
LET NEWSOUND=OLDSOUND*B
PRINT "変化後の音の周波数は",NEWSOUND,"です"
END


インデックスへ EXIT
新規発言を反映させるにはブラウザの更新ボタンを押してください。