Nokia 3310から着信音ジェネレーター用のコンバーターを作成します

昔ながらのファンですが、めちゃくちゃ面白い、こんばんは!







この電話-Nokia 3310を覚えていますか? もちろん、覚えておいてください! それにメロディーシンセサイザーのようなものは? また、覚えておいてください、素晴らしい。 古い、暖かくてランプのメロディーが恋しいですか? だから懐かしい。 そして、私はこの編集者のために100以上の楽譜があるウェブサイトに出会いました。 そして、私はこの魅力を注意せずに残さなければならなかったことを? いいえ、本当に。 私は何をしましたか? そう! まったく同じメロディジェネレーターを使用して作成しました。これにより、出力にメロディが含まれるWaveファイルを取得できます。 何から来たのかな? それから猫をお願いします。






Nokia Composerは、Nokia 3310などの携帯電話全体に組み込まれています。7つの音に加えて、5つのシャープを記録し、オクターブと期間を部分的に指定できます。 そして、音がしないノートがありました-一時停止。 つまり、Composerの「メモ」は本当にメモでした。



Composerのメモ自体は次のようになりました。







つまり、最初は持続時間 (全体からの部分)があり、音が1.5倍に伸びるポイント 、文字表記の音符オクターブがあります。 この場合、 一時停止後、オクターブは示されません (論理的ですか?)、そして持続時間は通常の音とまったく同じように示されます。



さて、話して。



そのままメモを取り、パラメーターのタプルを返すスクリプトを作成しましょう。


(Python 2.7で記述、はい)



def Parse_Tone(Note): Note = Note.upper() if Note.find("-") == -1: try: (Duration, Octave) = re.findall(r"[0-9]+", Note) except: pass else: Duration = re.findall(r"[0-9]+", Note)[0] Octave = 1 Tone = re.findall(r"[AZ,#,-]+", Note)[0] Duration = int(Duration) Octave = int(Octave) if Note.find(".") != -1: Duration = Duration/1.5 return (32/Duration, Tone, Octave)
      
      







で! つまり、最初にUPPER REGISTERに変換し、次に正規表現を使用してコンポーネントに解析します。 別途、ポイントの存在を確認し(1.5倍増加)、一時停止を考慮します。



後藤!

16C2などの関数を渡すと、出力で(2、C、2)が得られます。つまり、シェア、ノート、オクターブの期間です。



なに? 32という数字はどこから来たのですか? ただ

オリジナルのNokia Composerでは、音符の長さを「フル」音符の1/32に設定できました さらに、彼にとっては、1 / 16、1 / 8、1 / 4、1 / 2、および1の持続時間もあります。 つまり、次の各継続時間は、前の継続時間と正確に2回異なります。 次に、これを行うことができます。



1/32のメモを「単一のメモ」としてみましょう 。 その後、1/16はすでに2つのシングルノート、1/8-4などです。 次に、32を取得し、受信した期間で割ることができます。



私たちはそれを理解しました。 このすべてをWavファイルに変換する方法を理解する必要があります。



非常に粗い場合-Waveファイルには、ヘッダーに加えて、スピーカーに供給される電圧が記録されます。 もう少し正確に- 電圧の一部が最大値から 。 つまり、数値32765が2バイトフレームで書き込まれている場合、これは最大電圧を印加する必要があることを意味します。 ストレスレベルを経時的に変化させることにより、スピーカーメンブレンの振動を実現できます。 そして、これらの変動が必要な範囲内にある場合...そうです! 特定の周波数の音が聞こえます。



今、それを行う方法。



記憶に負担をかけましょう... ...学校の物理学コースを思い出してください! 調和振動について語る部分について。



非常に単純な場合: 調和振動は、正弦の法則 (必要に応じて、コサイン) に従って振動値が変化する振動の一種です







この不名誉の一般的な式は次のようになります。







この場合、巡回周波数は







覚えてますか? いいね! 今、あなたは理解する必要があります-なぜ。



スピーカーの両端の電圧の変化として音を設定することにしたので、 必要な周期周波数を持つ正弦波として変更を設定します(ところで、音を作成する最も明白な方法)。 この場合、現在のフレームの振幅を計算する式は次のようになります



結果=(32765 * VOL * math.sin(6.28 * FREQ * i / 44100))

これはどこから来たのですか? 教えます



32765-2バイトのフレームがあるため、最大振幅値は正確に32765です。VOLは音量を設定する変数です。 0(完全な無音)から1(エリアにいるかのように叫ぶ)の範囲の変化



6.28はちょうど2 * Piです。 毎回計算できますが、私たちは動物ではありません。



FREQ-そして、これがすべてのために始められたものです-私たちが必要とする周波数。



i / 44100-原点を基準とした時間。 なぜ44100で割るのですか? しかし、これは出力ファイルのサンプリングレートであるためです(まあ、私はそれをそのように考えました。たぶんそれよりも少ないでしょう。品質は低くなります)。 1秒あたり44100の読み取り値があるため、分割します。 私はそれが説明することが判明したことを願っています





よくここに。 1つのフレームを設定することを学びました。 次に、すべてを機能させる必要があります。 つまり、頻度に加えて、期間も設定します。



そして、周波数が固定されているので...うん! ループでラップします。



これでこれ。



 for i in range(0,TIME/10*441): Result = (32765*VOL*math.sin(6.28*FREQ*i/44100)) Frames.append(Result)
      
      







再びわかりにくい。 TIME / 10 * 441はどこから来たのですか? 私の想像から。 いいえ、本当に。 これが私が最小プレイ時間が0.001秒だと決めた方法です。 すでに述べたように、1つのサンプル(特定のサンプリング周波数で)は1/44100秒です。 したがって、0.001秒は44.1カウントです。 A 44.1 = 441/10。 また、Nミリ秒を設定する必要がある場合は、乗算してください。 書いたものを取得します(TIMEはミリ秒単位で同じ時間です、はい)





さて、この全体を関数でラップしましょう。誰も反対しないことを望みますか?



 def Append_Freq(VOL,FREQ, TIME): for i in range(0,TIME/10*441): Result = (32765*VOL*math.sin(6.28*FREQ*i/44100)) Frames.append(Result)
      
      







で! これで、絶対にあらゆる周波数の音を生成できます。



波で起こったことを記録するために残っています-ファイル。



Python(少なくとも2.7)でWaveを使用するには、忘れられない名前の魅力的なモジュールWaveがあります。 そして、あらゆる種類の構造-struct (一般的に、特定の点までは、Pythonはめちゃくちゃ論理的な言語です)を扱うために。



タンバリンと他の倒錯といくつかのダンスの後、この機能はここに判明しました:



 def Write_Wave(Name): File = wave.open(Name, 'w') File.setparams((1, 2, 44100, 0, 'NONE', 'not compressed')) Result = [] for frame in Frames: Result.append(pack('h', frame)) for Each in Result: File.writeframes(Each)
      
      







(私はそれについて話すつもりはありません。なぜなら、第一に、すべてが明確であり、第二に、我々はそのトピックから離れないからです)



よくここに。 これでサウンドを生成できます!

やってみます。



 Frames = [] Append_Freq(1, 4000, 5000) Write_Wave('Sound.wave')
      
      







フルボリューム、4キロヘルツ、5秒。

何が起こったのか見てみましょうか?



これはどのように聞こえるかです:



5000Hz.wav



そしてここに見えます:







まあ、一般的に-彼らが欲しかったのは彼らが得たものでした。 音は本当にかなり不快です。



ちなみに、私の記憶が私にぴったりなら、Turbo Pascalの古いライブラリでは、音は正弦波ではなく蛇行で設定されていました。 実際、スピーカーの電圧を変更するだけで十分です。 蛇行やのこぎりよりもきれいな正弦波です。



よくここに。 これで、目的の周波数と持続時間の音を生成する関数と、このファイルで行ったことを記録する関数ができました。



次に、メモを記録する方法を学習する必要があります。



きれいな(楽器の色ではない) 音は、特定の周波数の音です。



シャープなクリーンノート-クリーンノートよりもハーフトーンが高い周波数の



きれいな音よりも半トン低い周波数のモル 。 オリジナルの作曲家に祈らないでください(まだそこに何を書きたかったのか覚えていますか?すばらしい!) まあそれら。



オクターブ-簡略化すると、ノートの周波数乗数になります。 つまり、2番目のオクターブの周波数Reは、最初のオクターブの同じReの2倍です。



インターネットでメモとその頻度の表を見つける







そして、それから辞書を作ります。



以下がその1つです。



 Notes = {"-" : 0 ,"C" : 261.626, "#C" : 277.183, "D" : 293.665, "#D" : 311.127, "E": 329.628, "#E" : 349.228, "F" : 349.228, "#F" : 369.994, "G" : 391.995, "#G" : 415.305, "A" : 440.000, "#A" : 466.164, "B" : 493.883, "#B" : 523.251}
      
      







