Ripple Sounds

From biophysics
Revision as of 12:55, 11 September 2024 by Lof (talk | contribs) (→‎FFT-iFFT method)
Jump to navigation Jump to search

Introduction

Ripple sounds are temporal and spectral modulated sounds (or noise). They mimic some aspects of vowels. They are often used in experiments for cochlear implant users.

There are basically two methods for creating ripple sounds, which are described in detail below:

  • the FFT-iFFT method
  • the band-filter method

FFT-iFFT method

The FFT-iFFT method for creating rippled sounds begins by generating two copies of a broad band signal, often noise. Each copy is temporally modulated in the time domain with a sine and a cosine of the same frequency, creating two orthogonal components. Next, the FFT is applied to both modulated signals to obtain their spectra. In the spectral domain, these spectra are modulated by multiplying them sine and cosine functions. The modulated spectra are then transformed back to the time domain using the inverse FFT. The two time-domain signals are either summed or subtracted, which results in ripples that move upward or downward in frequency. Finally, these ripples are scaled by a modulation depth factor (ranging from 0 to 1) and added to the original sound, controlling the intensity of the ripples in the resulting audio.

Below is an example of an implementation in Matlab. It is based on a broadband signal consisting of pink noise. The input parameters are:

Term Description
t time domain array in seconds
octaves frequency domain array in octaves
ripples_per_sec the ripple velocity in the time domain
phi a phase that can be added to the time modulation
ripples_per_octave the ripple density in the frequency domain
rippleType determines if the ripple is ascending or descending
modulationDepth half the amplitude of the modulation


The variables that are sin modulated are denoted by the prefix 'sin_', the cos modulated by the prefix 'cos_'.
The variables in the time domain are denoted by the suffix '_td' and variables in the frequency domain by the suffix '_fd'.

% Generate an array with pink noise
broadBandSignal_td = pinknoise(length(t));

% Create modulation functions for time domain (velocity modulation)
sin_modulation_td = sin(2 * pi * ripples_per_sec * t + phi);
cos_modulation_td = cos(2 * pi * ripples_per_sec * t + phi);        

% Apply time modulation to the noise in the time domain
sin_modulatedSignal_td = sin_modulation_td .* broadBandSignal_td;
cos_modulatedSignal_td = cos_modulation_td .* broadBandSignal_td;

% Perform fft to convert the signals to the frequency domain
sin_modulatedSignal_fd = fft(sin_modulatedSignal_td);
cos_modulatedSignal_fd = fft(cos_modulatedSignal_td);

% Create modulation functions for frequency domain (density modulation)
sin_modulation_fd = sin(2 * pi * ripples_per_octave * octaves);
cos_modulation_fd = cos(2 * pi * ripples_per_octave * octaves);
     
% Apply frequency modulation in the frequency domain 
sin_rippledSignal_fd = sin_modulation_fd .* sin_modulatedSignal_fd;
cos_rippledSignal_fd = cos_modulation_fd .* cos_modulatedSignal_fd;   

% Mirror (fliplr) the frequency modulation components for ifft compatibility and perform ifft to get rippled noise in the time domain
sin_rippledSignal_td = ifft([sin_rippledSignal_fd , fliplr(sin_rippledSignal_fd )], 'symmetric');
cos_rippledSignal_td = ifft([cos_rippledSignal_fd , fliplr(cos_rippledSignal_fd )], 'symmetric');

% Determine the ripple type (ascending vs. descending)
switch rippleType
    case 'ascending'
        combinedRippledSignal_td = sin_rippledSignal_td + cos_rippledSignal_td;
    case 'descending'
        combinedRippledSignal_td = sin_rippledSignal_td - cos_rippledSignal_td;
end 

% Calculate the final rippled stimulus in the time domain          
rippledStimulus_td = broadBandSignal_td + modulationDepth * combinedRippledSignal_td;

N.B. It is important that you call the function 'pinknoise' only once and stored the result in broadBandSignal_time. If you instead call the function pinknoise again in the last line it gives a wrong result, because each call creates a new random array and this will destroy the necessary interference in the last line.

Band filter method

%todo

References

% todo