Sonifikacja interpretowana i wizualizacja liter Pana Tadeusza w postaci video
W tym wypadku bajty nie będą sonifikowane bezpośrednio, ale posłużą jako parametry syntezy dźwięku. Generowane będą proste tony sinusoidalne o częstotliwości równej liczbie kodującej dany znak. Najniższy dźwięk ma częstotliwość 32 Hz, co odpowiada liczbie 32 kodującej spację w systemie ASCII. W przypadku polskich znaków diakrytycznych dwa bajty reprezentujące taki znak są sumowane, stąd polskie znaki słyszalne będą jako dźwięki wyższe od innych. Próbki będą generowane z szybkością 8 dźwięków na sekundę. Do dźwięku dołączona jest prosta interpretacja wizualna. Kolor kwadratu (jego jasność) określa również liczba kodująca znak. W przypadku polskich znaków obraz jest jaśniejszy i kolorowy, a dźwięk przedłużony:
UWAGA! nagranie zawiera niskie częstotliwości (min. 32 Hz):
Kod w języku matlab:
% -------------------------
% Interpretowanie znaków tekstu jako danych sterująctych w procedurze generatywnej.
% W rezultacie: 8 dźwięków na sekundę i klatki wideo o rónych stopniach szarości
% % polskie znaki mają wyższe częstotliwości a obraz zyskuje kolor
% -------------------------
% ustawienia
text_file_name = 'PanTadeusz-Unicode.txt';
frameRate = 32;
videoQuality = 95;
sound_len_sec = .125;
fs = 44100;
sound_num = 1000;
% wyniki
outFolder = "konf"; outId = randi([1, 1000000]);
outVideo = char(join([outFolder, '/', num2str(outId), '.avi'], ''));
outAudio = char(join([outFolder, '/', num2str(outId), '.wav'], ''));
outMerged = char(join([outFolder, '/', num2str(outId), '.mp4'], ''));
% otwieranie tekstu
fileID = fopen(text_file_name,'r');
A = fscanf(fileID,'%c');
fclose (fileID);
% przygotowanie pojemnikow
a = double(A);
max_f = max(a);
sound_length = round(fs * sound_len_sec);
frames_per_sound = frameRate * sound_len_sec;
X = zeros(sound_length * sound_num, 1);
% mapy kolorow
gray_map = gray(256);
hot_map = flipud(jet(max_f - 255));
% przygotowanie video
v = VideoWriter(outVideo,'Motion JPEG AVI');
v.Quality = videoQuality;
v.FrameRate = frameRate;
v.open;
% czytaj po literze
for k=1:sound_num
disp(num2str(k))
f = a(k);
% czy polski znak?
if (f > 255)
l = sound_length * 10;
map = hot_map;
polski_znak = 1;
p = f - 255;
else
l = sound_length;
map = gray_map;
polski_znak = 0;
p = f;
end
% ramka video
frame = (ones(480, 640) * p) / max_f + 1;
frame = im2frame(round(frame * 255), map);
for m = 1 : frames_per_sound; writeVideo(v,frame); end
% wstaw sinusoidę
x = (sinusoida(f, 1, l , fs))';
x = fadeinout (x, 300);
if (polski_znak); x = x .* hann(length(x)); end
start_point = (k - 1) * sound_length + 1;
stop_point = start_point + length(x) - 1;
if length(X) < stop_point; X = [X; zeros(stop_point - length(X) + 10, 1)]; end
X(start_point:stop_point) = X(start_point:stop_point) + x;
end
v.close;
% normalizuj i zapisz audio
X = X - min(X); X = X / max(X); X = X * 2 - 1;
audiowrite (outAudio, X, fs, 'BitsPerSample', 16)
% zrób obraz
en = enframe(a, 663); en = round ((en / max(en(:))) * 100);
imwrite(en,gray,'konf/szum_gray_1.jpeg')
% złącz audio i video
command = ['/usr/local/bin/ffmpeg -i ', outVideo , ' -i ', outAudio, ' -c:v copy -c:a aac -strict experimental ', outMerged];
system(command);
return
% podprogram do generowania sygnału sinusoidalnego
function x = sinusoida(f, a, L, Fs, phase)
% x = sinusoida(f, a, L, Fs, p)
if nargin<5
phase = 0;
end
T = 1/Fs;
t = (0:L-1)*T;
period = Fs/f;
pshift = round ((phase/360) * period);
x = a * sin(2 * pi * f * t + pshift);
Autorstwo kodu, video i próbek dźwiękowych: Marcin Strzelecki