Implementing calibration
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import numpy as np
|
||||
from scipy.optimize import minimize
|
||||
|
||||
def logisticFunction(L, L_50, s_50):
|
||||
'''
|
||||
Calculate logistic function for SNRs L, 50% SRT point L_50, and slope
|
||||
s_50
|
||||
'''
|
||||
return 1./(1.+np.exp(4.*s_50*(L_50-L)))
|
||||
|
||||
def logisticFuncLiklihood(self, args):
|
||||
'''
|
||||
Calculate the log liklihood for given L_50 and s_50 parameters.
|
||||
This function is designed for use with the scipy minimize optimisation
|
||||
function to find the optimal L_50 and s_50 parameters.
|
||||
|
||||
args: a tuple containing (L_50, s_50)
|
||||
self.wordsCorrect: an n dimensional binary array of shape (N, 5),
|
||||
containing the correctness of responses to each of the 5 words for N
|
||||
trials
|
||||
self.trackSNR: A sorted list of SNRs of shape N, for N trials
|
||||
'''
|
||||
L_50, s_50 = args
|
||||
ck = self.wordsCorrect[np.arange(self.trackSNR.shape[0])]
|
||||
p_lf = self.logisticFunction(self.trackSNR, L_50, s_50)
|
||||
# Reshape array for vectorized calculation of log liklihood
|
||||
p_lf = p_lf[:, np.newaxis].repeat(5, axis=1)
|
||||
# Calculate the liklihood
|
||||
res = (p_lf**ck)*(((1.-p_lf)**(1.-ck)))
|
||||
with np.errstate(divide='raise'):
|
||||
try:
|
||||
a = np.concatenate(res)
|
||||
a[a == 0] = a.max()
|
||||
out = -np.sum(np.log(a))
|
||||
except:
|
||||
set_trace()
|
||||
return out
|
||||
|
||||
# Called from within a class in my implementation, will not work without a
|
||||
# class containing member variables for wordsCorrect and trackSNR
|
||||
res = minimize(logisticFuncLiklihood, np.array([-5.0,1.0]), method='L-BFGS-B')
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
sys.path.insert(0, "../matrix_test/helper_modules")
|
||||
|
||||
import numpy as np
|
||||
from pathops import dir_must_exist
|
||||
from filesystem import globDir
|
||||
from pysndfile import sndio
|
||||
import os
|
||||
from signalops import block_process_wav
|
||||
|
||||
def calc_potential_max(wavs, noise_filepath, out_dir, out_name):
|
||||
max_wav_samp = 0
|
||||
max_wav_rms = 0
|
||||
for wav in wavs:
|
||||
x, fs, enc = sndio.read(wav)
|
||||
max_wav_samp = np.max([max_wav_samp, np.max(np.abs(x))])
|
||||
max_wav_rms = np.max([max_wav_rms, np.sqrt(np.mean(x**2))])
|
||||
x, fs, enc = sndio.read(noise_filepath)
|
||||
noise_rms = np.sqrt(np.mean(x**2))
|
||||
max_noise_samp = max(np.abs(x))
|
||||
|
||||
snr = -15.0
|
||||
snr_fs = 10**(-snr/20)
|
||||
max_noise_samp *= max_wav_rms/noise_rms
|
||||
max_sampl = max_wav_samp+(max_noise_samp*snr_fs)
|
||||
reduction_coef = 1.0/max_sampl
|
||||
np.save(os.path.join(out_dir, "{}.npy".format(out_name)), reduction_coef)
|
||||
return reduction_coef
|
||||
|
||||
def main():
|
||||
'''
|
||||
'''
|
||||
da_files = ["../da_stim/stimulus/3000_da.wav"]
|
||||
story_dir = "../eeg_story_stim/stimulus"
|
||||
mat_dir = "../matrix_test/speech_components"
|
||||
noise_file = "../matrix_test/behavioural_stim/stimulus/wav/noise/noise.wav"
|
||||
|
||||
story_wavs = globDir(story_dir, '*.wav')
|
||||
mat_wavs = globDir(mat_dir, '*.wav')
|
||||
|
||||
out_dir = "./out"
|
||||
dir_must_exist(out_dir)
|
||||
story_coef = calc_potential_max(story_wavs, noise_file, out_dir, "story_red_coef")
|
||||
mat_coef = calc_potential_max(mat_wavs, noise_file, out_dir, "mat_red_coef")
|
||||
da_coef = calc_potential_max(da_files, noise_file, out_dir, "da_red_coef")
|
||||
|
||||
mat_cal_stim = "../matrix_test/long_concat_stim/out/stim/stim_0.wav"
|
||||
da_cal_stim = "../da_stim/stimulus/wav/10min_da.wav"
|
||||
click_cal_stim = "../click_stim/click_3000_20Hz.wav"
|
||||
story_cal_stim = "../eeg_story_stim/stimulus/odin_1_1.wav"
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,929 +0,0 @@
|
||||
{
|
||||
"patcher" : {
|
||||
"fileversion" : 1,
|
||||
"appversion" : {
|
||||
"major" : 6,
|
||||
"minor" : 1,
|
||||
"revision" : 10,
|
||||
"architecture" : "x64"
|
||||
}
|
||||
,
|
||||
"rect" : [ 0.0, 44.0, 1223.0, 678.0 ],
|
||||
"bglocked" : 0,
|
||||
"openinpresentation" : 0,
|
||||
"default_fontsize" : 12.0,
|
||||
"default_fontface" : 0,
|
||||
"default_fontname" : "Arial",
|
||||
"gridonopen" : 0,
|
||||
"gridsize" : [ 15.0, 15.0 ],
|
||||
"gridsnaponopen" : 0,
|
||||
"statusbarvisible" : 2,
|
||||
"toolbarvisible" : 1,
|
||||
"boxanimatetime" : 200,
|
||||
"imprint" : 0,
|
||||
"enablehscroll" : 1,
|
||||
"enablevscroll" : 1,
|
||||
"devicewidth" : 0.0,
|
||||
"description" : "",
|
||||
"digest" : "",
|
||||
"tags" : "",
|
||||
"boxes" : [ {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-51",
|
||||
"maxclass" : "flonum",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 53.25, 407.0, 88.0, 20.0 ],
|
||||
"presentation_rect" : [ 376.0, 544.0, 0.0, 0.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-52",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 141.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 464.0, 584.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-53",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 175.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 498.0, 584.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-54",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 141.25, 373.0, 33.0, 20.0 ],
|
||||
"presentation_rect" : [ 464.0, 510.0, 0.0, 0.0 ],
|
||||
"text" : "sig~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-55",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 173.75, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 496.5, 470.0, 0.0, 0.0 ],
|
||||
"text" : "1"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-56",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 141.25, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 464.0, 470.0, 0.0, 0.0 ],
|
||||
"text" : "0"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-57",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 3,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "signal", "signal" ],
|
||||
"patching_rect" : [ 141.25, 407.0, 110.0, 20.0 ],
|
||||
"text" : "groove~ noise_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-33",
|
||||
"maxclass" : "flonum",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 253.25, 407.0, 88.0, 20.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-34",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 341.25, 447.0, 32.5, 20.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-35",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 375.25, 447.0, 32.5, 20.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-37",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 341.25, 373.0, 33.0, 20.0 ],
|
||||
"text" : "sig~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-39",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 373.75, 333.0, 32.5, 18.0 ],
|
||||
"text" : "1"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-48",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 341.25, 333.0, 32.5, 18.0 ],
|
||||
"text" : "0"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-50",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 3,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "signal", "signal" ],
|
||||
"patching_rect" : [ 341.25, 407.0, 94.0, 20.0 ],
|
||||
"text" : "groove~ da_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-32",
|
||||
"maxclass" : "flonum",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 442.25, 407.0, 88.0, 20.0 ],
|
||||
"presentation_rect" : [ 557.0, 512.0, 0.0, 0.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-30",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 530.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 503.0, 573.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-31",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 564.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 537.0, 573.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-19",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 530.25, 373.0, 33.0, 20.0 ],
|
||||
"presentation_rect" : [ 732.0, 455.0, 0.0, 0.0 ],
|
||||
"text" : "sig~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-25",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 562.75, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 697.0, 411.0, 0.0, 0.0 ],
|
||||
"text" : "1"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-26",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 530.25, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 622.0, 416.0, 0.0, 0.0 ],
|
||||
"text" : "0"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-29",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 3,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "signal", "signal" ],
|
||||
"patching_rect" : [ 530.25, 407.0, 104.0, 20.0 ],
|
||||
"text" : "groove~ click_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-17",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 682.0, 486.0, 20.0 ],
|
||||
"text" : "loadmess append OSX:/Users/samuelperry/Work/SOTON/Initial_work/BPLabs/click_stim/"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-13",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 835.75, 204.0, 97.0, 20.0 ],
|
||||
"presentation_rect" : [ 512.0, 408.0, 0.0, 0.0 ],
|
||||
"text" : "prepend replace"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-14",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 835.75, 164.0, 79.0, 20.0 ],
|
||||
"presentation_rect" : [ 512.0, 368.0, 0.0, 0.0 ],
|
||||
"text" : "absolutepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-15",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 835.75, 132.0, 127.0, 18.0 ],
|
||||
"presentation_rect" : [ 512.0, 299.0, 0.0, 0.0 ],
|
||||
"text" : "click_3000_20Hz.wav"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-16",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"patching_rect" : [ 835.75, 235.0, 98.0, 20.0 ],
|
||||
"text" : "buffer~ click_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-28",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 702.0, 476.0, 20.0 ],
|
||||
"text" : "loadmess append OSX:/Users/samuelperry/Work/SOTON/Initial_work/BPLabs/da_stim/"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-27",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 662.0, 596.0, 20.0 ],
|
||||
"text" : "loadmess append OSX:/Users/samuelperry/Work/SOTON/Initial_work/BPLabs/matrix_test/stimulus/wav/noise/"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-23",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 650.0, 132.0, 64.0, 18.0 ],
|
||||
"text" : "noise.wav"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-20",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 650.0, 204.0, 97.0, 20.0 ],
|
||||
"text" : "prepend replace"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-21",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 650.0, 164.0, 79.0, 20.0 ],
|
||||
"text" : "absolutepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-22",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"patching_rect" : [ 650.0, 235.0, 103.0, 20.0 ],
|
||||
"text" : "buffer~ noise_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-18",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 508.0, 204.0, 97.0, 20.0 ],
|
||||
"text" : "prepend replace"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-2",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 750.0, 49.0, 20.0 ],
|
||||
"text" : "filepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-11",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 508.0, 164.0, 79.0, 20.0 ],
|
||||
"text" : "absolutepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-10",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 508.0, 132.0, 82.0, 18.0 ],
|
||||
"text" : "3000_da.wav"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-8",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"patching_rect" : [ 508.0, 235.0, 88.0, 20.0 ],
|
||||
"text" : "buffer~ da_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-6",
|
||||
"maxclass" : "ezdac~",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 0,
|
||||
"patching_rect" : [ 341.25, 537.0, 45.0, 45.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
"lines" : [ {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-11", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-10", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-18", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-11", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-16", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-13", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-13", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-14", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-14", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-15", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-17", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-8", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-18", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-29", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-19", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-22", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-20", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-20", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-21", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-21", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-23", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-19", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-25", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-19", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-26", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-27", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-28", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-30", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-29", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-31", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-29", 1 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-30", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-31", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-30", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-32", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-31", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-32", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-34", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-33", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-35", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-33", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-34", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-35", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-50", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-37", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-37", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-39", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-37", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-48", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-34", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-50", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-35", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-50", 1 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-52", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-51", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-53", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-51", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-52", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-53", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-57", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-54", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-54", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-55", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-54", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-56", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-52", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-57", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-53", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-57", 1 ]
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
"dependency_cache" : [ ]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
sys.path.insert(0, "../matrix_test/helper_modules")
|
||||
from scipy.signal import square
|
||||
from pysndfile import sndio
|
||||
import numpy as np
|
||||
import pdb
|
||||
import matplotlib.pyplot as plt
|
||||
from signalops import gen_trigger
|
||||
|
||||
def gen_click(idx, freq, length, fs):
|
||||
duty = length*freq
|
||||
@@ -22,7 +25,12 @@ def main():
|
||||
y = (np.arange(length) % period == 0).astype(float)
|
||||
y[np.where(y == 1.0)[0][1::2]] = -1.0
|
||||
y = np.concatenate([np.zeros(fs), y, np.zeros(fs)])
|
||||
print("Number of clicks generated: {}".format(np.sum(np.abs(y) == 1.0)))
|
||||
|
||||
idx = np.arange(y.size)
|
||||
trigger = gen_trigger(idx, 2., 0.01, fs)
|
||||
y = np.vstack((y, y, trigger)).T
|
||||
|
||||
print("Number of clicks generated: {}".format(np.sum(np.abs(y[:, 0]) == 1.0)))
|
||||
sndio.write('./click_3000_20Hz.wav', y, rate = fs, format='wav', enc='pcm16')
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+10
-2
@@ -8,6 +8,7 @@ import numpy as np
|
||||
import pdb
|
||||
import matplotlib.pyplot as plt
|
||||
from pathops import dir_must_exist
|
||||
from signalops import gen_trigger
|
||||
|
||||
def gen_da_stim(n, outpath):
|
||||
da_file = './BioMAP_da-40ms.wav'
|
||||
@@ -21,8 +22,15 @@ def gen_da_stim(n, outpath):
|
||||
y_part_inv = -y_part
|
||||
|
||||
y_2part = np.concatenate([y_part, y_part_inv])
|
||||
y = np.tile(y_2part, n)
|
||||
sndio.write(outpath, y, rate = fs, format = fmt, enc=enc)
|
||||
y_r = np.tile(y_2part, n)
|
||||
y_r = np.insert(y_r, 0, np.zeros(fs))
|
||||
y_l = np.zeros(y_r.size)
|
||||
|
||||
idx = np.arange(y_l.size)
|
||||
trigger = gen_trigger(idx, 2., 0.01, fs)
|
||||
|
||||
y = np.vstack((y_l, y_r, trigger))
|
||||
sndio.write(outpath, y.T, rate = fs, format = fmt, enc=enc)
|
||||
return outpath
|
||||
|
||||
|
||||
|
||||
Executable
+260
@@ -0,0 +1,260 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
sys.path.insert(0, "../matrix_test/helper_modules")
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import errno
|
||||
import shutil
|
||||
import re
|
||||
import fnmatch
|
||||
import pdb
|
||||
import numpy as np
|
||||
from natsort import natsorted
|
||||
from collections import namedtuple
|
||||
from pysndfile import PySndfile, sndio
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from gen_da import gen_da_stim
|
||||
|
||||
from pathops import dir_must_exist
|
||||
try:
|
||||
from signalops import rolling_window_lastaxis, calc_rms
|
||||
except ImportError:
|
||||
from .signalops import rolling_window_lastaxis, block_lfilter, calc_rms
|
||||
|
||||
import scipy.signal as sgnl
|
||||
from scipy.stats import pearsonr
|
||||
|
||||
from pyswarm import pso
|
||||
|
||||
try:
|
||||
from lpc import lpc
|
||||
except ImportError:
|
||||
from .lpc import lpc
|
||||
|
||||
try:
|
||||
from filesystem import globDir, organiseWavs, prepareOutDir
|
||||
except ImportError:
|
||||
from .filesystem import globDir, organiseWavs, prepareOutDir
|
||||
|
||||
|
||||
def block_lfilter_wav(b, a, x, outfile, fmt, fs, blocksize=8192):
|
||||
'''
|
||||
Filter 1D signal in blocks. For use with large signals
|
||||
'''
|
||||
new_state = np.zeros(b.size-1)
|
||||
sndfile = PySndfile(outfile, 'w', fmt, 1, fs)
|
||||
i = 0
|
||||
y_out = np.zeros(x.size)
|
||||
while i < x.size:
|
||||
print("Filtering {0} to {1} of {2}".format(i, i+blocksize, x.size))
|
||||
if i+blocksize > x.size:
|
||||
y, new_state = sgnl.lfilter(b,a,x[i:-1], zi=new_state)
|
||||
sndfile.write_frames(y)
|
||||
y_out[i:i+y.size] = y
|
||||
else:
|
||||
y, new_state = sgnl.lfilter(b,a,x[i:i+blocksize], zi=new_state)
|
||||
sndfile.write_frames(y)
|
||||
y_out[i:i+y.size] = y
|
||||
i += blocksize
|
||||
return y_out
|
||||
|
||||
|
||||
def synthesize_trial(wavFileMatrix, indexes):
|
||||
'''
|
||||
Using the matrix of alternative words and the selected words for each
|
||||
column, generate samples from audio files
|
||||
Returns an array of samples generated by concatenating the selected audio
|
||||
files
|
||||
'''
|
||||
columnNames = ['a', 'b', 'c', 'd', 'e']
|
||||
indexes = np.pad(indexes, ((0, 1)), 'constant', constant_values=0)
|
||||
indexes = rolling_window_lastaxis(indexes, 2)
|
||||
offset = 10
|
||||
y = np.array([])
|
||||
filenames = []
|
||||
for name, ind in zip(columnNames, indexes):
|
||||
if name == 'e':
|
||||
offset = 1
|
||||
wavFilename, wavFilepath = wavFileMatrix[name][(ind[0]*offset)+ind[1]]
|
||||
wav = PySndfile(wavFilepath)
|
||||
fs = wav.samplerate()
|
||||
x = wav.read_frames()
|
||||
y = np.append(y, x)
|
||||
filenames.append(wavFilename)
|
||||
return (y, {'rate': fs, 'format': wav.major_format_str(), 'enc': wav.encoding_str()}, filenames)
|
||||
|
||||
|
||||
def gen_audio_stim(da, OutDir, indexes):
|
||||
if os.path.exists(OutDir):
|
||||
shutil.rmtree(OutDir)
|
||||
os.makedirs(OutDir)
|
||||
wavFiles = globDir(MatrixDir, '*.wav')
|
||||
wavFileMatrix = organiseWavs(wavFiles)
|
||||
wavDir = os.path.join(OutDir, "wav")
|
||||
dir_must_exist(wavDir)
|
||||
wavDir = os.path.join(wavDir, "noise-sentences")
|
||||
dir_must_exist(wavDir)
|
||||
files = []
|
||||
n = 0
|
||||
o = 0
|
||||
for sentenceList in indexes:
|
||||
n += 1
|
||||
o = 0
|
||||
files.append([])
|
||||
for ind in sentenceList:
|
||||
o += 1
|
||||
y, wavInfo, partnames = synthesize_trial(wavFileMatrix, ind)
|
||||
fileName = os.path.join(wavDir, 'Trial_{0:02d}_{1:02d}.wav'.format(n, o))
|
||||
print("Generating: " + fileName)
|
||||
sndio.write(fileName, y, **wavInfo)
|
||||
files[-1].append(fileName)
|
||||
|
||||
return files
|
||||
|
||||
def gen_indexes():
|
||||
x = np.repeat(np.arange(10), 5)
|
||||
x = x.reshape(10, 5)
|
||||
|
||||
y = np.zeros((50, 10, 5), dtype=int)
|
||||
|
||||
# 50 lists
|
||||
for i in range(50):
|
||||
x[:, 1] = np.roll(x[:, 1], 1)
|
||||
x[:, 2] = np.roll(x[:, 2], 2)
|
||||
x[:, 3] = np.roll(x[:, 3], 3)
|
||||
x[:, 4] = np.roll(x[:, 4], 4)
|
||||
y[i] = x.copy()
|
||||
return y
|
||||
|
||||
def gen_rms(files, OutDir):
|
||||
rmsFiles = []
|
||||
for file in files:
|
||||
head, tail = os.path.split(file)
|
||||
tail = os.path.splitext(tail)[0]
|
||||
tail = tail + "_rms.npy"
|
||||
dir_must_exist(OutDir)
|
||||
rmsFilepath = os.path.join(OutDir, tail)
|
||||
print("Generating: "+rmsFilepath)
|
||||
y, fs, _ = sndio.read(file)
|
||||
y_rms = calc_rms(y, round(0.02*fs))
|
||||
np.save(rmsFilepath, y_rms)
|
||||
rmsFiles.append(rmsFilepath)
|
||||
return rmsFiles
|
||||
|
||||
def detect_silences(rmsFiles, fs, seg_min_size=0.02):
|
||||
print("Detecting silence in wav files...")
|
||||
if not seg_min_size:
|
||||
seg_min_size = np.inf
|
||||
silences = []
|
||||
for envelopeFile in rmsFiles:
|
||||
env = np.load(envelopeFile)
|
||||
silence = env < 0.001
|
||||
# Get segment start end indexes for all silences in envelope
|
||||
silentSegs = np.where(np.concatenate(([silence[0]],silence[:-1]!=silence[1:],[True])))[0].reshape(-1, 2)
|
||||
validSegs = np.diff(silentSegs) > seg_min_size*fs
|
||||
silences.append(silentSegs[np.repeat(validSegs, 2, axis=1)].reshape(-1, 2))
|
||||
return silences
|
||||
|
||||
|
||||
def calc_spectrum(files, silences, fs=44100, plot=False):
|
||||
window = 4096
|
||||
sentenceLen = []
|
||||
sentenceFFT = []
|
||||
|
||||
print("Calculating LTASS...")
|
||||
for ind, file in enumerate(files):
|
||||
x, fs, _ = sndio.read(file)
|
||||
f, t, Zxx = sgnl.stft(x, window=np.ones(window), nperseg=window, noverlap=0)
|
||||
sil = silences[ind]
|
||||
sTemp = np.zeros((sil.shape[0], t.size), dtype=bool)
|
||||
for ind3, s in enumerate(sil):
|
||||
sTemp[ind3, :] = np.logical_and(t > s[0], t < s[1])
|
||||
invalidFFT = np.any(sTemp, axis=0)
|
||||
sentenceFFT.append(np.abs(Zxx[:, ~np.any(sTemp, axis=0)]))
|
||||
sentenceLen.append(x.size)
|
||||
sentenceLen = np.array([sentenceLen]).T
|
||||
sentenceLen = sentenceLen / sentenceLen.max()
|
||||
sentenceFFT = [x * sentenceLen[i] for i, x in enumerate(sentenceFFT)]
|
||||
sentenceFFT = np.concatenate([x.T for x in sentenceFFT])
|
||||
|
||||
grandAvgFFT = np.mean(sentenceFFT, axis=0)
|
||||
grandAvgFFT = grandAvgFFT / grandAvgFFT.max()
|
||||
print("Fitting filter to LTASS...")
|
||||
b = sgnl.firls(2049, np.linspace(0, 1, 2049)[1:], grandAvgFFT[1:])
|
||||
if plot:
|
||||
plt.semilogy(np.abs(sgnl.freqz(b)[1]))
|
||||
plt.plot(np.linspace(0, 512, 2049), grandAvgFFT)
|
||||
plt.show()
|
||||
return b
|
||||
|
||||
|
||||
def gen_noise(OutDir, b, fs, s_rms):
|
||||
print("Generating noise...")
|
||||
# Generate 10 minutes of white noise
|
||||
x = np.random.randn(int(fs*60.*20.))
|
||||
x /= x.max()
|
||||
noiseDir = os.path.join(OutDir, 'wav')
|
||||
noiseRMSDir = os.path.join(OutDir, 'rms')
|
||||
dir_must_exist(noiseDir)
|
||||
noiseDir = os.path.join(noiseDir, 'noise')
|
||||
dir_must_exist(noiseDir)
|
||||
y = block_lfilter_wav(b, [1.0], x, os.path.join(noiseDir, 'noise.wav'), 65538, 44100)
|
||||
noise_rms_path = os.path.join(noiseRMSDir, 'noise_rms.npy')
|
||||
rms = np.sqrt(np.mean(y**2))
|
||||
np.save(noise_rms_path, rms)
|
||||
return y
|
||||
|
||||
|
||||
def calc_speech_rms(files, silences, rmsDir, fs=44100, plot=False):
|
||||
'''
|
||||
'''
|
||||
f = files
|
||||
sumsqrd = 0.0
|
||||
n = 0
|
||||
for wavfile, sil in zip(f, silences):
|
||||
y, fs, _ = sndio.read(wavfile)
|
||||
t = np.arange(y.size)
|
||||
sTemp = np.zeros(t.size, dtype=bool)
|
||||
print("Started")
|
||||
for ind, s in enumerate(sil):
|
||||
print("Check {}".format(ind))
|
||||
sTemp = np.logical_or(sTemp, np.logical_and(t > s[0], t < s[1]))
|
||||
print("Done")
|
||||
silentSamples = np.any(sTemp, axis=0)
|
||||
y_temp = y[~silentSamples]
|
||||
sumsqrd += np.sum(y_temp**2)
|
||||
n += y_temp.size
|
||||
rms = np.sqrt(sumsqrd/n)
|
||||
np.save(os.path.join(rmsDir, 'overall_da_rms.npy'), rms)
|
||||
return rms
|
||||
#sentenceFFT.append(np.abs(Zxx[:, ~np.any(sTemp, axis=0)]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from pathtype import PathType
|
||||
# Create commandline interface
|
||||
parser = argparse.ArgumentParser(description='Generate stimulus for '
|
||||
'training TRF decoder by concatenating '
|
||||
'matrix test materials')
|
||||
parser.add_argument('--OutDir', type=PathType(exists=None, type='dir'),
|
||||
default='./stimulus', help='Output directory')
|
||||
parser.add_argument('--CalcRMS', action='store_true')
|
||||
args = {k:v for k,v in vars(parser.parse_args()).items() if v is not None}
|
||||
|
||||
rmsDir = os.path.join(args['OutDir'], "rms")
|
||||
dir_must_exist(rmsDir)
|
||||
wavDir = os.path.join(args['OutDir'], "wav")
|
||||
dir_must_exist(wavDir)
|
||||
if args['CalcRMS']:
|
||||
daFile = gen_da_stim(3333, os.path.join(wavDir, '10min_da.wav'))
|
||||
rmsFiles = gen_rms([daFile], rmsDir)
|
||||
else:
|
||||
daFile = globDir(wavDir, '*.wav')[0]
|
||||
rmsFile = globDir(rmsDir, '*.npy')[0]
|
||||
silences = detect_silences([rmsFile], 44100, None)
|
||||
s_rms = calc_speech_rms([daFile], silences, rmsDir)
|
||||
b = calc_spectrum([daFile], silences)
|
||||
y = gen_noise(args['OutDir'], b, 44100, s_rms)
|
||||
@@ -62,7 +62,6 @@ class EEGMatTrainThread(BaseThread):
|
||||
|
||||
self.reduction_coef = np.load(red_coef)
|
||||
|
||||
|
||||
self.wav_files = []
|
||||
self.marker_files = []
|
||||
self.question_files = []
|
||||
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
sys.path.insert(0, "../matrix_test/helper_modules")
|
||||
|
||||
from filesystem import globDir
|
||||
from pudb import set_trace
|
||||
from pysndfile import sndio
|
||||
from signalops import gen_trigger
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
def main():
|
||||
'''
|
||||
'''
|
||||
wavs = globDir("./stimulus", "*.wav")
|
||||
for wav in wavs:
|
||||
x, fs, enc, fmt = sndio.read(wav, return_format=True)
|
||||
y_r = np.insert(x, 0, np.zeros(fs))
|
||||
idx = np.arange(x.shape[0])
|
||||
y = np.vstack([x, x, np.zeros(x.shape[0])]).T
|
||||
trigger = gen_trigger(idx, 2., 0.01, fs)
|
||||
y[:, 2] = trigger
|
||||
wav_out = os.path.splitext(wav)[0] + "_trig.wav"
|
||||
sndio.write(wav_out, y, rate=fs, format=fmt, enc=enc)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,3 +0,0 @@
|
||||
1, What items did the dwarves forge?
|
||||
2, Could they work in peace?
|
||||
3, Who is, in fact, Gadfly?
|
||||
@@ -59,6 +59,8 @@ class EEGTestThread(BaseThread):
|
||||
self.question = []
|
||||
self.response = []
|
||||
|
||||
self.reduction_coef = np.load(red_coef)
|
||||
|
||||
# Percent speech inteligibility (estimated using behavioural measure)
|
||||
# to present stimuli at
|
||||
self.si = np.array([20.0, 35.0, 50.0, 65.0, 80.0, 90.0, 100.0])
|
||||
|
||||
@@ -5,6 +5,7 @@ import queue
|
||||
import sys
|
||||
import threading
|
||||
from pysndfile import PySndfile, construct_format
|
||||
from scipy.signal import square
|
||||
|
||||
import sounddevice as sd
|
||||
import soundfile as sf
|
||||
@@ -83,6 +84,24 @@ def block_lfilter(b, a, x, blocksize=8192):
|
||||
i += blocksize
|
||||
return out
|
||||
|
||||
def block_process_wav(wavpath, out_wavpath, func, block_size=4096, **args):
|
||||
'''
|
||||
Mix two wav files, applying gains to each
|
||||
'''
|
||||
wav = PySndfile(wavpath_a, 'r')
|
||||
|
||||
out_wav = PySndfile(out_wavpath, 'w', construct_format('wav', 'pcm16'), wav.channels(), wav.samplerate())
|
||||
|
||||
i = 0
|
||||
while i < wav_a.frames():
|
||||
if i+block_size > wav_a.frames():
|
||||
block_size = wav_a.frames()-i
|
||||
x = wav_a.read_frames(block_size)
|
||||
y = func(x, **args)
|
||||
out_wav.write_frames(x1)
|
||||
i += block_size
|
||||
|
||||
|
||||
def block_mix_wavs(wavpath_a, wavpath_b, out_wavpath, a_gain=1., b_gain=1., block_size=4096):
|
||||
'''
|
||||
Mix two wav files, applying gains to each
|
||||
@@ -104,6 +123,13 @@ def block_mix_wavs(wavpath_a, wavpath_b, out_wavpath, a_gain=1., b_gain=1., bloc
|
||||
i += block_size
|
||||
|
||||
|
||||
def gen_trigger(x, freq, length, fs):
|
||||
|
||||
duty = length*freq
|
||||
trigger = square(2*np.pi*(x/fs)*freq, duty=duty)
|
||||
trigger[trigger < 0] = 0
|
||||
return trigger
|
||||
|
||||
|
||||
def calc_rms(y, window, plot=False):
|
||||
y_2 = y**2
|
||||
|
||||
@@ -10,13 +10,14 @@ import shutil
|
||||
import errno
|
||||
import re
|
||||
import fnmatch
|
||||
import pdb
|
||||
import pudb
|
||||
import numpy as np
|
||||
from natsort import natsorted
|
||||
from collections import namedtuple
|
||||
import pysndfile
|
||||
from pysndfile import sndio, PySndfile
|
||||
|
||||
from signalops import gen_trigger
|
||||
from pathtype import PathType
|
||||
from tokens_to_words import tokens_to_words, load_component_map
|
||||
|
||||
@@ -82,29 +83,44 @@ def concatenateStimuli(MatrixDir, OutDir, Length, n):
|
||||
totalSize += size
|
||||
totalSize += int(0.1*fs)
|
||||
if (totalSize/fs) > Length:
|
||||
y.append(np.zeros(totalSize))
|
||||
# total size + 2 second silence at start
|
||||
y.append(np.zeros((totalSize+2*fs, 3)))
|
||||
parts.append([])
|
||||
questions.append([])
|
||||
i += 1
|
||||
totalSize = 0
|
||||
|
||||
writePtr = 0
|
||||
writePtr = 2*fs
|
||||
idx = np.arange(0, writePtr)
|
||||
chunk = np.zeros(idx.size)
|
||||
chunk = np.vstack([chunk, chunk, chunk]).T
|
||||
trigger = gen_trigger(idx, 2., 0.01, fs)
|
||||
chunk[:, 2] = trigger
|
||||
for i, _ in enumerate(y):
|
||||
y[i][0:writePtr, :] = chunk
|
||||
|
||||
i = 0
|
||||
for wav, word, part in zip(wavFiles, stim_word_rows, stim_part_rows):
|
||||
if writePtr >= y[i].size:
|
||||
if writePtr >= y[i].shape[0]:
|
||||
i += 1
|
||||
writePtr = 0
|
||||
writePtr = fs*2
|
||||
if i == n:
|
||||
break
|
||||
x, fs, encStr, fmtStr = sndio.read(wav, return_format=True)
|
||||
threeMs = int(0.1*fs)
|
||||
silence = np.zeros(threeMs)
|
||||
chunk = np.append(x, silence)
|
||||
y[i][writePtr:writePtr + chunk.size] = chunk
|
||||
|
||||
idx = np.arange(writePtr, writePtr+chunk.shape[0])
|
||||
chunk = np.vstack([chunk, chunk, np.zeros(chunk.shape[0])]).T
|
||||
trigger = gen_trigger(idx, 2., 0.01, fs)
|
||||
chunk[:, 2] = trigger
|
||||
|
||||
y[i][writePtr:writePtr + chunk.shape[0], :] = chunk
|
||||
questions[i].append(word)
|
||||
parts[i].append(part)
|
||||
|
||||
writePtr += chunk.size
|
||||
writePtr += chunk.shape[0]
|
||||
|
||||
for ind, (data, q, p) in enumerate(zip(y, questions, parts)):
|
||||
pysndfile.sndio.write(os.path.join(OutDir, 'stim_{}.wav'.format(ind)), data, format=fmtStr, enc=encStr)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
sys.path.insert(0, "../helper_modules/")
|
||||
|
||||
def main():
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -108,6 +108,11 @@ def main():
|
||||
sample(range(stim_count_half, stim_count-1), n_questions)
|
||||
]).T
|
||||
a = 0
|
||||
silence = np.zeros((88200, 3))
|
||||
idx = np.arange(0, silence.shape[0])
|
||||
trigger = gen_trigger(idx, 2., 0.01, fs)
|
||||
silence[:, 2] = trigger
|
||||
out_wav.write_frames(silence)
|
||||
for ind, (wav, txt) in enumerate(zip(merged_wavs, words)):
|
||||
csv_line = [counter]
|
||||
silence = np.zeros((int(np.random.uniform(int(0.3*44100), int(0.4*44100), 1)), 3))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% extends 'participant_index.html' %}
|
||||
{% block content %}
|
||||
<div id="main-div" class="outer">
|
||||
<h3 id="question"></h3>
|
||||
<div class="mat_grid">
|
||||
<button type="button" href="#" disabled id="mat-0" class="Btn Btn-outline-secondary mat-button">Peter</button>
|
||||
<button type="button" href="#" disabled id="mat-1" class="Btn Btn-outline-secondary mat-button">got</button>
|
||||
@@ -100,6 +101,10 @@
|
||||
// Disable all inputs whilst processing
|
||||
$('#main-div').find('input, textarea, button, select').attr('disabled','disabled');
|
||||
});
|
||||
socket.on('question', function(msg) {
|
||||
// Disable all inputs whilst processing
|
||||
$('#question').text(msg);
|
||||
});
|
||||
|
||||
socket.on('stim_done', function(msg) {
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from pysndfile import sndio
|
||||
import numpy as np
|
||||
import pdb
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def main():
|
||||
'''
|
||||
Generate train of equally spaced clicks
|
||||
'''
|
||||
fs = 44100
|
||||
n = np.arange(fs*10)
|
||||
trig_s = np.where(np.mod(n, fs/2.) == 0)
|
||||
click = np.ones(int(0.01*fs))
|
||||
y = np.zeros(n.size)
|
||||
for i in trig_s[0]:
|
||||
y[i:i+click.size] = click
|
||||
|
||||
sndio.write("./trig_test.wav", y, fs, format='wav', enc='pcm16')
|
||||
|
||||
pdb.set_trace()
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user