├── .gitignore ├── src ├── waviostream.hpp ├── makefile ├── myfft.h ├── slideBlock.hpp ├── slidingHPSS.cpp └── HPSS.hpp ├── twostageHPSS_scripts ├── R │ ├── readme.md │ ├── Rlib │ │ └── mylib.R │ ├── experiment_2.R │ └── experiment_1.R └── twostageHPSS.sh ├── setup.sh ├── experiment_setup.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | experiments/* 3 | 4 | -------------------------------------------------------------------------------- /src/waviostream.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tachi-hi/slidingHPSS/HEAD/src/waviostream.hpp -------------------------------------------------------------------------------- /twostageHPSS_scripts/R/readme.md: -------------------------------------------------------------------------------- 1 | The scripts in this directory were used for the experiments in our paper. 2 | 3 | 4 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # make 4 | cd src; make; cd .. 5 | 6 | # create a directory "bin" 7 | if [ ! -d bin ]; 8 | then 9 | mkdir bin 10 | fi 11 | 12 | # mv 13 | mv src/slidingHPSS bin 14 | 15 | -------------------------------------------------------------------------------- /twostageHPSS_scripts/twostageHPSS.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | BINDIR=./bin 4 | HPSS=${BINDIR}/slidingHPSS 5 | # This is an example of two-stage HPSS 6 | 7 | ${HPSS} --input input.wav --block 100 --frame 128 --Hout _H1.wav --Pout _P.wav -Q 0.3 -W 0.3 8 | ${HPSS} --input _H1.wav --block 100 --frame 8192 --Hout _H.wav --Pout _V.wav -Q 0.3 -W 0.3 9 | 10 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -O3 -Wall #-pg -g 3 | RM = rm -f 4 | 5 | EXE = slidingHPSS 6 | SRC = slidingHPSS.cpp 7 | 8 | ## Libraries 9 | L_FFTW3 = -lfftw3 10 | LIBS = $(L_FFTW3) -lm 11 | 12 | # ----------------------------------- 13 | .PHONY: all 14 | all: 15 | $(CXX) $(CXXFLAGS) -o $(EXE) $(SRC) $(LIBS) 16 | 17 | .SUFFIXES: .o .cpp 18 | .cpp.o: 19 | $(CXX) $(CXXFLAGS) -c $< 20 | 21 | .PHONY: clean 22 | clean: 23 | $(RM) $(EXE) 24 | $(RM) *~ 25 | 26 | 27 | -------------------------------------------------------------------------------- /experiment_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | YOUR_WORKING_DIRECTORY=experiments 4 | 5 | bash setup.sh 6 | 7 | # create a directory 8 | if [ ! -d $YOUR_WORKING_DIRECTORY ]; 9 | then mkdir $YOUR_WORKING_DIRECTORY; fi 10 | 11 | if [ ! -d $YOUR_WORKING_DIRECTORY/tmp ]; 12 | then mkdir $YOUR_WORKING_DIRECTORY/tmp; fi 13 | 14 | if [ ! -d $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX ]; 15 | then mkdir $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX 16 | touch $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX/place_here_MIR1K_data; fi 17 | 18 | if [ ! -d $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX/Wavfile ]; 19 | then mkdir $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX/Wavfile; fi 20 | 21 | # Example files 22 | if [ ! -d $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX/Wavfile/ ]; 23 | then 24 | touch $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX/Wavfile/Ani_1_01.wav 25 | touch $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX/Wavfile/Ani_1_02.wav 26 | touch $YOUR_WORKING_DIRECTORY/MIR-1K_for_MIREX/Wavfile/Ani_1_03.wav 27 | fi 28 | 29 | 30 | 31 | cp ./bin/slidingHPSS $YOUR_WORKING_DIRECTORY 32 | cp -r ./twostageHPSS_scripts/R/* $YOUR_WORKING_DIRECTORY 33 | if [ ! -e $YOUR_WORKING_DIRECTORY/my_experiment_1.R ]; 34 | then cp ./twostageHPSS_scripts/R/experiment_1.R $YOUR_WORKING_DIRECTORY/my_experiment_1.R; fi 35 | 36 | if [ ! -e $YOUR_WORKING_DIRECTORY/my_experiment_2.R ]; 37 | then cp ./twostageHPSS_scripts/R/experiment_2.R $YOUR_WORKING_DIRECTORY/my_experiment_2.R; fi 38 | -------------------------------------------------------------------------------- /src/myfft.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | // wrappaer of fftw 6 | class FFT_forward{ 7 | public: 8 | FFT_forward(int size) 9 | { 10 | real = new double[size]; 11 | cmplx = new std::complex [size/2+1]; 12 | p = fftw_plan_dft_r2c_1d( 13 | size, 14 | real, 15 | reinterpret_cast(cmplx), 16 | FFTW_ESTIMATE); 17 | in = real; 18 | out = cmplx; 19 | } 20 | ~FFT_forward(){ 21 | fftw_destroy_plan(p); 22 | delete[] real; 23 | delete[] cmplx; 24 | } 25 | void exec(){ 26 | fftw_execute(p); 27 | } 28 | 29 | double *in; 30 | std::complex *out; 31 | private: 32 | fftw_plan p; 33 | double *real; 34 | std::complex *cmplx; 35 | }; 36 | 37 | class FFT_backward{ 38 | public: 39 | FFT_backward(int size__) 40 | { 41 | size = size__; 42 | real = new double[size]; 43 | cmplx = new std::complex [size/2+1]; 44 | p = fftw_plan_dft_c2r_1d( 45 | size, 46 | reinterpret_cast(cmplx), 47 | real, 48 | FFTW_ESTIMATE); 49 | in = cmplx; 50 | out = real; 51 | } 52 | ~FFT_backward(){ 53 | fftw_destroy_plan(p); 54 | delete[] real; 55 | delete[] cmplx; 56 | } 57 | 58 | void exec(){ 59 | fftw_execute(p); 60 | for(int i = 0; i < size; i++){ 61 | out[i] /= static_cast(size); // bug? (static_cast(size)/2 + 1); 62 | } 63 | } 64 | 65 | double *out; 66 | std::complex *in; 67 | private: 68 | fftw_plan p; 69 | double *real; 70 | std::complex *cmplx; 71 | int size; 72 | }; 73 | 74 | 75 | -------------------------------------------------------------------------------- /twostageHPSS_scripts/R/Rlib/mylib.R: -------------------------------------------------------------------------------- 1 | library(tuneR); 2 | 3 | "%+=%" <- function(a,b) eval.parent(substitute(a <- a + b)); 4 | "%-=%" <- function(a,b) eval.parent(substitute(a <- a - b)); 5 | "%*=%" <- function(a,b) eval.parent(substitute(a <- a * b)); 6 | "%/=%" <- function(a,b) eval.parent(substitute(a <- a / b)); 7 | 8 | ifft <- function(x) (fft(x, inverse=TRUE)/length(x)); 9 | 10 | fft.half <- function(x) 11 | (fft(x)[1:(length(x)/2+1)]); 12 | ifft.half <- function(x) 13 | (Re(fft( 14 | c(x, Conj(rev(x[2:(length(x)-1)]))), 15 | inverse=TRUE)/(length(x)*2-2))); 16 | 17 | hamming <- function(x) (0.54 - 0.46 * cos(2 * pi * x / length(x))); 18 | hanning <- function(x) (0.50 - 0.50 * cos(2 * pi * x / length(x))); 19 | sqrthan <- function(x) (sin(pi * x/length(x))); 20 | 21 | stft.half <- function(wave, len, shi, winfunc=function(x){sqrt(hanning(x))}){ 22 | n.frame <- length(wave) %/% shi - 1; 23 | nyq <- len/2 + 1; 24 | stft <- matrix(nrow = n.frame, ncol = nyq); 25 | for(i in 1:(n.frame)){ 26 | stft[i,] <- fft.half(wave[(i-1) * shi + (1:len)] * winfunc(1:len)); 27 | } 28 | return(stft); 29 | } 30 | 31 | istft.half <- function(STFT, shi,winfunc=function(x){sqrt(hanning(x))}){ 32 | len <- length(STFT[1,]) * 2 - 2; 33 | n.frame <- length(STFT[,1]); 34 | win <- winfunc(1:len); 35 | invSTFT <- numeric((n.frame+1) * shi); 36 | for(i in 1:(n.frame)){ 37 | tmp <- Re(win * ifft.half(STFT[i,])); 38 | invSTFT[(shi * (i-1) + 1):(shi * (i-1) + len)] %+=% tmp[1:len]; 39 | } 40 | return(invSTFT); 41 | } 42 | 43 | wavsave <- function(wave, file){ 44 | out <- normalize(Wave(wave, samp.rate=8000, bit=16), unit="16") * 0.1; 45 | writeWave(out,file); 46 | } 47 | 48 | rbcol <- rainbow(100,start=0,end=0.7); 49 | #rbcol <- rainbow(100,start=0,end=0.75); 50 | mncol <- gray(1:100/100); 51 | 52 | #powscale <- function(x){log(abs(x))} 53 | powscale <- function(x){abs(x)**0.5} 54 | 55 | spectrogram <- function(wave){ 56 | len <- 256; shi <- len/2; 57 | tmp <- stft.half(wave, len,shi); 58 | image(1:length(tmp[,1])*shi/8000, 1:length(tmp[1,])/shi*4000,-powscale(tmp),col=rbcol,#mncol,#rbcol, 59 | xlab = "Time [s]", ylab="Frequency [Hz]"); #サンプリングが8000を想定 60 | } 61 | 62 | -------------------------------------------------------------------------------- /twostageHPSS_scripts/R/experiment_2.R: -------------------------------------------------------------------------------- 1 | # Execute after experiment_1.R 2 | 3 | PASS = 0 # true or false 4 | 5 | if(1){ 6 | # plot 1 7 | postscript(file="NSDR_alone_boxplot.eps", 8 | horiz=F, 9 | height=10, 10 | width=8, 11 | pointsize=20, 12 | family="Times") 13 | 14 | par(mai=c(1.5,1.5,0.5,0.5),omi=c(0,0,0,0)) 15 | boxplot(t(NSDR_alone[5:1,]), 16 | xlab="input SNR [dB]", 17 | ylab="NSDR [dB]", 18 | names=-2:2*5) 19 | dev.off(); 20 | 21 | # plot 2 22 | postscript(file="NSDR_HPF_boxplot.eps", 23 | horiz=F, 24 | height=10, 25 | width=8, 26 | pointsize=20, 27 | family="Times") 28 | par(mai=c(1.5,1.5,0.5,0.5),omi=c(0,0,0,0)) 29 | boxplot(t(NSDR_HPF[5:1,]), 30 | xlab="input SNR [dB]", 31 | ylab="NSDR [dB]", 32 | names=-2:2*5) 33 | dev.off(); 34 | } 35 | 36 | 37 | # Measure the length of each song 38 | if(!PASS){ 39 | weight <- c(0); 40 | i <- 1; 41 | for(file in fs1){ 42 | tmp <- readWave(sprintf("./MIR-1K_for_MIREX/Wavfile/%s",file)); 43 | weight[i] <- length(tmp@left); 44 | i <- i + 1; 45 | } 46 | } 47 | 48 | # GNSDR 49 | GNSDR <- function(NSDR, weight){ 50 | return(sum(NSDR * weight) / sum(weight)) 51 | } 52 | 53 | ours1 <- c(GNSDR(NSDR_alone[4,], weight), 54 | GNSDR(NSDR_alone[3,], weight), 55 | GNSDR(NSDR_alone[2,], weight)) 56 | ours2 <- c(GNSDR(NSDR_HPF[4,], weight), 57 | GNSDR(NSDR_HPF[3,], weight), 58 | GNSDR(NSDR_HPF[2,], weight)) 59 | 60 | # GNSDR of the existing methods. The values are read from the papers. 61 | hsu <- c(-0.5, 0.9, 0.2) 62 | ozerov <- c(0.52, -0.7, -3.2) 63 | li <- c(-1.2, 0.3, 0) 64 | rafii <- c(0.52, 1.11, 1.10) 65 | 66 | dB <- c(-5, 0, 5) 67 | 68 | # Plot 69 | if(1){ 70 | x <- matrix(c(ours2, 71 | ozerov, 72 | li, 73 | hsu, 74 | rafii),3) 75 | 76 | postscript(file="compare.eps", 77 | horiz=F, 78 | onefile=F, 79 | height=10, 80 | width=8, 81 | pointsize=20, 82 | family="Times") 83 | 84 | par(mai=c(1.5,1.5,0.5,0.5),omi=c(0,0,0,0)) 85 | 86 | matplot(dB, x, 87 | type = "o", col = 1, 88 | xlim=c(-6,6), 89 | xaxp = c(-5, 5, 2), 90 | ylim = c(-4, 5), 91 | yaxp = c(-4, 5, 9), 92 | xlab = "Input SNR [dB]", 93 | ylab = "GNSDR [dB]", 94 | pch = c(1,2,3,5,8)) 95 | 96 | legend(-5.7, -1.7, 97 | c("Proposed Method", 98 | "Ozerov [3]", 99 | "Li [4]", 100 | "Hsu [5]", 101 | "Rafii [6]"), pch= c(1,2,3,5,8), pt.bg="white", lty=0, col = "black") 102 | 103 | dev.off() 104 | } 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/slideBlock.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SLIDE_BLOCK_HEADER 2 | #define SLIDE_BLOCK_HEADER 3 | 4 | #include 5 | #include 6 | 7 | template 8 | class SlideBlock{ 9 | public: 10 | SlideBlock(int t, int k); 11 | ~SlideBlock(); 12 | 13 | // access to (t,k) 14 | T at(int t, int k); 15 | T* operator[](int t); 16 | 17 | // push and pop 18 | void push(T *in); 19 | void push(std::vector in); 20 | void pop(T *out); 21 | std::vector pop(); 22 | 23 | protected: 24 | int n_time; 25 | int n_freq; 26 | T* data; 27 | 28 | private: 29 | int current_point; 30 | T** data_alias; 31 | }; 32 | 33 | template 34 | SlideBlock::SlideBlock(int n, int k) 35 | :n_time(n), 36 | n_freq(k), 37 | current_point(0) 38 | { 39 | data = new T[n * k]; 40 | data_alias = new T*[n]; 41 | for(int i = 0; i != n; i++){ 42 | data_alias[i] = &(data[i * k]); 43 | } 44 | 45 | for(int i = 0; i < n * k; i++){ 46 | data[i] = 0; 47 | } 48 | } 49 | 50 | template 51 | SlideBlock::~SlideBlock(){ 52 | delete[] data; 53 | delete[] data_alias; 54 | } 55 | 56 | template 57 | T SlideBlock::at(int t, int k){ 58 | t = (t - current_point); 59 | if(t < 0){ 60 | t = t + n_time; 61 | } 62 | if(0 <= t < n_time && 0 <= k < n_freq){ 63 | return data_alias[t][k]; 64 | }else{ 65 | printf("Error at SlideBlock.hpp\nToo large index: time index: %d and frequency index %d", t, k); 66 | exit(1); 67 | } 68 | } 69 | 70 | template 71 | T* SlideBlock::operator[](int t){ 72 | t += current_point; 73 | if(t >= n_time){ 74 | t -= n_time; 75 | } 76 | return data_alias[t]; 77 | } 78 | 79 | template 80 | void SlideBlock::push(T* in){ 81 | for(int i = 0; i != n_freq; i++) 82 | data_alias[current_point][i] = in[i]; 83 | current_point++; 84 | if(current_point == n_time) 85 | current_point = 0; 86 | } 87 | template 88 | void SlideBlock::push(std::vector in){ 89 | if(in.size() != n_freq){ 90 | printf("Error at SlideBlock.hpp, push(std::vector): size of std::vector is invalid.\n"); 91 | exit(1); 92 | } 93 | for(int i = 0; i != n_freq; i++) 94 | data_alias[current_point][i] = in[i]; 95 | current_point++; 96 | if(current_point == n_time) 97 | current_point = 0; 98 | } 99 | 100 | template 101 | void SlideBlock::pop(T* out){ 102 | for(int i = 0; i != n_freq; i++) 103 | out[i] = data_alias[current_point][i]; 104 | } 105 | 106 | template 107 | std::vector SlideBlock::pop(){ 108 | std::vector &out; 109 | out = new std::vector(n_freq); 110 | for(int i = 0; i != n_freq; i++) 111 | (*out)[i] = data_alias[current_point]; 112 | return out; 113 | } 114 | 115 | #endif 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sliding HPSS 2 | ============ 3 | 4 | Coded by : Hideyuki Tachibana 5 | 6 | 7 | What's this? 8 | ------------ 9 | This is an example of the implementation of "sliding HPSS" described in the following paper. 10 | 11 | * N. Ono, K. Miyamoto, H. Kameoka, S. Sagayama "A real-time equalizer of harmonic and percussive components in music signals" in Proc. ISMIR 2008. 12 | 13 | This program is coded for following paper [(IEEE Xplore)](https://doi.org/10.1109/TASLP.2013.2287052) on singing voice enhancement, 14 | in which it is applied twice with different parameter sets. 15 | ```bibtex 16 | @article{tachibana2014singing, 17 | author={Hideuyki Tachibana and Nobutaka Ono and Shigeki Sagayama}, 18 | journal={IEEE/ACM Transactions on Audio, Speech, and Language Processing}, 19 | title={Singing Voice Enhancement in Monaural Music Signals Based on 20 | Two-stage Harmonic/Percussive Sound Separation on Multiple Resolution Spectrograms}, 21 | year={2014}, 22 | volume={22}, 23 | number={1}, 24 | pages={228-237} 25 | } 26 | ``` 27 | See also the following conferene paper [(IEEE Xplore)](https://doi.org/10.1109/ICASSP.2010.5495764). 28 | ```bibtex, 29 | @inproceedings{tachibana2010melody, 30 | author={Hideyuki Tachibana and Tatsuma Ono and Nobutaka Ono and Shigeki Sagayama}, 31 | booktitle={2010 IEEE International Conference on Acoustics, Speech and Signal Processing}, 32 | title={Melody line estimation in homophonic music audio signals 33 | based on temporal-variability of melodic source}, 34 | year={2010}, 35 | pages={425-428} 36 | } 37 | ``` 38 | How to use (on UNIX like system.) 39 | --------------------------------- 40 | 41 | ### Build 42 | 43 | Download the codes as follows. 44 | 45 | cd your_working_directory 46 | git clone https://github.com/tachi-hi/slidingHPSS 47 | 48 | Install `FFTW3` (`libfftw3`) in your system. If you are an Ubuntu user, 49 | 50 | apt-get install libfftw3-dev 51 | 52 | Then type the follwoing commands to build the code and execute the obtained binary. 53 | 54 | bash setup.sh 55 | ./bin/slidingHPSS -h 56 | 57 | then usage massage will be displayed. 58 | 59 | ### Preprocessing: Stereo 44.1kHz MP3 -> Mono 16kHz WAV 60 | 61 | `YourMP3file.mp3` is converted to a suitable format by following commands. 62 | 63 | mpg123 -w wavefile_tmp.wav yourMP3file.mp3 64 | sox wavfile_tmp.wav -r 16000 -c 1 input.wav 65 | rm wavfile_tmp.wav 66 | 67 | ### Singing Voice Enhancement 68 | 69 | Just run the script file `twostageHPSSscripts/twostageHPSS.sh`. The file named `input.wav` in the working directory will be separated into three files named `_H.wav`, `_P.wav`, and `_V.wav`. 70 | 71 | ### Singing Voice Suppression 72 | 73 | You can similarly obtain a "karoake" signal just by mixing the two files `_H.wav` and `_P.wav` as follows. 74 | 75 | sox -m _H.wav _P.wav _karaoke.wav 76 | 77 | See also [euterpe](https://github.com/tachi-hi/euterpe), an automatic audio-to-audio karaoke system. 78 | 79 | ## License 80 | Free 81 | 82 | ### Academic Use 83 | Please cite one of the papers above. 84 | 85 | ## Links 86 | 87 | ### Other implementations of HPSS 88 | 89 | + Our group 90 | + [(non-sliding) HPSS](https://github.com/tachi-hi/HPSS) 91 | + [vocal suppression based on multi-stage HPSS ("euterpe")](https://github.com/tachi-hi/euterpe) 92 | + HPSS with GUI (http://hil.t.u-tokyo.ac.jp/software/) ... [expired link] 93 | + Others 94 | + [librosa](http://librosa.github.io/librosa/): This audio library for Python contains a variant of HPSS. 95 | 96 | ### Data 97 | + [MIR-1K](https://sites.google.com/site/unvoicedsoundseparation/mir-1k) 98 | 99 | -------------------------------------------------------------------------------- /src/slidingHPSS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include"waviostream.hpp" 9 | #include"HPSS.hpp" 10 | 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | 16 | int main(int argc, char **argv){ 17 | std::string input_file_name(""); 18 | std::string H_file_name("_H.wav"); 19 | std::string P_file_name("_P.wav"); 20 | int frame(512); 21 | int block_size(100); 22 | double sigmaH(0.30); double wh = 11.; 23 | double sigmaP(0.30); double wp = 11.; 24 | 25 | while (1) { 26 | int option_index = 0; 27 | static struct option long_options[] = { 28 | {"help", 0, 0, 'h'}, 29 | {"info", 0, 0, 'h'}, 30 | {"input", 1, 0, 'i'}, 31 | {"Hout", 1, 0, 'H'}, 32 | {"Pout", 1, 0, 'P'}, 33 | {"frame", 1, 0, 'f'}, 34 | {"block", 1, 0, 'b'}, 35 | {"sigmaH", 1, 0, 'Q'}, 36 | {"sigmaP", 1, 0, 'W'}, 37 | {0, 0, 0, 0} 38 | }; 39 | int c = getopt_long(argc, argv, "hi:H:P:f:b:Q:W:", 40 | long_options, &option_index); 41 | if (c == -1) break; 42 | 43 | switch (c) { 44 | case'h':{ 45 | cerr << "Harmonic/percussive sound separation" << endl; 46 | cerr << "Usage:" << argv[0] << " -i[input file name] [and other options you need]" << endl; 47 | cerr << "Options:" << endl; 48 | cerr << " --help or --info [-h]\t Display this document." << endl; 49 | cerr << " --input [-i] \t Input file name.\n\t\t\t The file should be monaural PCM .wav file" << endl; 50 | cerr << " --Hout [-H] \t Output H name, default: _H.wav" << endl; 51 | cerr << " --Pout [-P] \t Output P name, default: _P.wav" << endl; 52 | cerr << " --frame [-f] \t Frame length of the STFT, default: 512[sample]" << endl; 53 | cerr << " --block [-b] \t Block size of the HPSS, default: 30" << endl; 54 | cerr << " --sigmaH [-Q] \t H weighting constant of the HPSS, default: 0.3" << endl; 55 | cerr << " --sigmaP [-W] \t P weighting constant of the HPSS, default: 0.3" << endl; 56 | cerr << "(c) Hideyuki Tachibana 2008--2011, 2014" << endl; 57 | cerr << "contact: http://github.com/tachi-hi" << endl; 58 | exit(1); 59 | } 60 | case'i':{input_file_name = optarg; break;} 61 | case'H':{H_file_name = optarg;break;} 62 | case'P':{P_file_name = optarg;break;} 63 | case'f':{frame = atoi(optarg);break;} 64 | case'b':{block_size = atoi(optarg);break;} 65 | case'Q':{sigmaH = atof(optarg); break;} 66 | case'W':{sigmaP = atof(optarg); break;} 67 | default: 68 | cerr << "?? getopt returned character code 0" << c << endl; 69 | } 70 | wh = 1.0/sigmaH/sigmaH; 71 | wp = 1.0/sigmaP/sigmaP; 72 | } 73 | /*********************************************************************************************************/ 74 | 75 | wavistream *input; 76 | wavostream *H, *P; 77 | input = new wavistream(input_file_name.c_str(), frame); 78 | int n_channel = input->header.n_channel; 79 | H = new wavostream(H_file_name.c_str(), n_channel, frame/2); 80 | P = new wavostream(P_file_name.c_str(), n_channel, frame/2); 81 | P->header = H->header = input->header; 82 | 83 | HPSS *hpss = new HPSS[n_channel]; 84 | for(int i = 0; i < n_channel; i++){ 85 | hpss[i].init(block_size, frame, frame/2, wh, wp); 86 | } 87 | const int iteration_one_step = 1; 88 | 89 | std::vector > frame_in, frame_H, frame_P; 90 | std::vector > old_H, old_P; 91 | for(int i = 0; i < n_channel; i++){ 92 | std::vector frame_in_tmp(frame); 93 | frame_in.push_back(frame_in_tmp); 94 | frame_H.push_back(frame_in_tmp); 95 | frame_P.push_back(frame_in_tmp); 96 | std::vector oldH_tmp(frame/2); 97 | old_H.push_back(oldH_tmp); 98 | old_P.push_back(oldH_tmp); 99 | } 100 | 101 | // initial frame 102 | input->read(frame/2); 103 | for(int i = 0; i < block_size - 1; i++){ 104 | input->read(frame/2); 105 | for(int ch = 0; ch < n_channel; ch++){ 106 | input->copy(&(frame_in[ch][0]), ch, frame); 107 | hpss[ch].push_new_data(&(frame_in[ch][0])); 108 | hpss[ch].update(iteration_one_step); 109 | } 110 | } 111 | 112 | while( !hpss[0].eof()){ 113 | input->read(frame/2); 114 | for(int ch = 0; ch < n_channel; ch++){ 115 | input->copy(&(frame_in[ch][0]), 0, frame); 116 | hpss[ch].push_new_data(&(frame_in[ch][0])); 117 | hpss[ch].update(iteration_one_step); 118 | 119 | if( input->eof() ) 120 | hpss[ch].flag_on(); 121 | 122 | // pop 123 | hpss[ch].pop(&(frame_H[ch][0]), &(frame_P[ch][0])); 124 | for(int i = 0; i < frame/2; i++){ 125 | frame_H[ch][i] += old_H[ch][i]; 126 | frame_P[ch][i] += old_P[ch][i]; 127 | old_H[ch][i] = frame_H[ch][frame/2 + i]; 128 | old_P[ch][i] = frame_P[ch][frame/2 + i]; 129 | } 130 | H->set(&(frame_H[ch][0]), ch, frame/2); 131 | P->set(&(frame_P[ch][0]), ch, frame/2); 132 | } 133 | 134 | // save 135 | H->write(frame/2); 136 | P->write(frame/2); 137 | } 138 | delete input; 139 | delete H; 140 | delete P; 141 | delete[] hpss; 142 | 143 | return 0; 144 | } 145 | 146 | 147 | -------------------------------------------------------------------------------- /src/HPSS.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _HPSS_HPP_ 3 | #define _HPSS_HPP_ 4 | 5 | #include 6 | #include 7 | 8 | //#include 9 | 10 | #include"slideBlock.hpp" 11 | #include"myfft.h" 12 | 13 | class HPSS{ 14 | public: 15 | HPSS(){}; 16 | void init(int, int, int, double, double); 17 | ~HPSS(); 18 | 19 | void push_new_data(double*); 20 | void update(int); 21 | void pop(double*, double*); 22 | 23 | bool eof(){return push_pop_count < 0 ? true : false;} 24 | void flag_on(){count_flag = true;} 25 | bool filled(){return push_pop_count >= block_size ? true : false;} 26 | 27 | private: 28 | int block_size; 29 | int frame_length; 30 | int frame_shift; 31 | double w_h; 32 | double w_p; 33 | 34 | int push_pop_count; 35 | bool count_flag; 36 | 37 | SlideBlock *W; 38 | SlideBlock *H, *H_buffer; 39 | SlideBlock *P, *P_buffer; 40 | SlideBlock *maskH, *maskH_buf; 41 | SlideBlock *maskP, *maskP_buf; 42 | SlideBlock *phaseSpec; 43 | 44 | double *amplitude, *phase, *mask_def; 45 | std::complex *fft_ed, *Hcompspec, *Pcompspec; 46 | 47 | FFT_forward *fft_forward; 48 | FFT_backward *fft_backward_H, *fft_backward_P; 49 | static std::complex J; // sqrt(-1) 50 | 51 | }; 52 | std::complex HPSS::J (0.0, 1.0); 53 | 54 | //////////////////////////////////////////////////////////////////////////////////// 55 | void HPSS::init(int a, int b, int c, double d, double e) 56 | { 57 | block_size = a; 58 | frame_length = b; 59 | frame_shift = c; 60 | push_pop_count = 0; 61 | count_flag = false; 62 | w_h = d; 63 | w_p = e; 64 | 65 | W = new SlideBlock(block_size, frame_length/2 + 1); 66 | H = new SlideBlock(block_size, frame_length/2 + 1); 67 | P = new SlideBlock(block_size, frame_length/2 + 1); 68 | H_buffer = new SlideBlock(block_size, frame_length/2 + 1); 69 | P_buffer = new SlideBlock(block_size, frame_length/2 + 1); 70 | phaseSpec = new SlideBlock(block_size, frame_length/2 + 1); 71 | maskH = new SlideBlock(block_size, frame_length/2 + 1); 72 | maskP = new SlideBlock(block_size, frame_length/2 + 1); 73 | maskH_buf = new SlideBlock(block_size, frame_length/2 + 1); 74 | maskP_buf = new SlideBlock(block_size, frame_length/2 + 1); 75 | mask_def = new double[frame_length/2 + 1]; 76 | 77 | amplitude = new double[frame_length/2 + 1]; 78 | phase = new double[frame_length/2 + 1]; 79 | fft_ed = new std::complex[frame_length/2 + 1]; 80 | Hcompspec = new std::complex[frame_length/2 + 1]; 81 | Pcompspec = new std::complex[frame_length/2 + 1]; 82 | 83 | fft_forward = new FFT_forward(frame_length); 84 | fft_backward_H = new FFT_backward(frame_length); 85 | fft_backward_P = new FFT_backward(frame_length); 86 | } 87 | 88 | 89 | HPSS::~HPSS(){ 90 | delete W; 91 | delete H; 92 | delete P; 93 | delete H_buffer; 94 | delete P_buffer; 95 | delete phaseSpec; 96 | 97 | delete maskH; 98 | delete maskP; 99 | delete maskH_buf; 100 | delete maskP_buf; 101 | delete []mask_def; 102 | 103 | delete []amplitude; 104 | delete []phase; 105 | delete []fft_ed; 106 | delete []Hcompspec; 107 | delete []Pcompspec; 108 | 109 | delete fft_forward; 110 | delete fft_backward_H; 111 | delete fft_backward_P; 112 | } 113 | 114 | // push new data 115 | void HPSS::push_new_data(double *x){ 116 | if(count_flag == false)push_pop_count++; 117 | for(int i = 0 ; i < frame_length; i++){ 118 | fft_forward->in[i] = x[i] * sin(M_PI * i/ frame_length); 119 | } 120 | fft_forward->exec(); 121 | for(int i = 0; i < frame_length/2 + 1; i++){ 122 | amplitude[i] = abs(fft_forward->out[i]); 123 | phase[i] = arg(fft_forward->out[i]); 124 | mask_def[i] = 0.5; 125 | } 126 | 127 | W->push(&(amplitude[0])); 128 | H->push(&(amplitude[0])); 129 | P->push(&(amplitude[0])); 130 | phaseSpec->push(&(phase[0])); 131 | maskH->push(&(mask_def[0])); 132 | maskP->push(&(mask_def[0])); 133 | } 134 | 135 | // HPSS updating formula 136 | inline void HPSS::update(int n){ 137 | static double H_A = 2 * w_h + 2; 138 | static double P_A = 2 * w_p + 2; 139 | 140 | // #pragma omp parallel 141 | for(int iter = 0; iter < n; iter++){ 142 | // #pragma omp for schedule(guided) 143 | for(int t = 1; t < block_size-1; t++){ 144 | for(int k = 1; k < frame_length/2; k++){ 145 | double w = pow((*W)[t][k],2); 146 | 147 | double H_B = w_h * ((*H)[t+1][k] + (*H)[t-1][k]); 148 | double H_C = 2 * (*maskH)[t][k] * w; 149 | (*H_buffer)[t][k] = (H_B + sqrt(H_B*H_B + 4 * H_A * H_C))/(2*H_A); 150 | 151 | double P_B = w_p * ((*P)[t][k+1] + (*P)[t][k-1]); 152 | double P_C = 2 * (*maskP)[t][k] * w; 153 | (*P_buffer)[t][k] = (P_B + sqrt(P_B*P_B + 4 * P_A * P_C))/(2*P_A); 154 | } 155 | } 156 | // #pragma omp for schedule(guided) 157 | for(int t = 1; t < block_size-1; t++){ 158 | for(int k = 1; k < frame_length/2; k++){ 159 | (*H)[t][k] = (*H_buffer)[t][k]; 160 | (*P)[t][k] = (*P_buffer)[t][k]; 161 | double tmp = pow((*H)[t][k],2) 162 | + pow((*P)[t][k],2); 163 | if(tmp > 0.0){ 164 | (*maskH)[t][k] = pow((*H)[t][k],2) / tmp; 165 | (*maskP)[t][k] = pow((*P)[t][k],2) / tmp; 166 | }else{ 167 | (*maskH)[t][k] = 0.5; 168 | (*maskP)[t][k] = 0.5; 169 | } 170 | } 171 | } 172 | } 173 | } 174 | 175 | 176 | //pop 177 | void HPSS::pop(double *Hout, double *Pout){ 178 | push_pop_count--; 179 | H->pop(&(Hout[0])); // trash 180 | P->pop(&(Pout[0])); // trash 181 | W->pop(&(amplitude[0])); // used 182 | phaseSpec->pop(&(phase[0]));// used 183 | maskH->pop(&(Hout[0])); // used 184 | maskP->pop(&(Pout[0])); // usedB 185 | 186 | // amplitude 187 | for(int j = 0; j < frame_length/2 + 1; j++){ 188 | Hout[j] = amplitude[j] * Hout[j]; // Hout in rhs means time-frequency mask 189 | Pout[j] = amplitude[j] * Pout[j]; 190 | } 191 | 192 | // phase 193 | for(int j = 0; j < frame_length/2 + 1; j++){ 194 | std::complex isou(cos(phase[j]),sin(phase[j])); 195 | std::complex conj(cos(phase[j]),-sin(phase[j])); 196 | Hcompspec[j] = Hout[j] * isou; 197 | Pcompspec[j] = Pout[j] * isou; 198 | } 199 | 200 | // inverse STFT 201 | for(int i = 0; i < frame_length/2 + 1; i++){ 202 | fft_backward_H->in[i] = Hcompspec[i]; 203 | fft_backward_P->in[i] = Pcompspec[i]; 204 | } 205 | fft_backward_H->exec(); 206 | fft_backward_P->exec(); 207 | for(int i = 0; i < frame_length; i++){ 208 | Hout[i] = fft_backward_H->out[i] * sin(M_PI * i / frame_length); 209 | Pout[i] = fft_backward_P->out[i] * sin(M_PI * i / frame_length); 210 | } 211 | } 212 | 213 | #endif 214 | 215 | -------------------------------------------------------------------------------- /twostageHPSS_scripts/R/experiment_1.R: -------------------------------------------------------------------------------- 1 | # Large Scale Experiment 2 | 3 | source("./Rlib/mylib.R"); 4 | 5 | HPSS_done <- 0; # 0: not done, 1: done 6 | 7 | len <- 512; 8 | shi <- 256; 9 | 10 | # volume is not adjusted, and signal and noise are known 11 | SNR1 <- function(sig, noise){ 12 | pow_sig <- sum(sig**2); 13 | pow_noise <- sum(noise**2); 14 | snr <- 10 * log(pow_sig/pow_noise)/log(10); 15 | return(snr); 16 | } 17 | 18 | # Volume is adjusted 19 | SNR2 <- function(mixed, sig){ 20 | # x(t) = a * s(t) + n(t), multiply s, expectation value, assuming that sum(sn)=0 21 | a <- sum(1.0 * mixed * sig)/sum(1.0 * sig**2); 22 | noise <- mixed - a * sig; 23 | snr <- SNR1(a * sig, noise); 24 | return(snr); 25 | } 26 | 27 | SDR <- function(x, y){ 28 | x <- x / 1000; 29 | y <- y / 1000; 30 | s <- sum(x * y)**2; 31 | a <- s / (sum(x**2) * sum(y**2) - s) 32 | sdr <- 10 * log(a) / log(10); 33 | return (sdr); 34 | } 35 | 36 | # Normalized SDR 37 | NSDR <- function(n,m,x){ 38 | return(SDR(n,m) - SDR(x,m)); 39 | } 40 | 41 | # Mix signal and noise in an arbitrary SNR. 42 | mix <- function(signal, noise, db){ 43 | return (signal + noise * exp(-db/20*log(10)) ) 44 | } 45 | 46 | ###################################################################### 47 | HPSS <- function(data, frame, q, w){ 48 | # concatenate noise both side of the signal 49 | range <- frame + 1:length(data); 50 | data <- c(runif(1:frame)* 0.01, data, runif(1:frame)* 0.01); 51 | out <- Wave(data, samp.rate=16000, bit=16); 52 | writeWave(out,"./tmp/_input.wav"); 53 | 54 | cmdline <- paste("./slidingHPSS --input ./tmp/_input.wav --block 100 --frame ", frame, 55 | " --Hout ./tmp/_H.wav --Pout ./tmp/_P.wav -Q ", q , " -W ", w, sep=""); 56 | system(cmdline); 57 | print(cmdline); 58 | 59 | tmp <- readWave("./tmp/_H.wav"); H <- tmp@left[range]; 60 | tmp <- readWave("./tmp/_P.wav"); P <- tmp@left[range]; 61 | return(list(H=H, P=P)); 62 | } 63 | 64 | # Multi-stage HPSS 65 | MSHPSS <- function(data, frame1, frame2){ 66 | hp1 <- HPSS(data, frame1, 0.3, 0.3); 67 | H1 <- hp1$H; 68 | P1 <- hp1$P; 69 | 70 | hp2 <- HPSS(H1, frame2, 0.3, 0.3); 71 | H2 <- hp2$H; 72 | P2 <- hp2$P; 73 | 74 | # High Pass Filter 75 | tmp <- stft.half(c(runif(1:512), P2, runif(1:512)),512, 256); 76 | tmp[,16000/512*(1:257-1) < 110] <- 0; 77 | Filtered <- istft.half(tmp, 256)[512+ 1:length(P2)] 78 | 79 | return(list(V=P2, F=Filtered, NV=P1+H2)); 80 | } 81 | 82 | ####################################################################### 83 | 84 | # Protocol: 85 | # List files 86 | # Mix Left and Right channels. 87 | # Concatenate short noise both side of the signal 88 | # Apply HPSS 89 | # W-V is the vocal off 90 | # SNR 91 | # Statistics 92 | # (frame-wise), file-wise, (singer-wise) 93 | 94 | fs1 <- list.files("./MIR-1K_for_MIREX/Wavfile/") 95 | 96 | NSDR_alone <- matrix(0, 5, length(fs1)) 97 | NSDR_HPF <- matrix(0, 5, length(fs1)) 98 | 99 | i = 0; 100 | for(file in fs1){ 101 | i <- i + 1; 102 | print(sprintf("Files: %d / %d", i, length(fs1))); 103 | 104 | print(file); 105 | tmp <- readWave(sprintf("./MIR-1K_for_MIREX/Wavfile/%s",file)); 106 | accomp <- tmp@left; 107 | singer <- tmp@right; 108 | input_p10 <- accomp + singer * 10**0.5; # 10dB 109 | input_p5 <- accomp + singer * 10**0.25; # 5dB 110 | input_0 <- accomp + singer; # 0dB 111 | input_m5 <- accomp + singer / 10**0.25; # -5dB 112 | input_m10 <- accomp + singer / 10**0.5; #-10dB 113 | 114 | print(sprintf("SNR (singer to accompaniment) = %f [dB]", SNR1(singer,accomp))); 115 | print(sprintf("SNR (singer to accompaniment) = %f [dB]", SNR2(input_0,singer))); 116 | print(sprintf("SNR (input_m5 to singer) = %f [dB]", SNR2(input_m5,singer))); 117 | 118 | out_p10 <- normalize(Wave(input_p10, samp.rate=16000, bit=16), unit="16") * 0.1; 119 | out_p5 <- normalize(Wave(input_p5, samp.rate=16000, bit=16), unit="16") * 0.1; 120 | out_0 <- normalize(Wave(input_0, samp.rate=16000, bit=16), unit="16") * 0.1; 121 | out_m5 <- normalize(Wave(input_m5, samp.rate=16000, bit=16), unit="16") * 0.1; 122 | out_m10 <- normalize(Wave(input_m10, samp.rate=16000, bit=16), unit="16") * 0.1; 123 | 124 | writeWave(out_p10 * 9, sprintf("./tmp/p10_%s", file)); 125 | writeWave(out_p5 * 9, sprintf("./tmp/p5_%s", file)); 126 | writeWave(out_0 * 9, sprintf("./tmp/0_%s", file)); 127 | writeWave(out_m5 * 9, sprintf("./tmp/m5_%s", file)); 128 | writeWave(out_m10 * 9, sprintf("./tmp/m10_%s", file)); 129 | 130 | # apply HPSS 131 | if(!HPSS_done){ 132 | short <- 128; 133 | long <- 8192; 134 | 135 | VNV_p10 <- MSHPSS(out_p10@left, short,long); 136 | VNV_p5 <- MSHPSS(out_p5@left, short,long); 137 | VNV_0 <- MSHPSS(out_0@left, short,long); 138 | VNV_m5 <- MSHPSS(out_m5@left, short,long); 139 | VNV_m10 <- MSHPSS(out_m10@left, short,long); 140 | 141 | writeWave(normalize(Wave(VNV_p10$V, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Vp10_%s", file)); 142 | writeWave(normalize(Wave(VNV_p5$V, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Vp5_%s", file)); 143 | writeWave(normalize(Wave(VNV_0$V, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/V0_%s", file)); 144 | writeWave(normalize(Wave(VNV_m5$V, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Vm5_%s", file)); 145 | writeWave(normalize(Wave(VNV_m10$V, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Vm10_%s", file)); 146 | 147 | writeWave(normalize(Wave(VNV_p10$F, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Fp10_%s", file)); 148 | writeWave(normalize(Wave(VNV_p5$F, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Fp5_%s", file)); 149 | writeWave(normalize(Wave(VNV_0$F, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/F0_%s", file)); 150 | writeWave(normalize(Wave(VNV_m5$F, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Fm5_%s", file)); 151 | writeWave(normalize(Wave(VNV_m10$F, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/Fm10_%s", file)); 152 | 153 | writeWave(normalize(Wave(VNV_p10$NV, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/NVp10_%s", file)); 154 | writeWave(normalize(Wave(VNV_p5$NV, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/NVp5_%s", file)); 155 | writeWave(normalize(Wave(VNV_0$NV, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/NV0_%s", file)); 156 | writeWave(normalize(Wave(VNV_m5$NV, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/NVm5_%s", file)); 157 | writeWave(normalize(Wave(VNV_m10$NV, samp.rate=16000, bit=16),unit="16") * 0.9, sprintf("./tmp/NVm10_%s", file)); 158 | 159 | }else{ 160 | VNV_p10$V <- readWave(sprintf("./tmp/Vp10_%s", file))@left; 161 | VNV_p5$V <- readWave(sprintf("./tmp/Vp5_%s", file))@left; 162 | VNV_0$V <- readWave(sprintf("./tmp/V0_%s", file))@left; 163 | VNV_m5$V <- readWave(sprintf("./tmp/Vm5_%s", file))@left; 164 | VNV_m10$V <- readWave(sprintf("./tmp/Vm10_%s", file))@left; 165 | VNV_p10$F <- readWave(sprintf("./tmp/Fp10_%s", file))@left; 166 | VNV_p5$F <- readWave(sprintf("./tmp/Fp5_%s", file))@left; 167 | VNV_0$F <- readWave(sprintf("./tmp/F0_%s", file))@left; 168 | VNV_m5$F <- readWave(sprintf("./tmp/Fm5_%s", file))@left; 169 | VNV_m10$F <- readWave(sprintf("./tmp/Fm10_%s", file))@left; 170 | VNV_p10$NV <- readWave(sprintf("./tmp/NVp10_%s", file))@left; 171 | VNV_p5$NV <- readWave(sprintf("./tmp/NVp5_%s", file))@left; 172 | VNV_0$NV <- readWave(sprintf("./tmp/NV0_%s", file))@left; 173 | VNV_m5$NV <- readWave(sprintf("./tmp/NVm5_%s", file))@left; 174 | VNV_m10$NV <- readWave(sprintf("./tmp/NVm10_%s", file))@left; 175 | } 176 | 177 | # SDR 178 | NSDR_alone[1,i] = NSDR(VNV_p10$V, singer, out_p10@left) 179 | NSDR_alone[2,i] = NSDR(VNV_p5$V, singer, out_p5@left) 180 | NSDR_alone[3,i] = NSDR(VNV_0$V, singer, out_0@left) 181 | NSDR_alone[4,i] = NSDR(VNV_m5$V, singer, out_m5@left) 182 | NSDR_alone[5,i] = NSDR(VNV_m10$V, singer, out_m10@left) 183 | print(sprintf("SDR (+10dB) = %f [dB]",NSDR_alone[1,i])); 184 | print(sprintf("SDR (+5dB) = %f [dB]",NSDR_alone[2,i])); 185 | print(sprintf("SDR ( 0dB) = %f [dB]",NSDR_alone[3,i])); 186 | print(sprintf("SDR (-5dB) = %f [dB]",NSDR_alone[4,i])); 187 | print(sprintf("SDR (-10dB) = %f [dB]",NSDR_alone[5,i])); 188 | 189 | NSDR_HPF[1,i] = NSDR(VNV_p10$F, singer, out_p10@left) 190 | NSDR_HPF[2,i] = NSDR(VNV_p5$F, singer, out_p5@left) 191 | NSDR_HPF[3,i] = NSDR(VNV_0$F, singer, out_0@left) 192 | NSDR_HPF[4,i] = NSDR(VNV_m5$F, singer, out_m5@left) 193 | NSDR_HPF[5,i] = NSDR(VNV_m10$F, singer, out_m10@left) 194 | print(sprintf("SDR (+10dB) = %f [dB]",NSDR_HPF[1,i])); 195 | print(sprintf("SDR (+5dB) = %f [dB]",NSDR_HPF[2,i])); 196 | print(sprintf("SDR ( 0dB) = %f [dB]",NSDR_HPF[3,i])); 197 | print(sprintf("SDR (-5dB) = %f [dB]",NSDR_HPF[4,i])); 198 | print(sprintf("SDR (-10dB) = %f [dB]",NSDR_HPF[5,i])); 199 | 200 | } 201 | 202 | 203 | --------------------------------------------------------------------------------