├── LICENSE.txt ├── README.md ├── commandlist.txt ├── howtouse.md ├── src ├── act1.m ├── act2.m ├── act3.m ├── act4.m ├── act5.m ├── act6.m ├── check_toolbox.m ├── estimate_f0.m ├── extract_commands.m ├── freq2cent.m ├── generate_f0_contour.m ├── generate_pulsetrain_from_f0_contour.m ├── generate_signal_from_f0_contour.m └── plot_figure.m └── tusk_example.m /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------- */ 2 | /* TUSK: A framework for overviewing the performance of */ 3 | /* F0 estimators */ 4 | /* developed by M. Morise */ 5 | /* https://github.com/mmorise/tusk */ 6 | /* ----------------------------------------------------------------- */ 7 | /* */ 8 | /* Copyright (c) 2016 M. Morise */ 9 | /* */ 10 | /* All rights reserved. */ 11 | /* */ 12 | /* Redistribution and use in source and binary forms, with or */ 13 | /* without modification, are permitted provided that the following */ 14 | /* conditions are met: */ 15 | /* */ 16 | /* - Redistributions of source code must retain the above copyright */ 17 | /* notice, this list of conditions and the following disclaimer. */ 18 | /* - Redistributions in binary form must reproduce the above */ 19 | /* copyright notice, this list of conditions and the following */ 20 | /* disclaimer in the documentation and/or other materials provided */ 21 | /* with the distribution. */ 22 | /* - Neither the name of the M. Morise nor the names of its */ 23 | /* contributors may be used to endorse or promote products derived */ 24 | /* from this software without specific prior written permission. */ 25 | /* */ 26 | /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */ 27 | /* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */ 28 | /* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ 29 | /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 30 | /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS */ 31 | /* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */ 32 | /* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */ 33 | /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ 34 | /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 35 | /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */ 36 | /* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY */ 37 | /* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ 38 | /* POSSIBILITY OF SUCH DAMAGE. */ 39 | /* ----------------------------------------------------------------- */ 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TUSK: A framework for overviewing the performance of F0 estimators 2 | 3 | TUSK can measure the characteristics of Fundamental frequency (F0 or FO) estimators. 4 | Please see the concept of TUSK. 5 | 6 | [1] Masanori Morise and Hideki Kawahara, TUSK: A framework for overviewing the performance of F0 estimators, Proc. INTERSPEECH2016, pp. 1790-1794, 2016. 7 | 8 | ## Note 9 | TUSK does not disallow the conventional evaluation using electroglottography (EGG) signal. 10 | We reccomend that TUSK is used supplementarily to measure the characteristics. 11 | 12 | This source code is released under the modified-BSD license. 13 | There is no patent in all algorithms in TUSK. 14 | -------------------------------------------------------------------------------- /commandlist.txt: -------------------------------------------------------------------------------- 1 | 2 2 | 3 | DIO 4 | op.frame_period = 1; 5 | op.target_fs = fs; 6 | op.f0_floor = 40; 7 | op.f0_ceil = 1000; 8 | r = Dio(x, fs, op); 9 | f0 = r.f0; 10 | 11 | DIO+StoneMask 12 | f0 = StoneMask(x, fs, r.temporal_positions, r.f0); 13 | -------------------------------------------------------------------------------- /howtouse.md: -------------------------------------------------------------------------------- 1 | # How to use TUSK 2 | 3 | ## 0. Preparation 4 | The test script uses Dio() in WORLD. 5 | Please download WORLD (MATLAB version) from the following. 6 | http://ml.cs.yamanashi.ac.jp/world/english/index.html 7 | 8 | ## 1. usage 9 | 10 | Since the file "tusk_example.m" is the test script of TUSK, please see it. 11 | The file "commandlist.txt" is requied to set the conditions in 12 | F0 estimators (The number of estimators and options in each estimator). 13 | 14 | The format of commandlist.txt is follows: 15 | 16 | ``` 17 | 2 : Number of estimators for evaluation. 18 | 19 | DIO : Name used for plot_figure.m. 20 | op.frame_period = 1; : Options to fulfill the conditions for TUSK. 21 | op.target_fs = fs; : Sampling frequency (48 kHz). 22 | op.f0_floor = 40; : Floor used for searching F0. 23 | op.f0_ceil = 1000; : Ceil used for searching F0. 24 | r = Dio(x, fs, op); : F0 estimation on the basis of the conditions. 25 | f0 = r.f0; : Variable "f0" is used for evaluation. 26 | : Blank line is used to switch the estimator. 27 | DIO+StoneMask 28 | f0 = StoneMask(x, fs, r.temporal_positions, r.f0); 29 | ``` 30 | Note: Since the variables are not deleted, we can reuse them. 31 | Variables "x" and "fs" are defined in advance as input waveform and sampling frequency. 32 | You must not change them. 33 | 34 | ## 3. For F0 estimator developed on C (.exe in Windows OS) 35 | MATLAB has the function "system()" in Windows OS, and you can call F0 estimators developed on other languages such as C. 36 | This is an example of commandlist.txt with an F0 estimator (f0_estimation.exe in Windows OS). 37 | The format of this estimator is 38 | 39 | ``` 40 | > f0_estimation.exe input_name output_name 41 | ``` 42 | 43 | Conditions are set appropriately (you can also set them by arguments when calling it). 44 | The file "output_name" consists of a text that is F0 sequence (1 ms frame shift). 45 | Binary file can be used, but you must implement the loader. 46 | 47 | ``` 48 | TEST 49 | x = 0.8 * x / max(abs(x)); % Amplitude normalization 50 | % File output. 51 | filename = sprintf('test%d.wav', option); 52 | audiowrite(filename, x, fs, 'BitsPerSample', 24); 53 | % F0 estimation (please modify following area) 54 | command = sprintf('f0_estimation.exe %s output%d.txt', filename, option); 55 | system(command); 56 | filename = sprintf('output%d.txt', option); 57 | f0 = load(filename); 58 | % Delete temporaly files 59 | command = sprintf('del output%d.txt', option); 60 | system(command); 61 | command = sprintf('del test%d.wav', option); 62 | system(command); 63 | ``` 64 | Note: TUSK has a hidden variable "option". This is used for parallel processing, and you must not modify. 65 | -------------------------------------------------------------------------------- /src/act1.m: -------------------------------------------------------------------------------- 1 | function [result, method_list] = act1(filename_list, f0_list, parallel_flag) 2 | 3 | fs = 48000; 4 | [command_list, number_of_methods, method_list] =... 5 | extract_commands(filename_list); 6 | 7 | % Function loop_parallel() requires parallel computing toolbox. 8 | if parallel_flag == 1 && check_toolbox == 1 9 | result = loop_parallel(fs, f0_list, command_list, number_of_methods); 10 | else 11 | result = loop_normal(fs, f0_list, command_list, number_of_methods); 12 | end; 13 | 14 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15 | function result = loop_parallel(fs, f0_list, command_list, number_of_methods) 16 | 17 | result = zeros(length(f0_list), number_of_methods); 18 | 19 | parfor i = 1 : length(f0_list) 20 | basic_f0 = f0_list(i); 21 | 22 | f0_contour = generate_f0_contour(basic_f0, 0); 23 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 24 | 25 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 26 | result(i, :) = tmp(:)'; 27 | 28 | fprintf('ACT 1: %d cent\n', round(freq2cent(basic_f0))); 29 | end; 30 | 31 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 32 | function result = loop_normal(fs, f0_list, command_list, number_of_methods) 33 | 34 | result = zeros(length(f0_list), number_of_methods); 35 | 36 | for i = 1 : length(f0_list) 37 | basic_f0 = f0_list(i); 38 | 39 | f0_contour = generate_f0_contour(basic_f0, 0); 40 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 41 | 42 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 43 | result(i, :) = tmp(:)'; 44 | 45 | fprintf('ACT 1: %d cent\n', round(freq2cent(basic_f0))); 46 | end; 47 | -------------------------------------------------------------------------------- /src/act2.m: -------------------------------------------------------------------------------- 1 | function [result, method_list] = act2(filename_list, alpha_list, parallel_flag) 2 | 3 | fs = 48000; 4 | [command_list, number_of_methods, method_list] =... 5 | extract_commands(filename_list); 6 | 7 | % Function loop_parallel() requires parallel computing toolbox. 8 | if parallel_flag == 1 && check_toolbox == 1 9 | result = loop_parallel(fs, alpha_list, command_list, number_of_methods); 10 | else 11 | result = loop_normal(fs, alpha_list, command_list, number_of_methods); 12 | end; 13 | 14 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15 | function result =... 16 | loop_parallel(fs, alpha_list, command_list, number_of_methods) 17 | 18 | result = zeros(length(alpha_list), number_of_methods); 19 | basic_f0 = 440; 20 | 21 | parfor i = 1 : length(alpha_list) 22 | alpha = alpha_list(i); 23 | 24 | f0_contour = generate_f0_contour(basic_f0, alpha); 25 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 26 | 27 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 28 | result(i, :) = tmp(:)'; 29 | 30 | fprintf('ACT 2: %.1f\n', alpha); 31 | end; 32 | 33 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 | function result = loop_normal(fs, alpha_list, command_list, number_of_methods) 35 | 36 | result = zeros(length(alpha_list), number_of_methods); 37 | basic_f0 = 440; 38 | 39 | for i = 1 : length(alpha_list) 40 | alpha = alpha_list(i); 41 | 42 | f0_contour = generate_f0_contour(basic_f0, alpha); 43 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 44 | 45 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 46 | result(i, :) = tmp(:)'; 47 | 48 | fprintf('ACT 2: %.1f\n', alpha); 49 | end; 50 | -------------------------------------------------------------------------------- /src/act3.m: -------------------------------------------------------------------------------- 1 | function [result, method_list] = act3(filename_list, amp_list, parallel_flag) 2 | 3 | fs = 48000; 4 | [command_list, number_of_methods, method_list] =... 5 | extract_commands(filename_list); 6 | 7 | % Function loop_parallel() requires parallel computing toolbox. 8 | if parallel_flag == 1 && check_toolbox == 1 9 | result = loop_parallel(fs, amp_list, command_list, number_of_methods); 10 | else 11 | result = loop_normal(fs, amp_list, command_list, number_of_methods); 12 | end; 13 | 14 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15 | function result = loop_parallel(fs, amp_list, command_list, number_of_methods) 16 | 17 | basic_f0 = 440; 18 | result = zeros(length(amp_list), number_of_methods); 19 | 20 | parfor i = 1 : length(amp_list) 21 | amp = amp_list(i); 22 | f0_contour = generate_f0_contour(basic_f0, 0); 23 | x = generate_signal_from_f0_contour(f0_contour, fs, amp, 0); 24 | 25 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 26 | result(i, :) = tmp(:)'; 27 | 28 | fprintf('ACT 3: %.1f dB\n', amp); 29 | end; 30 | 31 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 32 | function result = loop_normal(fs, amp_list, command_list, number_of_methods) 33 | 34 | basic_f0 = 440; 35 | result = zeros(length(amp_list), number_of_methods); 36 | 37 | for i = 1 : length(amp_list) 38 | amp = amp_list(i); 39 | f0_contour = generate_f0_contour(basic_f0, 0); 40 | x = generate_signal_from_f0_contour(f0_contour, fs, amp, 0); 41 | 42 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 43 | result(i, :) = tmp(:)'; 44 | 45 | fprintf('ACT 3: %.1f dB\n', amp); 46 | end; 47 | -------------------------------------------------------------------------------- /src/act4.m: -------------------------------------------------------------------------------- 1 | function [result, method_list] = act4(filename_list, phase_list, parallel_flag) 2 | 3 | fs = 48000; 4 | [command_list, number_of_methods, method_list] =... 5 | extract_commands(filename_list); 6 | 7 | % Function loop_parallel() requires parallel computing toolbox. 8 | if parallel_flag == 1 && check_toolbox == 1 9 | result = loop_parallel(fs, phase_list, command_list, number_of_methods); 10 | else 11 | result = loop_normal(fs, phase_list, command_list, number_of_methods); 12 | end; 13 | 14 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15 | function result =... 16 | loop_parallel(fs, phase_list, command_list, number_of_methods) 17 | 18 | basic_f0 = 440; 19 | result = zeros(length(phase_list), number_of_methods); 20 | 21 | parfor i = 1 : length(phase_list) 22 | phase = phase_list(i); 23 | f0_contour = generate_f0_contour(basic_f0, 0); 24 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, phase); 25 | 26 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 27 | result(i, :) = tmp(:)'; 28 | 29 | fprintf('ACT 4: %.1f\n', phase); 30 | end; 31 | 32 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 33 | function result = loop_normal(fs, phase_list, command_list, number_of_methods) 34 | 35 | basic_f0 = 440; 36 | result = zeros(length(phase_list), number_of_methods); 37 | 38 | for i = 1 : length(phase_list) 39 | phase = phase_list(i); 40 | f0_contour = generate_f0_contour(basic_f0, 0); 41 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, phase); 42 | 43 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 44 | result(i, :) = tmp(:)'; 45 | 46 | fprintf('ACT 4: %.1f\n', phase); 47 | end; 48 | -------------------------------------------------------------------------------- /src/act5.m: -------------------------------------------------------------------------------- 1 | function [result, method_list] =... 2 | act5(filename_list, SNR_list, parallel_flag, flag) 3 | 4 | fs = 48000; 5 | [command_list, number_of_methods, method_list] =... 6 | extract_commands(filename_list); 7 | 8 | % Function loop_parallel() requires parallel computing toolbox. 9 | if parallel_flag == 1 && check_toolbox == 1 10 | result = loop_parallel(fs, SNR_list, command_list, number_of_methods, flag); 11 | else 12 | result = loop_normal(fs, SNR_list, command_list, number_of_methods, flag); 13 | end; 14 | 15 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 | function result =... 17 | loop_parallel(fs, SNR_list, command_list, number_of_methods, flag) 18 | 19 | basic_f0 = 440; 20 | result = zeros(length(SNR_list), number_of_methods); 21 | 22 | parfor i = 1 : length(SNR_list) 23 | SNR = SNR_list(i); 24 | f0_contour = generate_f0_contour(basic_f0, 0); 25 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 26 | if flag == 0 27 | n = randn(length(x), 1); 28 | else 29 | n = generate_pinknoise(length(x), fs); 30 | end; 31 | amp = 10 ^ (SNR / 20); 32 | n = n ./ sqrt(sum(n .^ 2)) / amp; 33 | x = x + n; 34 | 35 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 36 | result(i, :) = tmp(:)'; 37 | 38 | fprintf('ACT 5: %.1f dB\n', SNR); 39 | end; 40 | 41 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 42 | function result =... 43 | loop_normal(fs, SNR_list, command_list, number_of_methods, flag) 44 | 45 | basic_f0 = 440; 46 | result = zeros(length(SNR_list), number_of_methods); 47 | 48 | for i = 1 : length(SNR_list) 49 | SNR = SNR_list(i); 50 | f0_contour = generate_f0_contour(basic_f0, 0); 51 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 52 | if flag == 0 53 | n = randn(length(x), 1); 54 | else 55 | n = generate_pinknoise(length(x), fs); 56 | end; 57 | amp = 10 ^ (SNR / 20); 58 | n = n ./ sqrt(sum(n .^ 2)) / amp; 59 | x = x + n; 60 | 61 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 62 | result(i, :) = tmp(:)'; 63 | 64 | fprintf('ACT 5: %.1f dB\n', SNR); 65 | end; 66 | 67 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 68 | function pink_noise = generate_pinknoise(N, fs) 69 | 70 | filter_size = 8192; % Filter length to manipulate the spectrum 71 | 72 | w = (0:filter_size-1) * fs / filter_size; 73 | w = w(:); 74 | % Frequency of under 20 Hz is ignored. 75 | w(w < 20) = w(find(w > 20, 1)); 76 | half_spectrum = 1 ./ sqrt(w); 77 | spectrum = [half_spectrum(1:filter_size / 2);... 78 | conj(half_spectrum(filter_size / 2 - 1:-1:2))]; 79 | impulse_response = fftshift(real(ifft(spectrum))); 80 | [~, impulse_response] = rceps(impulse_response); 81 | 82 | y = fftfilt(impulse_response, randn(N + filter_size * 2, 1)); 83 | 84 | pink_noise = y(filter_size + 1:end - filter_size); 85 | -------------------------------------------------------------------------------- /src/act6.m: -------------------------------------------------------------------------------- 1 | function [result, method_list] =... 2 | act6(filename_list, reverb_list, parallel_flag) 3 | 4 | fs = 48000; 5 | [command_list, number_of_methods, method_list] =... 6 | extract_commands(filename_list); 7 | 8 | % Function loop_parallel() requires parallel computing toolbox. 9 | if parallel_flag == 1 && check_toolbox == 1 10 | result = loop_parallel(fs, reverb_list, command_list, number_of_methods); 11 | else 12 | result = loop_normal(fs, reverb_list, command_list, number_of_methods); 13 | end; 14 | 15 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 | function result =... 17 | loop_parallel(fs, reverb_list, command_list, number_of_methods) 18 | 19 | t = (0 : fs - 1) / fs; 20 | basic_f0 = 440; 21 | result = zeros(length(reverb_list), number_of_methods); 22 | 23 | parfor i = 1 : length(reverb_list) 24 | reverb = reverb_list(i) / 1000; 25 | damping = -log(0.001) / reverb; 26 | envelope = exp(-damping * t) / sqrt(10); 27 | impulse_response = envelope(:) .* ((rand(length(envelope), 1) - 0.5) * 2); 28 | impulse_response(1) = 1; 29 | 30 | f0_contour = generate_f0_contour(basic_f0, 0); 31 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 32 | x_len = length(x); 33 | x = fftfilt(impulse_response, [x(:); zeros(fs, 1)]); 34 | x = x(1 : x_len); 35 | 36 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 37 | result(i, :) = tmp(:)'; 38 | 39 | fprintf('ACT 6: %.1f ms\n', reverb * 1000); 40 | end; 41 | 42 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 43 | function result = loop_normal(fs, reverb_list, command_list, number_of_methods) 44 | 45 | t = (0 : fs - 1) / fs; 46 | basic_f0 = 440; 47 | result = zeros(length(reverb_list), number_of_methods); 48 | 49 | for i = 1 : length(reverb_list) 50 | reverb = reverb_list(i) / 1000; 51 | damping = -log(0.001) / reverb; 52 | envelope = exp(-damping * t) / sqrt(10); 53 | impulse_response = envelope(:) .* ((rand(length(envelope), 1) - 0.5) * 2); 54 | impulse_response(1) = 1; 55 | 56 | f0_contour = generate_f0_contour(basic_f0, 0); 57 | x = generate_signal_from_f0_contour(f0_contour, fs, 0, 0); 58 | x_len = length(x); 59 | x = fftfilt(impulse_response, [x(:); zeros(fs, 1)]); 60 | x = x(1 : x_len); 61 | 62 | tmp = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, i); 63 | result(i, :) = tmp(:)'; 64 | 65 | fprintf('ACT 6: %.1f ms\n', reverb * 1000); 66 | end; 67 | -------------------------------------------------------------------------------- /src/check_toolbox.m: -------------------------------------------------------------------------------- 1 | function result = check_toolbox 2 | 3 | result = 0; 4 | toolbox_list = ver; 5 | for i = 1 : length(toolbox_list) 6 | if strcmp(toolbox_list(i).Name, 'Parallel Computing Toolbox') == 1 7 | result = 1; 8 | end; 9 | end; 10 | -------------------------------------------------------------------------------- /src/estimate_f0.m: -------------------------------------------------------------------------------- 1 | function result = estimate_f0(x, fs, f0_contour, number_of_methods, command_list, option) 2 | result = zeros(number_of_methods, 1); 3 | 4 | for j = 1 : number_of_methods 5 | for k = 1 : length(command_list{j}) 6 | eval(command_list{j}{k}); 7 | end; 8 | if isempty(f0) 9 | f0 = f0_contour * 0; 10 | end; 11 | tmp1 = f0(101 : 1100); 12 | tmp1(isnan(tmp1)) = 0; 13 | tmp2 = f0_contour(101 : 1100); 14 | error_sequence = tmp1(:) - tmp2(:); 15 | result(j) = sqrt(mean(error_sequence .^ 2)); 16 | end; 17 | -------------------------------------------------------------------------------- /src/extract_commands.m: -------------------------------------------------------------------------------- 1 | function [command_list, number_of_methods, method_list] = extract_commands(filename) 2 | fid = fopen(filename, 'r'); 3 | 4 | number_of_methods = str2num(fgets(fid)); 5 | fgets(fid); 6 | 7 | for i = 1 : number_of_methods 8 | j = 1; 9 | method_list{i} = fgets(fid); 10 | while 1 11 | tmp = fgets(fid); 12 | if tmp == -1 break; end; 13 | if (tmp(1) == 13 && tmp(2) == 10) 14 | break; 15 | end; 16 | command_list{i}{j} = tmp; 17 | j = j + 1; 18 | end; 19 | end; 20 | 21 | fclose(fid); -------------------------------------------------------------------------------- /src/freq2cent.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmorise/tusk/dfde82c770789f0bd70c92d84439256e7303b7c3/src/freq2cent.m -------------------------------------------------------------------------------- /src/generate_f0_contour.m: -------------------------------------------------------------------------------- 1 | function f0_contour = generate_f0_contour(basic_f0, vibrato_modulation) 2 | t = (0 : 1200) / 1000; 3 | FL = 25; 4 | % FL = 150; 5 | 6 | basic_f0_contour = zeros(1, length(t)) + basic_f0; 7 | delta_f0_contour = FL / 50 * basic_f0 / 100 * (sin(12.7 * 2 * pi * t) + ... 8 | sin(7.1 * 2 * pi * t) + sin(4.7 * 2 * pi * t)); 9 | vibrato_f0_contour = sqrt(vibrato_modulation * basic_f0) * ... 10 | cos(sqrt(vibrato_modulation * basic_f0) * t); 11 | 12 | f0_contour = basic_f0_contour + delta_f0_contour + vibrato_f0_contour; 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/generate_pulsetrain_from_f0_contour.m: -------------------------------------------------------------------------------- 1 | function x = generate_pulsetrain_from_f0_contour(f0, fs) 2 | 3 | temporal_positions = (0 : length(f0) - 1) / 1000; 4 | signal_time = (0 : 1 / fs : (length(f0) - 1) / 1000); 5 | 6 | f0_interpolated = ... 7 | interp1(temporal_positions, f0, signal_time, 'linear', 'extrap'); 8 | total_phase = cumsum(2 * pi * f0_interpolated / fs); 9 | pulse_locations = signal_time(abs(diff(rem(total_phase, 2 * pi))) > pi / 2); 10 | pulse_locations_index = round(pulse_locations * fs) + 1; 11 | 12 | x = zeros(length(signal_time), 1); 13 | for i = 1 : length(pulse_locations_index) 14 | x(pulse_locations_index(i)) = 1; 15 | end; -------------------------------------------------------------------------------- /src/generate_signal_from_f0_contour.m: -------------------------------------------------------------------------------- 1 | function x = generate_signal_from_f0_contour(f0_contour, fs, amp, phase) 2 | 3 | w0_contour = f0_contour * 2 * pi; 4 | 5 | time_axis = (0 : length(w0_contour) - 1) / 1000; 6 | time_axis2 = (0: 1 / fs : time_axis(end)); 7 | 8 | cumlative_w0_contour = cumsum(w0_contour) / 1000; 9 | cumlative_w0_contour2 = interp1(time_axis, cumlative_w0_contour, time_axis2); 10 | 11 | x = zeros(length(cumlative_w0_contour2), 1); 12 | 13 | % fft_size = 65536; 14 | % w = (0 : fft_size - 1) * fs / fft_size; 15 | for i = 1 : floor((fs / 2) / max(f0_contour)) 16 | % rand_amp = 10 ^ (rand * amp / 20); 17 | rand_amp = 10 ^ (rand * amp / 20); 18 | rand_phase = rand * phase; 19 | x = x + cos(i * cumlative_w0_contour2' + rand_phase) * rand_amp; 20 | % plot(w, 20 * log10(abs(fft(x .* blackman(length(x)), fft_size)))); 21 | % grid; 22 | % pause; 23 | end 24 | 25 | x = x ./ sqrt(sum(x .^ 2)); 26 | -------------------------------------------------------------------------------- /src/plot_figure.m: -------------------------------------------------------------------------------- 1 | function plot_figure(result, range, xlabel_text, method_list, selected_methods) 2 | 3 | if nargin ~= 5 4 | selected_methods = 1 : length(method_list); 5 | end; 6 | 7 | figure; 8 | semilogy(range, result(:, selected_methods)); 9 | % legend('Dio', 'YIN', 'SWIPE', 'XSX', 'NDF', 'ACDC'); 10 | legend(method_list(selected_methods)); 11 | grid; 12 | set(gca, 'xlim', [range(1) range(end)]); 13 | xlabel(xlabel_text); 14 | ylabel('RMS error'); 15 | -------------------------------------------------------------------------------- /tusk_example.m: -------------------------------------------------------------------------------- 1 | %% Examples of TUSK 2 | % Please see the following reference in the details of TUSK. 3 | % M. Morise and H. Kawahara: 4 | % TUSK: A framework for overviewing the performance of F0 estimators, 5 | % Proc. INTERSPEECH 2016, pp. 1790-1794, San Francisco, Sept. 8-12, 2016. 6 | 7 | % This script uses Dio() in WORLD for test. 8 | % Please download WORLD from the following. 9 | % http://ml.cs.yamanashi.ac.jp/world/english/index.html 10 | 11 | % Please set the frame shift to 1 ms. Since the duration of test signal is 1.2 s, 12 | % the estiamted result should be 1,200 (or 1201) samples. 13 | % Note: TUSK uses the result from 0.1 to 1.1 s (101 : 1100). 14 | % It may be possible to evaluate the estimator even if it does not 15 | % return the sequences consisting of 1,200 sample. 16 | % In case that the difference is large, the result may be unreliable. 17 | 18 | % The file "commandlist.txt" is used to set the commands for obtaining the 19 | % estimated F0 contour. 20 | % You can use not only the MATLAB script but also other scripts. 21 | % Function system() would be useful to write the script. 22 | 23 | %% Setting 24 | % If you have Parallel Computing Toolbox (PCT), you can select using it 25 | parallel_flag = 1; % You want to use PCT. 26 | % parallel_flag = 0; % You don't want to use PCT. 27 | 28 | % In ACT 3, 4, 5 and 6, they use a random sequence. To remove the 29 | % its dependency, you should average the results of multiple test. 30 | % N is the number of repeats (N > 1). 31 | N = 5; 32 | 33 | %% ACT 1: Relationship between basic F0 and estimation performance 34 | clearvars -except parallel_flag N 35 | % In Act 1, you can set the frequency range. 36 | f0_list = 55 * 2 .^ ((0 : 48) / 12); 37 | 38 | [result1, method_list] = act1('commandlist.txt', f0_list, parallel_flag); 39 | save result_act1.mat 40 | plot_figure(result1, freq2cent(f0_list), 'F0 (cent)', method_list); 41 | 42 | %% ACT 2: Influence of temporal fluctuation in F0 contour 43 | clearvars -except parallel_flag N 44 | % In Act 2, you can set the range of alpha. 45 | alpha_list = 0 : 0.1 : 25; % vibrato intensity 46 | 47 | [result2, method_list] = act2('commandlist.txt', alpha_list, parallel_flag); 48 | save result_act2.mat 49 | plot_figure(result2, alpha_list, 'Vibrato intensity \alpha', method_list); 50 | 51 | %% ACT 3: Influence of amplitudes of each harmonic component 52 | clearvars -except parallel_flag N 53 | % In Act 3, you can set the dynamic range of amplitude. 54 | amp_list = 0 : 0.5 : 60; 55 | 56 | [tmp, method_list] = act3('commandlist.txt', amp_list, parallel_flag); 57 | result3 = zeros(size(tmp, 1), size(tmp, 2), N); 58 | for i = 2 : N 59 | tmp = act3('commandlist.txt', amp_list, parallel_flag); 60 | result3(:, :, i) = tmp; 61 | fprintf('--------------------------------------------------------------\n'); 62 | fprintf('i : %d completed.\n', i); 63 | fprintf('--------------------------------------------------------------\n'); 64 | end; 65 | save result_act3.mat 66 | plot_figure(median(result3, 3), amp_list, 'Amplitude randomization (dB)', method_list); 67 | 68 | %% ACT 4: Influence of phases of each harmonic component 69 | clearvars -except parallel_flag N 70 | % In Act 4, you can set the dynamic range of phase. 71 | phase_list = 0 : 0.05 : 2 * pi; 72 | 73 | [tmp, method_list] = act4('commandlist.txt', phase_list, parallel_flag); 74 | result4 = zeros(size(tmp, 1), size(tmp, 2), N); 75 | for i = 2 : N 76 | tmp = act4('commandlist.txt', phase_list, parallel_flag); 77 | result4(:, :, i) = tmp; 78 | fprintf('--------------------------------------------------------------\n'); 79 | fprintf('i : %d completed.\n', i); 80 | fprintf('--------------------------------------------------------------\n'); 81 | end; 82 | save result_act4.mat 83 | plot_figure(median(result4, 3), phase_list, 'Phase randomization (rad)', method_list); 84 | 85 | %% ACT 5: Noise robustness (whitenoise) 86 | clearvars -except parallel_flag N 87 | % In Act 5, you can set the SNR. 88 | SNR_list = 0 : 0.5 : 60; 89 | 90 | [tmp, method_list] = act5('commandlist.txt', SNR_list, parallel_flag, 0); 91 | result5_1 = zeros(size(tmp, 1), size(tmp, 2), N); 92 | for i = 2 : N 93 | tmp = act5('commandlist.txt', SNR_list, parallel_flag, 0); 94 | result5_1(:, :, i) = tmp; 95 | fprintf('--------------------------------------------------------------\n'); 96 | fprintf('i : %d completed.\n', i); 97 | fprintf('--------------------------------------------------------------\n'); 98 | end; 99 | save result_act5_1.mat 100 | plot_figure(median(result5_1, 3), SNR_list, 'SNR (dB)', method_list); 101 | 102 | %% ACT 5: Noise robustness (pinknoise) 103 | clearvars -except parallel_flag N 104 | % In Act 5, you can set the SNR. 105 | SNR_list = 0 : 0.5 : 60; 106 | 107 | [tmp, method_list] = act5('commandlist.txt', SNR_list, parallel_flag, 1); 108 | result5_2 = zeros(size(tmp, 1), size(tmp, 2), N); 109 | for i = 2 : N 110 | tmp = act5('commandlist.txt', SNR_list, parallel_flag, 1); 111 | result5_2(:, :, i) = tmp; 112 | fprintf('--------------------------------------------------------------\n'); 113 | fprintf('i : %d completed.\n', i); 114 | fprintf('--------------------------------------------------------------\n'); 115 | end; 116 | save result_act5_2.mat 117 | plot_figure(median(result5_2, 3), SNR_list, 'SNR (dB)', method_list); 118 | 119 | %% ACT 6: Influence of the reverberation 120 | clearvars -except parallel_flag N 121 | % In Act 6, you can set the reverberation. 122 | reverb_list = 10 : 10 : 1000; 123 | 124 | [tmp, method_list] = act6('commandlist.txt', reverb_list, parallel_flag); 125 | result6 = zeros(size(tmp, 1), size(tmp, 2), N); 126 | for i = 2 : N 127 | tmp = act6('commandlist.txt', reverb_list, parallel_flag); 128 | result6(:, :, i) = tmp; 129 | fprintf('--------------------------------------------------------------\n'); 130 | fprintf('i : %d completed.\n', i); 131 | fprintf('--------------------------------------------------------------\n'); 132 | end; 133 | save result_act6.mat 134 | plot_figure(median(result6, 3), reverb_list, 'Reverberation (ms)', method_list); 135 | --------------------------------------------------------------------------------