How to properly map an audio signal from 0 to 1 range into a -1 to 1 range
11 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
Miroslav Müller
am 26 Dez. 2021
Bearbeitet: Miroslav Müller
am 1 Jan. 2022
Hi, I have a signal which looks like this:

and its amplitude is in the range from 0 to 1. I am further working with it with filters (karplus-strong algorithm, convolution,...).
The thing is, I dont want the signal to be on just one side (from 0 to 1) for the whole time, while it could better use the potential of the speaker by going to both sides (from -1 to 1). The result after I applied the KS filter also stay above 0 because of this, sometimes not even touching 0 for a long time (eg 2 seconds).
If I were to subtract 0.5 and then multiply by 2 to stretch it, it would create a sharp 'jump' at the start and at the end. Is there any standard way of mapping or converting the signal into the -1 to 1 range while not involving such 'jumps'?
EDIT:
Ive reached a conclusion that it is not possible without changing the resulting percieved sound effect, and am thinking whether it is even desired (in my case Im simulating the piano's hammer). Intuition tells me it should be from -1 to 1 as Ive always seen audio signals like this, but maybe in this case not.
EDIT2:
The first answer with a discussion in comments where i sent and discussed my code was sadly deleted by its original author, the second answer which I now marked as solution is a good way on how to deal with this type of thing. I tried it and it helps, although it created another small problems in my design, so I have come up with my personal solution by rather using the detrend() function later in my code after applying filters. The thing why I needed it was since I discovered that for high frequencies, my algorithm produces an output which stays on one side from zero even for a few seconds, which was not good when I wanted eg to cut the signal halfway. Another problem was, that with my laptop setup, this somehow added electrical buzzing during playback - the speakers or drivers probably didnt like to "hold" the signal in a non-zero position for a long time. The detrend helped a bit with it. Although the problem still quite remained, so I added a very low frequency (difficult to hear) sine wave to the signal - this way, it regularly crossed zero, and the buzzing reduced :D

1 - output of my algotihm for high frequencies, oscillates around a point above zero
2 - output after using detrend (which curved the whole thing down a bit) with an added low-frequency sine
3 Kommentare
Akzeptierte Antwort
Image Analyst
am 27 Dez. 2021
How about if you just make a ramp from 0 to the end of the signal so it goes smoothly from silence to the actual signal?
Also I'm just basically scaling and shifting the signal so that it's in the same range rather than normalizing the signal, which might make other signals be of the improper relative amplitude. In other words a signal from 0-0.4 will go from -0.2 to +0.2 not -1 to +1. Why? Because if the next signal is twice as loud, you want to hear it twice as loud and if all signals go from -1 to 1, they won't have much volume difference. Doing what I did the signal would go from -0.4 to +0.4 and sound twice as loud.
However if you want all signals to have the same relative volume you can use rescale() or normalize() to send the min to -1 and max to +1, or use even more sophisticated volume equalizing methods.
% Demo by Image Analyst, December, 2021.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clearvars;
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 16;
fprintf('Beginning to run %s.m ...\n', mfilename);
% Define data as 2-D matrix with times in column 1 and signal in column 2.
originalData = [
4.78e-05, 0.01303;
8.36e-05, 0.12144;
0.0001075, 0.22985;
0.0001314, 0.33826;
0.0001553, 0.44666;
0.0001672, 0.55507;
0.000215, 0.65915;
0.0003822, 0.61152;
0.0005494, 0.52486;
0.0006808, 0.43386;
0.0007644, 0.48592;
0.0008002, 0.59
0.000836, 0.69841;
0.0008599, 0.80682;
0.0009077, 0.91524;
0.0010271, 0.89794;
0.0011107, 0.79391;
0.0012063, 0.69422;
0.0013137, 0.5902;
0.0013735, 0.48616;
0.001469, 0.49054;
0.0015168, 0.59895;
0.0015646, 0.70303;
0.0016243, 0.81146;
0.0017437, 0.73346;
0.0018034, 0.62942;
0.001887, 0.52105;
0.0019587, 0.41702;
0.0020303, 0.31298;
0.0020901, 0.20894;
0.0022334, 0.23068;
0.0022931, 0.3391;
0.0024245, 0.37817;
0.0025081, 0.27414;
0.0025917, 0.17011;
0.0026872, 0.06609;
0.003, 0;
];
% Get the times from column 1 and signal from column 2.
originalTimes = originalData(:, 1);
originalSignal = originalData(:, 2);
% Make row vectors for convenience in appending ramps, etc.
originalTimes = reshape(originalTimes, 1, []);
originalSignal = reshape(originalSignal, 1, []);
% Compute a new time axis to use and interpolate over.
fs = 44100;
dur = 2; % new time is 2 seconds instead of originalTimes(end) which is 0.003;
deltat = 1/fs;
tt = 0 : deltat : (dur - deltat);
numSamples = length(tt)
% Find sampling points using the original times so we can do the interpolation over the original signal's range.
t = linspace(originalTimes(1), originalTimes(end), numSamples);
% Plot original signal.
subplot(3, 1, 1);
plot(originalTimes, originalSignal, 'LineWidth', 2)
axis("tight");
grid on;
title('Original Signal', 'FontSize', fontSize)
% Create new signal
newSignal = interp1(originalTimes, originalSignal, t, 'makima', 0);
% newSignal = normalize(newSignal, 'Range', [-1 1]); % normalizing here
% Shift potential range from 0-1 to -1 to +1, regardless of where signal actually lies.
newSignal = newSignal * 2 - 1;
subplot(3, 1, 2);
plot(t, newSignal, 'LineWidth', 2)
axis("tight");
grid on;
% Put x axis at y=0.
ax2 = gca;
ax2.XAxisLocation = 'origin';
title('Interpolated, Scaled, and Shifted Signal', 'FontSize', fontSize)
% Create ranmps to tack on to the left and right of the signal
numRampElements = round(0.05 * length(newSignal))
leftRamp = linspace(0, newSignal(1), numRampElements);
rightRamp = linspace(newSignal(end), 0, numRampElements);
% Prepend and append ramps
newSignal = [leftRamp, newSignal, rightRamp];
% Need to stretch time axis because we added on elements.
lastTime = t(end) + numRampElements * 2 * deltat;
t = linspace(0, lastTime, length(t) + 2 * numRampElements);
% Plot new signal.
subplot(3, 1, 3);
plot(t, newSignal, 'b-', 'LineWidth', 2)
axis("tight");
grid on;
% Put x axis at y=0.
ax3 = gca;
ax3.XAxisLocation = 'origin';
title('New Signal With Ramps', 'FontSize', fontSize)
% Just for info, put vertical red lines at the connection points with the ramps.
xline(t(numRampElements), 'Color', 'r', 'LineWidth', 2);
xline(t(end - numRampElements), 'Color', 'r', 'LineWidth', 2);

If you want you could use something smoother than ramps, like a sine wave that matches up the slope at the connection point, at a little more complication in the code. Or just attenuate the signal at the outer ends with something like a Hamming function.
0 Kommentare
Weitere Antworten (0)
Siehe auch
Kategorien
Mehr zu Measurements and Spatial Audio finden Sie in Help Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!