(一般に、おそらく#CではなくC#を記述する方が正しいでしょうが、原則としてComposerのすべての曲はこの形式で示されています)



それでは、ある音の音を生成する別の関数を書きましょう。



 def Append_Note(VOL, TIME, NOTE, OCTAVE): for i in range(0,int(TIME/10.0*441)): FREQ = Notes[NOTE]*OCTAVE Result = (32765*VOL*math.sin(6.28*FREQ*i/44100)) Frames.append(Result) #making clear sound if (abs(math.sin(6.28*FREQ*i/44100))>0.01): while (abs(math.sin(6.28*FREQ*i/44100))>0.01): Result = (32765*VOL*math.sin(6.28*FREQ*i/44100)) Frames.append(Result) i+=1
      
      







ですから、他に言いたいことがあります。



最初の部分では、すべてが明確です-目的の周波数の値が辞書から取得され、オクターブが乗算されてリストに書き込まれます。



なぜあなたは秒が必要なのですか?



とても簡単です。 希望の持続時間が正弦波周期の倍数ではない場合、時間T1でスピーカーに大きな電圧を印加でき、T1 + 1には何も供給さません 。 私の熊の耳には、殺された同志の突然壊れたフレーズのように聞こえます-不快です。 したがって、 正弦波を最も近いゼロに近づけます 。 サンプリング頻度が高い場合、これは顕著に小さくなりますが、欺く(しかし叫んでいる)友人が井戸に落ちた場合、耳から見ると友人のクリッピングフレーズのように見えます。 また、神は何を知っているのではありませんが、ノキエフの世代のメロディーにとってはそうなります。





ここで、メモのリストを取得し、それを要素ごとにジェネレーターに供給する関数を作成します。

 def Append_Notes(VOL, LIST, BPM): for Each in LIST: (Duration, Tone, Octave) = Parse_Tone(Each) try: Append_Note(VOL, int(Duration*1000*7.5/BPM), Tone, Octave) except: print "!    %s" %Each Append_Note(0, int(250*7.5/BPM), "-", 1)
      
      





このようなもの。



再び理解できないものはありますか? これは正常です、 私も何も理解していません 、今私たちはそれを理解します。



BPMは、1分あたりの拍数です。 大まかに言えば、これが「ゲームの速度」です。 このBPMは、1分間の4分音符の数に等しくなります。 つまり、4分の1音を60 / BPM秒で再生する必要があります。 そして、私たちは私たちとの単一の音の持続時間は1/32であると決定しました-この値は60/32 * 4 / BPM = 7.5 / BPMです。 1分音符は正確に1000ミリ秒に聞こえます(何らかの理由で作曲家がこれを思いついた)。そして、この結果にそのような1/32音の数を掛けます。



関数が完了すると、完成したリストがフレームリストに表示されますが、これはまだ書き込まれていません。





GUIを書くのが面倒なので、コンソールインターフェイスが好きなので、このシーケンス、BPM、および出力ファイルの名前を引数リストに入れてAppend_Notes()関数にフィードするノートシーケンスハンドラを記述します



 def MakeTune(): if (len(Arguments)!=3): print 'ERROR!\n USAGE:\n Composer "Notes" BMP FileName\nExample:\n Composer "16c2 16#a1 4c2 2f1 16#c2 16c2 8#c2 8c2 2#a1 16#c2 16c2 4#c2 2f1 16#a1 16#g1 8#a1 8#g1 8g1 8#a1 2#g1 16g1 16#g1 2#a1 16#g1 16#a1 8c2 8#a1 8#g1 8g1 4f1 4#c2 1c2 16c2 16#c2 16c2 16#a1 1c2" 120 Music.wave' return 1 List = Arguments[0].split(' ') BPM = int(Arguments[1]) OutFile = Arguments[2] print "\nFile information:\n\n Note number: %s\n Tempo: %s BPM\n\nGeneration of amplitude..." % (len(List), BPM) Append_Notes(1, List, BPM) print "\nOk!\n\nWriting Wave File..." Write_Wave(OutFile) File = open(OutFile,'rb').read() Size = len(File) print "\n File size: %.2f MB\n Duration: %.2f c. \n\nAll Done." % (Size/1024.0/1024, Size/44100/2)
      
      







以上です。



これで、ソースデータをプログラムに転送し、完成したメロディを取得するだけになります。



やってみますか?



楽譜
16c2 16#a1 4c2 2f1 16#c2 16c2 8#c2 8c2 2#a1 16#c2 16c2 4#c2 2f1 16#a1 16#g1 8#a1 8#g1 8g1 8#a1 2#g1 16g1 16#g1 2# a1 16#g1 16#a1 8c2 8#a1 8#g1 8g1 4f1 4#c2 1c2 16c2 16#c2 16c2 16#a1 1c2




発電機に乗り込み......







そして、結果を取得します。



output.wav



私の意見では、悪くない。



他の例? 簡単!



ソ連の国歌

青空の下で



クリスマスチューン(3310から)



自分で書きたいですか? 試してみてください!



ここにメモがあります
4d1 4g1 8g1 8a1 8g1 8#f1 4e1 4c1 4e1 4a1 8a1 8b1 8a1 8g1 4#f1 4d1 4d1 4b1 8b1 8c2 8b1 8a1 4g1 4e1 8d1 8d1 4e1 4a1 4#f1 2g1




ペースは次のとおりです。200



ジェネレーターを通過して、何が起こるかを見てください(そして誰かが目で知っているかもしれません)。



ジェネレータースクリプト



楽しんでいただけましたでしょうか!



心からあなた、モノフォニックモーツァルト、GrakovNeを聞いて



All Articles