-
-
Save jamshark70/b6b23110b1ce4b28864c72afb0c35367 to your computer and use it in GitHub Desktop.
FFT + pitch analysis testing code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1. Prepare analysis function | |
( | |
/////////////////////////////////////// | |
// Non-Realtime FFT Analysis To File // | |
/////////////////////////////////////// | |
~analyseWav = { | |
arg wavIn, fftOut, pitchOut, action; | |
// Define function vars | |
var inBuf, fftBuf, pitchBuf, fftSize = ~fftSize, f, nrtServer, nrtScore, env; | |
var cond = Condition.new; | |
fork { | |
f = SoundFile.openRead(wavIn); | |
f.close; | |
// Define Non-RealTime server | |
nrtServer = Server(\nrt, NetAddr("127.0.0.1", 57110), | |
ServerOptions.new | |
.numOutputBusChannels_(2) | |
.numInputBusChannels_(2) | |
.sampleRate_(44100) | |
); | |
// Create buffer for input file | |
inBuf = Buffer(nrtServer, 65536, 1); | |
// Create output buffer for FFT analysis data | |
fftBuf = Buffer(nrtServer, f.duration.calcPVRecSize(fftSize, 0.5, nrtServer.options.sampleRate), 1); | |
pitchBuf = Buffer(nrtServer, (f.numFrames / nrtServer.options.blockSize).roundUp.asInteger, 2); | |
// Create score for recording of FFT analysis to WAV file | |
nrtScore = Score([ | |
[0, inBuf.allocMsg], | |
[0, fftBuf.allocMsg], | |
[0, pitchBuf.allocMsg], | |
[0, inBuf.readMsg(wavIn, leaveOpen: true)], | |
[0, [\d_recv, SynthDef(\pv_ana, { | |
var sig = VDiskIn.ar(1, inBuf, f.sampleRate / SampleRate.ir); | |
var fft = FFT(LocalBuf(fftSize, 1), sig); | |
var pitch = Tartini.kr(sig); | |
RecordBuf.kr(pitch, pitchBuf, loop: 0); | |
fft = PV_RecordBuf(fft, fftBuf, run: 1); | |
Out.ar(0, sig); | |
}).asBytes]], | |
[0, Synth.basicNew(\pv_ana, nrtServer).newMsg], | |
[f.duration + (fftSize / nrtServer.options.sampleRate), | |
fftBuf.writeMsg(fftOut, "wav", "float"); | |
], | |
[f.duration + (fftSize / nrtServer.options.sampleRate), | |
pitchBuf.writeMsg(pitchOut, "wav", "float"); | |
] | |
]); | |
nrtScore.score.do(_.postln); | |
// Run score | |
nrtScore.recordNRT( | |
outputFilePath: if(thisProcess.platform.name == \windows) { "NUL" } { "/dev/null" }, | |
headerFormat: "wav", | |
sampleRate: nrtServer.options.sampleRate, | |
options: nrtServer.options, | |
duration: f.duration + (fftSize / nrtServer.options.sampleRate), | |
action: { "done".postln; cond.unhang } | |
); | |
cond.hang; | |
// Free score | |
nrtScore.free; | |
// Free NRT server | |
nrtServer.remove; | |
// not really needed b/c their server is gone | |
// inBuf.free; | |
// fftBuf.free; | |
// pitchBuf.free; | |
action.value; | |
}; | |
} | |
) | |
// 2. Prepare reference files | |
~fftSize = 2048; | |
// Default soundfile to be analysed | |
~wavPath = Platform.resourceDir +/+ "sounds/a11wlk01.wav"; | |
// ^^ but, better to substitute a monophonic instrument or vocal recording | |
// Default location for analysis file | |
~fftPath = "~/fft.wav".standardizePath; | |
~pitchPath = "~/pitch.wav".standardizePath; | |
~fftRefPath = ~fftPath.splitext[0] ++ "-reference.wav"; | |
~pitchRefPath = ~pitchPath.splitext[0] ++ "-reference.wav"; | |
~analyseWav.value(~wavPath, ~fftRefPath, ~pitchRefPath); | |
// 3. 30x test | |
( | |
fork { | |
var cond = Condition.new; | |
var fftReference = ~fftRefPath; | |
var pitchReference = ~pitchRefPath; | |
var getData = { |path| | |
var f = SoundFile.openRead(path); | |
var result; | |
protect { | |
result = Signal.newClear(f.numFrames * f.numChannels); | |
f.readData(result); | |
} { | |
f.close; | |
}; | |
result | |
}; | |
~fftRefData = getData.(fftReference); | |
~pitchRefData = getData.(pitchReference); | |
30.do { |i| | |
var fpath = ~fftPath.splitext[0] ++ i.asPaddedString(2) ++ ".wav"; | |
var ppath = ~pitchPath.splitext[0] ++ i.asPaddedString(2) ++ ".wav"; | |
var fData, pData; | |
~analyseWav.value(~wavPath, fpath, ppath, { cond.unhang }); | |
cond.hang; | |
fData = getData.(fpath); | |
if(fData != ~fftRefData) { | |
"Iteration '%' fft file is corrupt".format(i).warn; | |
}; | |
pData = getData.(ppath); | |
if(pData != ~pitchRefData) { | |
"Iteration '%' pitch file is corrupt".format(i).warn; | |
}; | |
}; | |
}; | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment