Jump to content
Nokioteca Forum

Ora Possiamo Scrivere Un Accordatore Per Chitarra!


JumpJack_
 Share

Recommended Posts

Per la verità e' addirittura gia pronto:

http://discussion.forum.nokia.com/forum/sh...ad.php?p=477243

Ma la cosa interessante è il modulo fft.py , che permette l'analisi in frequenza di un suono. :D

Il file di cui si parla in quel thread lo attacco direttamente qui, visto che al momento è ospitato in un fastidiosissimo sito di condivisione file temporanea...

strobe.zip

Link to comment
Condividi su altri siti

  • 2 settimane dopo...

Sembra ci sia un modo molto piu' facile per fare un accordatore:

http://www.embedded.com/story/OEG20020819S0057

Si tratterebbe di prendere un segmento di segnale campionato, e sommare i valori di tutti i campioni N volte, usando queste formule:

function ExamineWav(CommandName as string) as integer
   dim wav as qfilestream

   dim FormatStart as long
   dim DataStart as long
   dim c as long

   dim i as long
   dim WavHeader as string

   wav.open( CommandName & ".wav",fmOpenRead) ' Apre file WAV

   ' ********* Legge header
   WavHeader = wav.readbinstr(wav.size)   
   FormatStart = instr(WavHeader,"fmt")-1
   wav.seek(FormatStart+10,0)
   WavChannels=wav.readnum(2)
   AppendLog( "chan=" & str$(WavChannels))
   wav.seek(FormatStart+12,0)
   WavFreq = wav.readnum(4)
   AppendLog(  "freq= " & str$(WavFreq))
   wav.seek(FormatStart+16,0)
   WavBytesSec=wav.readnum(4)
   AppendLog(  "bytes= " & str$(WavBytesSec))
   wav.seek(FormatStart+10,0)
   WavBytesSample=wav.readnum(2)
   AppendLog(  "Bytes/sample= " & str$(WavBytesSample))
   DATALEN = ASCII2DEC(mid$(WavHeader,FormatStart+20,2),2)
   wav.seek(FormatStart+22,0)
   WavBitsSample=wav.readnum(2)
   AppendLog(  "bits= " & str$(WavBitsSample))
   DataStart = instr(WavHeader,"data")-1
   AppendLog(  "Datastart=" & str$(datastart))
   wav.seek(DataStart+4,0)
   DataSize =  hex$(wav.readnum(4))
   print "Lunghezza Data Chunk = 0x" & DataSize

   ' ********* Verifica se il formato del file è accettabile:
   if WavChannels<>1  or WavBitsSample <> 16 then
       showmessage("File " & CommandName & ".wav has wrong format and will be ignored.")
       ExamineWav = ERR_BAD_FORMAT
       exit function
   end if

   print "Leggo " , DataSize, " dati RAW..."
   c = 0

   ' ********* Memorizza i campioni:
   for i = 45 to DataSize step 2
       c = c + 1
          rawdata©=(sign)*wav.Readnum(2) ' Memorizza campione
   next

   wav.close
   ExamineWav = 0
end function

sub AppendLog (s as string)
   txtLog.text = txtLog.text & s & chr$(13) & chr$(10)
end sub

Modificato da JumpJack_
Link to comment
Condividi su altri siti

Ecco qua:

$include "object\rapidq2.inc"
$option explicit

declare sub ExamineWav(MaxSamples as long)
declare function Goertzel(target_freq as long, N as long) as integer
declare sub vai

dim Freq as long

dim FILENAME as string
const ERR_BAD_FORMAT = 2 
const FATAL_ERROR = 99

dim  SampleRate as long 

' create form as qform
' 	 width = 320
' 	 height = 250
' 	 create txtLog as qrichedit
' 	 	top = 10
' 	 	left = 10
' 	 	height = 150
' 		width = 230
' 	 end create
' 	CREATE StatusBar AS qlabel
' 		top = 10
' 		left = 250
' 		caption = "--"
' 	END CREATE	 
' 	 create btnVai as qbutton
' 	 	top = 180
' 	 	left = 10
' 	 	caption = "VAI"
' 	 	onclick = Vai
' 	 end create
' 	
' end create
' 
' form.showmodal

sub PrintHelp
	print
	print "Frequency detector by Jumpjack 2008 - freeware"
	print "----------------------------------------------"
	print
	print "Program looks for frequencies into a WAV file"
	print
	print "Syntax:"
	print "leggiWav <--SamplingFreq xxxx> <--TuningFreq xxxx> <--Iterations xxxx> <--File xxxxx> 
	print "	   --SamplingFreq (-sf): Sampling frequency of the file"
	print "    --TuningFreq (-tf): Frequency to look for"
	print "    --Iterations (-i): Algorithm precision (higher=slower)"
	print "    --File (-f): File to process (WAV)"
	print
	print "All parameters are mandatory."
	print
	print "Example:"
	print "freqdet -sf 44100 -tf 440 -i 5000 -f c:\temp\audio.wav"
	print
	print "See [url="http://www.embedded.com/story/OEG20020819S0057"]http://www.embedded.com/story/OEG20020819S0057[/url] for details"
	print "about algorithm used (Goertzel algorithm)."
	print
	print "(Thanks to Kevin Banks for his page)"
	print 
	print "This program was written in RapidQ"
end sub

SampleRate = 44100

dim i as integer
dim Iterations as integer

if CommandCount = 0 then
printHelp
end
end if

for i = 1 to CommandCount step 2
if instr(ucase$(Command$(i)),ucase$("--SamplingFreq"))>0  or instr(ucase$(Command$(i)),ucase$("-SF")) >0 then
	SampleRate = val(mid$(Command$(i+1),instr(Command$(i+1)," "), len(Command$(i+1))-instr(Command$(i+1)," ")))
end if
if instr(ucase$(Command$(i)),ucase$("--TuningFreq"))>0  or instr(ucase$(Command$(i)),ucase$("-TF")) >0 then
	Freq = val(mid$(Command$(i+1),instr(Command$(i+1)," "), len(Command$(i+1))-instr(Command$(i+1)," ")))
end if
if instr(ucase$(Command$(i)),ucase$("--Iterations"))>0  or instr(ucase$(Command$(i)),ucase$("-I")) >0 then
	Iterations = val(mid$(Command$(i+1),instr(Command$(i+1)," "), len(Command$(i+1))-instr(Command$(i+1)," ")))
end if
if instr(ucase$(Command$(i)),ucase$("--File"))>0  or instr(ucase$(Command$(i)),ucase$("-F")) >0 then
	FileName = val(mid$(Command$(i+1),instr(Command$(i+1)," "), len(Command$(i+1))-instr(Command$(i+1)," ")))
end if
if instr(ucase$(Command$(i)),ucase$("--Help"))>0  or instr(ucase$(Command$(i)),ucase$("-H"))  or instr(ucase$(Command$(i)),ucase$("-?")) >0 then
	call PrintHelp
	end		
end if
next

if FileName = "" then
print "No file specified"
end
end if

Print "SampleRate:",SampleRate
print "Looking for frequency:",Freq
print "Iterations:",Iterations
print "(Duration:", Iterations/Samplerate," seconds)"
print


call Vai

'****************************************************************************
**

DefInt WavChannels, WavFreq,WavBytesSec,WavBytesSample,WavBitsSample 

dim cosine as double
dim sine as double
dim coeff as double

dim RawData(64000) as integer
dim NumSamples as long

dim f as double

sub Vai
dim MaxSamples as long
dim G as integer
MaxSamples = Iterations
call ExamineWav(MaxSamples)
for f = Freq-12 to Freq+12 step 2 
	G = int(Goertzel(f,MaxSamples))
	print f,": ", string$(int(G/10000000),"*")
next
end sub

function Goertzel(target_freq as double, N as long) as integer
' target_freq = frequency to look for;
' N = Number of samples to examine.
' rawdata() contains raw values of audio samples
'
' This function must be called once per each frequency to be tested.
' The more the test frequency is near to detected frequency, the
' greater is the returned value.
'
' Many thanks to Kevin Banks from  [url="http://www.embedded.com/story/OEG20020819S0057"]http://www.embedded.com/story/OEG20020819S0057[/url]
'
' Musical frequencies:
' DO -  C: 	262 Hz
' RE -  D:	294 Hz
' MI -  E:	330 Hz
' FA -  F:	349 Hz
' SOL - G:	392 Hz
' LA -  A:	440 Hz
' SI -  B:	494 Hz


defdbl Q0, Q1, Q2
dim sample as long
defdbl realPart, imgPart, magnitudeSquared, magnitude

dim k as double
dim w as double
dim pi as double	

pi = 3.141592654
k=int(0.5 + (N*target_freq/SampleRate)) 
w = (2*pi*k)/N	
cosine = cos(w)
sine = sin(w)
coeff = 2 * cosine		

q0=0
q1=0
q2=0
for sample = 1 to N 
	Q0 = coeff * Q1 - Q2 + rawdata(sample)
	Q2 = Q1
	Q1 = Q0		
next		

realPart = (Q1 - Q2 * cosine)
imgPart = (Q2 * sine)

magnitudeSquared = realPart*realPart + imgPart*imgPart
magnitude = sqr(magnitudeSquared)

Goertzel= magnitude
end function


sub ExamineWav(MaxSamples as long)
   dim wav as qfilestream
   dim i as long
   dim c as long

   wav.open( FILENAME ,fmOpenRead) ' Apre file WAV

   c = 0    
   ' ********* Memorizza i campioni:
   for i = 45 to MaxSamples 
       c = c + 1
       rawdata©=wav.Readnum(2) ' Memorizza campione
   next    
   wav.close
   NumSamples = c-1
end sub

Il programma va compilato usando RapidQ, per ottenere un eseguibile per WINDOWS (non per il cellulare!)

In allegato c'e' l'eseguibile.

Viene mostrato una specie di "istogramma testuale" centrato sulla frequenza che si sta cercando: se c'e' un picco, vuol dire che quella frequenza è presente nel file audio (ma potrebbero essercene altre).

Ok, ora chi lo porta in Python? :shifty:

FreqDet.zip

Link to comment
Condividi su altri siti

Ehi, sembra proprio che funzioni!

Ho provato a registrare la mia chitarra col telefono, con un semplice:

S=audio.Sound.open(filename)
S.record()

Il risultato è un file WAV a 8 kHz, che esaminato con questo comando:

freqdet -sf 8000 -tf 300 -i 14000 -f f:\temp\boo.wav

evidenzia un picco in corrispondenza della frequenza della corda pizzicata!

Pero' ho cambiato nel programma la riga che disegna gli asterischi:

print f,": ", string$(int(G/(20*Iterations)),"*")

QUindi il nostro accordatore dovrà semplicemente mostrare un istogramma che va da 130Hz a 330 Hz .

Solo che il DO basso non viene rilevato bene.... tutte le altre note si'... a patto pero' che la frequenza "suggerita" al programma tramite linea di comando sia prossima a quella rilevata.

Quindi bisognerà accordare una corda per volta, con questo accordatore, non mostrerà quale frequenza viene "pizzicata", ma solo se quella pizzicata corrisponde a quella attesa.

Link to comment
Condividi su altri siti

Quindi bisognerà accordare una corda per volta, con questo accordatore, non mostrerà quale frequenza viene "pizzicata", ma solo se quella pizzicata corrisponde a quella attesa.

nn ne capisco molto di accordatori... però se dalla frequenza, ti dice se è + o - quella attesa...

per rilevare che frequenza viene "pizzicata" non basta controllare tutte le frequenze delle note disponibili, vedere se corrisponde a qualcuna di quelle e quindi associargli quella frequenza? (ovviamente credo sia una approssimazione... ma meglio che niente xD)

pò esse che nn c'ho capito niente dato che nn so cm funziona sta roba XD

Link to comment
Condividi su altri siti

nn ne capisco molto di accordatori... però se dalla frequenza, ti dice se è + o - quella attesa...

per rilevare che frequenza viene "pizzicata" non basta controllare tutte le frequenze delle note disponibili, vedere se corrisponde a qualcuna di quelle e quindi associargli quella frequenza? (ovviamente credo sia una approssimazione... ma meglio che niente xD)

pò esse che nn c'ho capito niente dato che nn so cm funziona sta roba XD

il programma è già lento sul computer per poter lavorare in questo modo, sul cellulare sarà anche peggio. :)

Ci vogliono circa 2 secondi per tracciare il grafico di una nota, su un Athlon a 2600 Hz...

Link to comment
Condividi su altri siti

Ecco un primo port in python: su PC funzina, sul cell... vedremo.

Per il momento "cerca" solo il LA, e il file c:\temp\sample.wav deve già esistere.

from math import * # for sin and cos.
import struct # for signed integer extraction from file.

def ExamineWav(MaxSamples):
global rawdata
f=open("c:\\temp\\sample.wav","rb")
f.seek(45) #Skip header
c=0
rawdata = [] #Inizialize array of samples
dato = 0
for i in range(1,MaxSamples+2):
	c=c+1
	dato = struct.unpack('h',f.read(2))[0] # Extract signed integer 2 bytes long (signed sHort)
	rawdata.append(dato)


def Goertzel(target_freq,N):
global rawdata, SampleRate
pi = 3.141592654
k=int(0.5 + (N*target_freq/SampleRate)) 
w = (2*pi*k)/N	
cosine = cos(w)	
sine = sin(w)
coeff = 2 * cosine		

q0=0.0
q1=0.0
q2=0.0
for sample in range(0,N):
	q0 = coeff * q1 - q2 + rawdata[sample]
	q2 = q1
	q1 = q0		
next		

realPart = q1 - q2 * cosine
imgPart = q2 * sine


magnitudeSquared = realPart*realPart + imgPart*imgPart
magnitude = sqrt(magnitudeSquared)

return magnitude




Samples=5000
Span = 12
Freq = 440
SampleRate = 44100.0
Factor = 1000000.0

ExamineWav(Samples)

for f in range(Freq-Span,Freq+Span,2):
G = int(Goertzel(f,Samples))
print
print f,": ", #int(G/Factor)
for i in range(1,int(G/Factor)+1):
	print "*",

Modificato da JumpJack_
Link to comment
Condividi su altri siti

Ok, ecco a voi il primo accordatore per chitarra in Python!

Serve anche il modulo smidi, perche' oltre a registrare i suoni, l'accordatore puo' anche produrre quelli corretti, tramite midi, per una prima accordatura a orecchio (c'e' una voce PLAY alla fine del menu).

Potrei aver scritto qualche "corbelleria musicale" nel sorgente e nei menu... qui ci vuole l'aiuto di chi la chitarra la sa suonare per davvero...

Io sono un programmatore, non un chitarrista... :crying_anim02:

guitar.zip

smidi.zip

Modificato da JumpJack_
Link to comment
Condividi su altri siti

  • 8 mesi dopo...
Ok, ecco a voi il primo accordatore per chitarra in Python!

Serve anche il modulo smidi, perche' oltre a registrare i suoni, l'accordatore puo' anche produrre quelli corretti, tramite midi, per una prima accordatura a orecchio (c'e' una voce PLAY alla fine del menu).

Potrei aver scritto qualche "corbelleria musicale" nel sorgente e nei menu... qui ci vuole l'aiuto di chi la chitarra la sa suonare per davvero...

Io sono un programmatore, non un chitarrista... :thumbs:

ma come si può istallare sul cellulare??...io ho un N70

Link to comment
Condividi su altri siti

ma come si può istallare sul cellulare??...io ho un N70

Beh inanzitutto ti devi scaricare il python: librerie e script shell.

Poi apri sul telefono il file guitar.py e fai install as script. Mentre con il secondo file, smidi, lo apri ma lo installi come libreria (modulo). Ora apri la shell python, menu, run script, e selezioni guitar.py e poi provi il programma :(

Link to comment
Condividi su altri siti

  • 1 mese dopo...

La butto li la mia ca***ta...

In teoria prendendo il "cuore" di questo accordatore per chitarra, che se non sbaglio analizza la frequenza,

Si potrebbe "isolare" una frequenza, che ne so attorno ai 1000 Hz e vedere quanto e come viene riprodotto un suono su quella frequenza in uno spetro sonoro in ingresso...

Mi servirebbe qualcosa di simile per decdificare dal telefono un segnale in CW (Codice Morse) tipo radiofari... per cominciare, per poi estenderlo alla modulazione PSK...

esiste un programmino per winmobile (pocketDigi) che lo fa egregiamente... però ho notato che questi tel symbian emettono molto molto meno disturbi di un qualsiasi pocket pc...

Link to comment
Condividi su altri siti

  • 2 settimane dopo...
La butto li la mia ca***ta...

In teoria prendendo il "cuore" di questo accordatore per chitarra, che se non sbaglio analizza la frequenza,

Si potrebbe "isolare" una frequenza, che ne so attorno ai 1000 Hz e vedere quanto e come viene riprodotto un suono su quella frequenza in uno spetro sonoro in ingresso...

Mi servirebbe qualcosa di simile per decdificare dal telefono un segnale in CW (Codice Morse) tipo radiofari... per cominciare, per poi estenderlo alla modulazione PSK...

esiste un programmino per winmobile (pocketDigi) che lo fa egregiamente... però ho notato che questi tel symbian emettono molto molto meno disturbi di un qualsiasi pocket pc...

per decodificare un segnale morse non serve l'analisi in frequenza, basta vedere quando il segnale c'e' o non c'e' e misurare la durata degli impulsi.

Ho scritto un programma in basic che, per altri motivi, fa proprio questo:

http://code.google.com/p/ledrem/source/bro...=svn14&r=14

La parte che ti interessa è questa:

	' ************* Convert to pseudo-binary
AppendLog("Converting to binary... " ) : doevents	
c = 0
x = 0
For i = 1 To DataSize/2
	c = c + 1
	x = x + 1
	binary(i) = 0
	If RawData(i) > Max/BINARYFACTOR then ' Max - (Max * tolerance / 100) Then
		binary(i) = One	  
	End If

i dati in RawData() vengono scritti cosi' dalla funzione ExamineWav(): si tratta semplicemente di saltare i primi 45 byte di intestazione di un file WAV; tutti i successivi byte costituiscono la forma d'onda, memorizzata in valori compresi tra -32767 e +32768 (quindi devi prendere i byte a coppie).

Link to comment
Condividi su altri siti

  • 1 anno dopo...
  • 3 settimane dopo...

Please sign in to comment

You will be able to leave a comment after signing in



Accedi Ora
 Share

×
×
  • Crea Nuovo...

Informazione Importante

Questo sito utilizza i cookie per analisi, contenuti personalizzati e pubblicità. Continuando la navigazione, accetti l'utilizzo dei cookie da parte nostra | Privacy Policy