Wir schreiben einen Konverter für den Klingeltongenerator von Nokia 3310

    Fans aller alten, aber wahnsinnig interessanten, guten Abend!




    Erinnerst du dich an dieses Handy - Nokia 3310? Denken Sie natürlich daran! Und so etwas wie ein Melodiesynthesizer drin? Denken Sie auch daran, toll. Vermissen Sie alte, warme und Lampenmelodien? Also ich vermisse. Und ich bin auf eine Website mit mehr als hundert Noten für diesen Herausgeber gestoßen. Und dass ich diesen Charme ohne Aufmerksamkeit lassen musste? Nein, wirklich. Was habe ich gemacht Richtig! Ich habe genau den gleichen Melodie - Generator genommen und geschrieben, mit dem Sie eine Wave - Datei mit einer Melodie am Ausgang erhalten. Ich frage mich, was daraus geworden ist? Dann frage ich nach Katze.



    Nokia Composer wurde in eine ganze Reihe von Handys wie das Nokia 3310 eingebaut. Zusätzlich zu 7 Notizen konnten Sie 5 Sharps aufnehmen, eine Oktave und eine Dauer in Teilen angeben. Und es gab Notizen, die nicht hörbar waren - Pausen. Das heißt, die "Notiz" in Composer war wirklich eine Notiz.

    Die Aufzeichnung der Note für Composer sah folgendermaßen aus:



    Das heißt, am Anfang gibt es eine Dauer (in Teilen des Ganzen), dann könnte es einen Punkt geben , der den Klang um das Eineinhalbfache erweitert, die Note selbst in der Buchstabenbezeichnung und eine Oktave . In diesem Fall wird nach einer Pause die Oktave nicht angezeigt (ist das logisch?), Und die Dauer wird genau wie bei einer normalen Note angezeigt.

    Okay, rede.

    Schreiben wir ein Skript, das eine Notiz so wie sie ist aufnimmt und ein Tupel von Parametern zurückgibt.

    (Schreiben in Python 2.7, ja)

    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"[A-Z,#,-]+", Note)[0]
    	Duration = int(Duration)
    	Octave = int(Octave)
    	if Note.find(".") != -1:
    		Duration = Duration/1.5
    	return (32/Duration, Tone, Octave)
    


    In! Das heißt, wir übersetzen es zuerst in das UPPER REGISTER und analysieren es dann - unter Verwendung regulärer Ausdrücke - in Komponenten. Prüfen Sie, ob ein Punkt vorhanden ist (1,5-fache Erhöhung), und berücksichtigen Sie die Pause.

    Gototo!
    Übergeben wir nun Funktionen, zB 16C2, so erhalten wir am Ausgang (2, C, 2), also die Dauer in Shares, Note und Oktave.

    Was denn Woher kam die Nummer 32? Mit
    Original Nokia Composer können Sie die Dauer einer Notiz auf 1/32 einer „vollständigen“ Notiz einstellen . Darüber hinaus gibt es für ihn auch 1/16, 1/8, 1/4, 1/2 und 1 Dauer. Das heißt, jede nächste Dauer unterscheidet sich genau zweimal von der vorherigen. Dann können wir dies tun:

    Nehmen Sie 1/32 Noten als "einzelne Note". Dann ist 1/16 schon 2 Einzelnoten, 1/8 - 4 und so weiter. Dann können wir 32 durch die empfangene Dauer nehmen und dividieren.

    Wir haben es herausgefunden. Jetzt bleibt zu verstehen, wie wir das Ganze in eine Wav-Datei verwandeln.

    Wenn es sehr rau ist, werden in der Wave-Datei zusätzlich zum Header die an den Lautsprecher gelieferten Spannungen aufgezeichnet. Wenn ein bisschen genauer - ein Teil der Spannung vom Maximum . Das heißt, wenn die Nummer 32765 in einem Zwei-Byte-Frame geschrieben ist, bedeutet dies, dass Sie die maximale Spannung anlegen müssen. Durch die Veränderung des Spannungsniveaus im Laufe der Zeit können Vibrationen der Lautsprechermembran erreicht werden. Und wenn diese Schwankungen im Bereich liegen, brauchen wir ... Das stimmt! Wir werden einen Ton von einer bestimmten Frequenz hören.

    Nun, wie es geht.

    Lassen Sie uns die Erinnerung belasten und ... sich an den Physikkurs erinnern! Über den Teil, der über harmonische Schwingungen spricht .

    Wenn es ganz einfach ist: Oberschwingungen sind eine Art von Schwingung, deren Schwingungswert sich nach dem Sinusgesetz ändert (oder nach dem Cosinus, wie Sie möchten).



    Die allgemeine Formel dieser Schande sieht so aus: Haben



    Sie sich



    an diese Taktfrequenz erinnert ? Großartig! Jetzt musst du verstehen - warum.

    Da wir uns entschieden haben, den Klang als Änderung der Spannung am Lautsprecher einzustellen, werden wir die Änderungen als Sinuskurve mit der von uns benötigten zyklischen Frequenz einstellen (übrigens die naheliegendste Art, Klang zu erzeugen). In diesem Fall sieht die Formel zur Berechnung der Amplitude des aktuellen Frames folgendermaßen aus

    Ergebnis = (32765 * VOL * math.sin (6,28 * FREQ * i / 44100))
    Woher kommt das alles? Ich sage es dir.

    32765 - Wir haben einen Zwei-Byte-Frame, der maximale Amplitudenwert beträgt also genau 32765. VOL ist eine Variable, die die Lautstärke festlegt. Änderungen im Bereich von 0 (völlige Stille) bis 1 (schreien wie auf einer Fläche)

    6.28 - dies ist nur 2 * Pi. Sie können jedes Mal rechnen, aber wir sind keine Tiere.

    FREQ - Und dafür wurde alles gestartet - die Frequenz, die wir brauchen.

    i / 44100 - Zeit relativ zum Ursprung. Warum teilen wir durch 44100? Aber weil dies die Abtastrate der Ausgabedatei ist (nun, ich habe es so gesehen. Vielleicht weniger. Die Qualität wird niedriger sein). Es gibt 44100 Messwerte pro Sekunde, daher teilen wir. Ich hoffe, es hat sich herausgestellt, um zu erklären


    Bitte schön. Wir haben gelernt, einen Frame zu setzen. Jetzt müssen Sie alles zum Laufen bringen. Das heißt, zusätzlich zur Frequenz wird auch die Dauer eingestellt.

    Und da die Frequenz festgelegt ist ... Ja! Wickle es in eine Schleife.

    Hier in diesem.

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


    Wieder Unverständlichkeit. Woher kam TIME / 10 * 441 ? Aus meiner Fantasie. Nein, wirklich. So habe ich beschlossen, dass die minimale Spielzeit 0,001 Sekunden beträgt . Wie ich bereits sagte - eine Probe (bei einer gegebenen Abtastfrequenz) ist 1/44100 Sekunden. Dementsprechend sind 0,001 Sekunden 44,1 Zählimpulse. A 44,1 = 441/10. Und wenn Sie N Millisekunden einstellen müssen ... multiplizieren Sie, ja. So bekommen wir, was wir geschrieben haben (ZEIT ist genau die gleiche Zeit in Millisekunden, ja)


    Also gut, lassen Sie uns diese ganze Sache zu einer Funktion machen, ich hoffe, niemand ist dagegen?

    
    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)
    


    In! Jetzt können wir Töne mit absolut jeder Frequenz erzeugen.

    Es bleibt festzuhalten, was in der Wave - Datei passiert ist.

    Für die Arbeit mit Wave in Python (mindestens 2.7) gibt es ein attraktives Modul mit einem unvergesslichen Namen - Wave . Und um mit allen Arten von Strukturen zu arbeiten - struct (im Allgemeinen ist Python bis zu einem gewissen Punkt eine wahnsinnig logische Sprache).

    Nach einigen Tänzen mit Tamburin und anderen Perversionen stellte sich diese Funktion hier heraus:

    
    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)
    


    (Ich werde nicht darüber sprechen, weil erstens alles klar ist und zweitens wir uns nicht vom Thema entfernen werden.)

    Nun. Jetzt können Sie einen Sound erzeugen!
    Wir versuchen es.

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


    Volle Lautstärke, 4 Kilohertz, 5 Sekunden.
    Mal sehen, was passiert ist?

    So hört es sich an:

    5000Hz.wav

    Und es sieht so aus:



    Nun, im Allgemeinen wollten sie, was sie haben. Der Klang ist wirklich eher unangenehm.

    Wenn ich mich recht erinnere, wurde der Sound in der alten Bibliothek für Turbo Pascal übrigens nicht von einer Sinuskurve, sondern von einem Mäander gesetzt. Tatsächlich reicht es aus, nur die Spannung am Lautsprecher zu ändern. Nur eine Sinuswelle, die hübscher ist als ein Mäander oder eine Säge.

    Bitte schön. Jetzt haben wir eine Funktion, die Sound mit der gewünschten Frequenz und Dauer erzeugt, und eine Funktion, die aufzeichnet, was wir in dieser Datei getan haben.

    Jetzt müssen Sie lernen, wie Sie Notizen aufzeichnen.

    Eine saubere (nicht instrumental gefärbte) Note ist der Klang einer bestimmten Frequenz.

    Eine scharfe Note ist ein Ton mit einer Frequenz, die eineinhalb Töne höher

    ist als eine saubere Note . Bete nicht den ursprünglichen Komponisten (erinnere dich noch daran, was wir dort schreiben wollten? Hervorragend!) Frag nicht, also werden wir nicht mit Beoles arbeiten. Na sie.

    Oktave - vereinfacht ausgedrückt handelt es sich um einen Notenfrequenzvervielfacher . Das heißt, die Frequenz Re der zweiten Oktave ist doppelt so hoch wie die gleiche Re der ersten Oktave.

    Finden Sie im Internet eine Tabelle mit Notizen und deren Häufigkeit



    und machen Sie daraus ein Wörterbuch.

    Hier ist einer:

    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}
    


    (Im Allgemeinen ist es wahrscheinlich richtiger, C # als #C zu schreiben, aber in der Regel wurden alle Melodien für Composer in diesem Format angezeigt.)

    Nun werden wir eine weitere Funktion schreiben, die den Klang einer bestimmten Note erzeugt

    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
    


    Es gibt also noch etwas zu sagen.

    Mit dem ersten Teil ist alles klar - der Wert der gewünschten Frequenz wird aus dem Wörterbuch entnommen, mit einer Oktave multipliziert und in die Liste geschrieben.

    Warum brauchen wir eine Sekunde?

    Sehr einfach. Wenn die gewünschte Dauer nicht ein Vielfaches der Sinuswellenperiode ist, kann zum Zeitpunkt T1 eine große Spannung an den Lautsprecher angelegt werden, und T1 + 1 wird nichts zugeführt . In den Ohren meines Bären klingt es wie eine plötzlich gebrochene Phrase eines ermordeten Kameraden - unangenehm. Deshalb bringen wir unsere Sinuskurve auf die nächste Null. Bei einer hohen Abtastfrequenz ist dies merklich gering, aber nach dem Gehör sieht es aus wie die gleiche Beschneidungsphrase eines Freundes, wenn der betrügerische (aber schreiende) Freund in den Brunnen fällt. Es ist auch nicht Gott weiß was, aber für die Erzeugung von Nokiev-Melodien wird es genügen.


    Jetzt muss noch eine Funktion geschrieben werden, die eine Liste von Notizen aufnimmt und sie Element für Element an den Generator weiterleitet.
    
    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)
    

    So etwas in der Art.

    Ist wieder etwas unverständliches? Das ist normal, ich verstehe auch nichts , jetzt werden wir verstehen .

    BPM ist die Anzahl der Schläge pro Minute. Grob gesagt ist dies die "Geschwindigkeit des Spiels". Dieser BPM entspricht der Anzahl der Viertelnoten in einer Minute . Das heißt, eine Viertelnote sollte 60 / BPM Sekunden lang gespielt werden. Und da haben wir entschieden, dass die Dauer einer einzelnen Note bei uns 1/32 ist - dieser Wert ist 60/32 * 4 / BPM = 7,5 / BPM . Eine Viertelnote klingt genau 1000 Millisekunden (aus irgendeinem Grund haben sich die Komponisten das ausgedacht), und dann wird dieses Ergebnis auch mit der Anzahl solcher 1/32 Noten multipliziert.

    Wenn die Funktion abgeschlossen ist, wird die fertige Liste in der Frame- Liste angezeigt, die noch geschrieben werden muss.


    Da ich zu faul bin, um GUIs zu schreiben, mag ich Konsolenschnittstellen, schreiben wir einen Notensequenz-Handler, der diese Sequenz, BPM und den Namen der Ausgabedatei in die Argumentliste aufnimmt und die Append_Notes () -Funktionen eingibt

    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)
    


    Das ist alles.

    Jetzt müssen nur noch die Quelldaten an das Programm übertragen und die fertige Melodie abgeholt werden.

    Versuchen wir es?

    Notenblätter
    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


    Wir fahren es in den Generator ...



    Und wir nehmen das Ergebnis:

    output.wav

    Meiner Meinung nach nicht schlecht.

    Weitere Beispiele? Einfach!

    Hymne der UdSSR
    Unter dem blauen Himmel
    Herbstweihnachtsmelodie
    (aus dem Original 3310)

    Wollen Sie sich selbst schreiben? Probieren Sie es aus!

    Hier sind die Notizen
    4d1 4g1 8g1 8a1 8g1 8 # f1 4e1 4c1 4e1 4a1 8a1 8b1 8g1 4 # f1 4d1 4d1 4b1 8b1 8c2 8b1 8a1 4g1 4e1 8d1 8d1 4e1 4a1 4 # f1 2g1


    Hier ist das Tempo: 200

    Gehen Sie durch den Generator und sehen Sie, was passiert (und jemand kann es mit den Augen wissen).

    Generator Skript

    Ich hoffe es hat euch gefallen!

    Mit freundlichen Grüßen, hören Sie den monophonen Mozart GrakovNe

    Nur registrierte Benutzer können an der Umfrage teilnehmen. Bitte komm rein .

    War es interessant

    • 95,4% Ja 376
    • 4,5% Nr. 18

    Jetzt auch beliebt: