Vous êtes sur la page 1sur 22

Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

Esgrove
Akseli Lukkarila / DJ Esgrove / Ru! Cut

# $ % (
' &

Home » DJ » Analysing the Serato DJ timecode signal

Analysing the Serato DJ timecode Search

signal
2

15 Mar, 2016 in DJ / Matlab by Akseli Lukkarila (updated on 16.03.2016)


! Archives
› March 2016
› February 2016

Serato DJ (and previously Scratch Live) is one of the leading DJ


" Categories
software applications out there, and in my personal experience by far
the most widely used. I have played almost all of my dj gigs with the › Arduino
Serato software since January 2007. Serato DJ and the old Scratch Live, › DJ
together with an appropriate sound card, form a so called DVS setup, › Matlab
which is short for Digital Vinyl System. Nowadays these software

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 1 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

solutions do much much more than what the name DVS implies, but › Programming
the core function is still the same that it was in 2004 when Serato › Python
Scratch Live was introduced. › Qt

The fundamental idea is taking a traditional dj setup with either › Uncategorized


turntables or cd players (or both), and instead of playing actual
records (vinyl or cd), the music comes from a computer. The main ) Pages
point is that the playback is still controlled with the vinyls or cd’s just › About
like you would with real records, but the actual audio data is stored › DJ
digitally on the computer. So instead of music, the physical records
› Engineer
used with a DVS contain a timecode signal that is send to the software,
which in turn controls the audio file. Here’s an old example picture of › CV
a DVS setup using the Rane SL2 usb interface (sound card): › Blog

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 2 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

Alright that’s enough introduction, let’s get down to business. What I


want to know is how it actually works, and how accurate it can be. To
control the playback of the digital audio files and enable things like
scratching, where the direction and speed of the playback changes
rapidly, the timecode has to describe the current playback speed,
direction and position accurately and reliably. The signal found on a
Serato control vinyl or cd is a regular stereo audio file, and the official
description of it goes like this:

“There are two parts to the Serato DJ Control Vinyl: The directional
tone, and the NoiseMap™. Listening to the control vinyl, the
directional tone is the 1 kHz tone. The NoiseMap™ sounds like
random noise over the top of the tone. The directional tone provides
the current speed and direction of the record, while the
NoiseMap™ tells the software precisely where on the record the
needle is currently. “

Indeed, when comparing the control signal to a pure 1 kHz tone, it


sounds quite noisy.

“Serato Control Signal”

00:00 00:00

1. “Serato Control Signal” 0:10


2. “1 kHz sine reference” 0:10

But how does it actually work? Well, let’s fire up Matlab and have a
closer look.

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 3 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 4 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 5 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

From the frequency spectrum we can confirm that the signal is indeed
exactly 1 kHz, and looking at the waveforms both channels contain
the same sine wave, but the phase of the right channel is 90 degrees
ahead. This is confirmed in the “padded right channel picture”, where
the right channel has been shifted 90 degrees backwards and the
waveforms line up nicely. The distinctly varying amplitudes of the
sine wave suggests the use of Amplitude shift keying -modulation,
which is a digital version of amplitude modulation. From here we can
already deduce two of the three control parameters.

Speed

Detecting speed changes is really straightforward. Changing the speed,


aka pitch, linearly affects the frequency, so a 1% speed increase
corresponds to the frequency:

And 16% speed decrease:

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 6 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

Therefore one can just do a quick Fourier transform, for example


using STFT, to get the frequency and then calculate the corresponding
speed. The performance limiting factor here is the frequency
resolution of the Fourier transform, i.e. how small changes in the
frequency can be detected and how long does it take. The frequency
resolution of FFT is simply:

, where is the sampling frequency and is the number of


FFT points (samples).

So to get a resolution of 1 Hz, which corresponds to 0,1 % speed


change, we would need when . This means
it would take one second to read a change in the speed with this
accuracy (since we need 44100 samples for the FFT). One second
between speed readings is not good. However, there is an easy way to
reduce the time, as we don’t need the whole frequency spectrum all
the way to 20 000 Hz, which we are now calculating every time. With
a maximum speed change of 100%, the frequency will be between 500
Hz and 2000 Hz. Therefore for the FFT calculation, the sampling rate
could be lowered to as low as 4000, which gives an usable frequency
range of 0-2000 Hz, that covers the range of the control signal. This
way, to achieve the same frequency resolution of 1 Hz we only need
4000 samples for the FFT, and the time between speed measurements
is ideally:

Of course there will be some overhead from all the calculations, but I
think an overall update speed of around a hundred milliseconds
should be enough even for fast scratching, which would allow the
system to detect ten speed changes in a second. Serato probably has
an even better / more optimized detection and calculation method for
this, but these calculations were just to see that it’s feasible. One
possible method would be to just stay in the time domain, and look at
the length of one period, since . Also, most of the DJ hardware
uses an ADC sampling rate of 48 kHz or higher instead of the 44,1 kHz

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 7 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

used here, which changes the results a bit.

Direction

This one is also very simple. There’s a reason for the 90 degree phase-
shift between the channels: when the signal is played forward, the
right channels sine wave is ahead, and when played backwards, the
left channel is ahead by 90 degrees. This could be detected in many
ways, and ideally it only takes two consecutive samples to determine
the direction, which would be really fast. Assuming that we take a
whole one period of the signal to detect the direction, it would still
only take around one millisecond on normal speed.

Position

Now comes the hard part. This is were the so called NoiseMap comes
in. We need to have some sort of sequence or pattern in the signal that
tells us where we are, i.e. a position marker.

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 8 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

Firstly, there’s what appears to be amplitude shift keying (the spikes


in the waveform). The simplest way to interpret this would be to just
look at the positive part and assume two amplitude levels: one period
encodes one binary value, where a high amplitude in corresponds to
binary one and low amplitude to zero. This gives us a binary sequence
that follows the amplitudes:

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 9 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

The first 64 binary values extracted with this method:

This could work in practice, for example we could use a 16 bit


sequence as one position marker. Reading this marker would take 16
periods, which corresponds to 16 milliseconds (one period is ) at
normal speed. The A-side on the Serato vinyl is 10 minutes (600 s) long

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 10 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

and the B-side is 15 minutes (900 s), so there are 600 000 and 900 000
wave periods per side. There would be

position markers per one second, which sounds reasonable, and

(side A), and

(side B)

position markers for the whole track, which is doable since with 16
bits we can represent

different values. Of course by using more amplitude levels, and for


example by taking the absolute value of the sine wave it would be
possible to pack a lot more data into one period.

However, in this old interview from 2011, Dylan Wood from Serato
says the following:

Behind the Scenes: Interview with Serato R&D


Share Reddit Share Tweet Stumble EmailShares 737Remember our article
on timecode and MIDI control article a little while back? We explained at
the time that it was just scratching the surface of the realities of what it
takes to measure platter control. There are a huge number of factors that
go into the development of … Continue reading

DJ TechTools 36

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 11 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

“ The difference between timecode and our noisemap is that our


noisemap is not a sequential series of markers that the software
counts to know where it is, it’s more a pattern. Imagine that timecode
is like going along a road, and you [need to] pass a certain number of
markers until you know where you are. Our unique noise map is
more like an island – if you’re a fisherman and you know that island
really really well, you can be plonked at any point on that island and
know immediately where you are, it’s more like a map, a picture that
our software knows REALLY well.”

Maybe this is just marketing talk, but this answer suggests that instead
of a one dimensional sequence, like we just obtained, the noisemap
seems to be more akin to a 2d pattern, i.e. a picture. Also, what has
been bothering me is that why does the control signal sound so noisy,
when the frequency spectrum shows only a single tone. So let’s look at
the spectrogram of the signal to see what is happening with the
frequency in relation to time.

First, here is a reference spectrogram for a regular 1 kHz tone:

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 12 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'26 AM

Serato control signal:

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 13 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

There is clearly something interesting going on here. The first Serato


spectrogram looks a little bit like a QR code, and zooming in there
seems to be patterns in the spectrum. This might indeed be what
Serato calls their noisemap. This seems like a good place to stop my
analysis, since everything further would just be pure speculation.

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 14 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

Matlab

Here’s all the Matlab magic:

001 %% SERATO CONTROL SIGNAL ANALYSIS ?


002 % Akseli Lukkarila / DJ Esgrove
003
004 clear all;
005
006 % read audio file, 10 sec sample without the
007 silence in the beginning
008 [xt, Fs] = audioread('Serato_Control_CD.wav',
009 [1363, 1363+10*44100]);
010
011 N = max(size(xt)); % samples
012 Ts = 1/Fs; % sample time
013 t = 0:Ts:(N-1)*Ts; % time vector
014
015 xt = xt/max(xt(:,1)); % normalize to 1
016
017 xleft = xt(1:N)'; % left channel
018 xright = xt(1:N, 2); % right channel
019
020 %% Time plots
021
022 figure();
023 plot(t, xleft); grid on;
024 title({'Serato Control Signal';'left
025 channel'});
026 xlabel('Time (ms)');
027 axis([0 0.1 -1.05 1.05]);
028 set(gca,'XTick',0:0.01:0.1);
029 set(gca,'XTickLabel',{0 10 20 30 40 50 60 70
030 80 90 100});
031 set(gcf, 'PaperUnits','centimeters',
032 'PaperPosition',[0 0 16 9])
033 print(gcf, 'Serato_left', '-dpng', '-r300');
034
035 figure();
036 plot(t, xright, 'r'); grid on;
037 title({'Serato Control Signal';'right
038 channel'});
039 xlabel('Time (ms)');
040 axis([0 0.1 -1.05 1.05]);
041 set(gca,'XTick',0:0.01:0.1);
042 set(gca,'XTickLabel',{0 10 20 30 40 50 60 70
043 80 90 100});
044 set(gcf, 'PaperUnits','centimeters',
045 'PaperPosition',[0 0 16 9])
046 print(gcf, 'Serato_right', '-dpng', '-r300');
http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 15 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

047
048 figure();
049 plot(t, xt); grid on;
050 title({'Serato Control Signal';'stereo'});
051 xlabel('Time (ms)');
052 axis([0 0.1 -1.05 1.05]);
053 set(gca,'XTick',0:0.01:0.1);
054 set(gca,'XTickLabel',{0 10 20 30 40 50 60 70
055 80 90 100});
056 legend('Left', 'Right', 'Location', 'Best');
057 set(gcf, 'PaperUnits','centimeters',
058 'PaperPosition',[0 0 16 9])
059 print(gcf, 'Serato_stereo', '-dpng', '-r300');
060
061 figure();
062 plot(t, xt); grid on;
063 title({'Serato Control Signal';'stereo'});
064 xlabel('Time (ms)');
065 axis([0 0.01 -1.05 1.05]);
066 set(gca,'XTick', 0:0.001:0.01);
067 set(gca,'XTickLabel',{0 1 2 3 4 5 6 7 8 9
068 10});
069 legend('Left', 'Right', 'Location', 'Best');
070 set(gcf, 'PaperUnits','centimeters',
071 'PaperPosition',[0 0 16 9])
072 print(gcf, 'Serato_stereo2', '-dpng', '-
073 r300');
074
075 %% Frequency plots
076
077 % FFT
078 Xf = 2*abs((fft(xleft)/N)); % real part
079 Xf = 20*log(Xf); % dB
080
081 f0 = Fs/N; % frequency resolution (Hz)
082 f1 = 0:f0:(N-1)*f0; % frequency vector
083
084 figure();
085 semilogx(f1, Xf); grid on;
086 title({'Serato Scratch Live Control
087 Signal';'frequency spectrum'});
088 ylabel('Magnitude (dB)');
089 xlabel('Frequency (Hz)');
090 axis([20 20000 -90 3]);
091 set(gca,'XTick',[20 50 100 200 500 1000 2000
092 5000 10000 20000])
093 set(gca,'XTickLabel',{20 50 100 200 500 '1k'
094 '2k' '5k' '10k' '20k'})
095 set(gcf, 'PaperUnits','centimeters',
096 'PaperPosition',[0 0 16 9])

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 16 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

097 print(gcf, 'Serato_fft', '-dpng', '-r300');


098
099 figure(6);
100 plot(f1, Xf); grid on;
101 title({'Serato Scratch Live Control
102 Signal';'frequency spectrum'});
103 ylabel('Magnitude (dB)');
104 xlabel('Frequency (Hz)');
105 axis([900 1100 -90 3]);
106 set(gca,'XTick',[950 1000 1050])
107 set(gca,'XTickLabel',{950 1000 1050})
108 set(gcf, 'PaperUnits','centimeters',
109 'PaperPosition',[0 0 16 9])
110 print(gcf, 'Serato_fft2', '-dpng', '-r300');
111
112 %% Pure sine wave reference
113
114 % export 10 sec clip
115 audiowrite('Serato Control Signal clip.wav',
116 xt, Fs);
117
118 % 1 kHz sine wave for reference
119 sinref = zeros(max(size(t)), 2);
120 sinref(:,1) = sin(2*pi*1000.*t);
121 sinref(:,2) = sin(2*pi*1000.*t);
122 audiowrite('1 kHz sine reference.wav', sinref,
123 Fs)
124
125 %% Spectrograms
126
127 % reference sine
128 figure();
129 spectrogram(sinref(:,1),1024, 512,
130 [],Fs,'yaxis','MinThreshold',-100)
131 title('1 kHz sine, 1024 sample window');
132 axis([0 10 0 2]);
133 set(gcf, 'PaperUnits','centimeters',
134 'PaperPosition',[0 0 16 9])
135 print(gcf, 'Sine_spectrogram1', '-dpng', '-
136 r300');
137
138 figure();
139 spectrogram(sinref(:,1),2^12, 2^11,
140 [],Fs,'yaxis','MinThreshold',-100)
141 title('1 kHz sine, 4096 sample window');
142 axis([0 10 0 2]);
143 set(gcf, 'PaperUnits','centimeters',
144 'PaperPosition',[0 0 16 9])
145 print(gcf, 'Sine_spectrogram2', '-dpng', '-
146 r300');

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 17 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

147
148 % serato
149 figure();
150 spectrogram(xleft(1:441001),1024, 512,
151 [],Fs,'yaxis', 'MinThreshold',-100)
152 title('Serato timecode, 1024 sample window');
153 axis([0 10 0 2]);
154 set(gcf, 'PaperUnits','centimeters',
155 'PaperPosition',[0 0 16 9])
156 print(gcf, 'Serato_spectrogram1', '-dpng', '-
157 r300');
158
159 figure();
160 spectrogram(xleft(1:441001),2^12, 2^11,
161 [],Fs,'yaxis', 'MinThreshold',-100)
162 title('Serato timecode, 4096 sample window');
163 axis([0 2 0 2]);
164 set(gcf, 'PaperUnits','centimeters',
165 'PaperPosition',[0 0 16 9])
166 print(gcf, 'Serato_spectrogram2', '-dpng', '-
167 r300');
168
169 figure();
170 spectrogram(xleft,2^11, 2^10,[],Fs,'yaxis',
171 'MinThreshold',-100)
172 title('Serato timecode, 2048 sample window');
173 axis([0.01 0.2 0 2]);
174 set(gcf, 'PaperUnits','centimeters',
175 'PaperPosition',[0 0 16 9])
176 print(gcf, 'Serato_spectrogram3', '-dpng', '-
177 r300');
178
179 %% Phase shift
180
181 samples90deg = 44100/(4*1000); % samples for
182 1/4 wavelength for 1 kHz sine
183
184 % samples90deg = 11
185
186 % pad right channel 11 samples = 90 deg phase
187 shift backwards
188 % -> waveforms should overlap
189 rightpad = padarray(xright,11,'pre'); % insert
190 11 zeros to beginning
191 padded = rightpad(1:441001);
192
193 figure(5);
194 plot(t, xleft, t, padded); grid on;
195 title({'Serato Scratch Live Control
196 Signal';'padded right channel'});

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 18 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

197 xlabel('Time (ms)');


198 axis([0 0.02 -1.05 1.05]);
199 set(gca,'XTick', 0:0.001:0.02);
200 set(gca,'XTickLabel',{0 1 2 3 4 5 6 7 8 9 10
201 11 12 13 14 15 16 17 18 19 20});
202 legend('Left', 'Right', 'Location', 'Best');
203 set(gcf, 'PaperUnits','centimeters',
204 'PaperPosition',[0 0 16 9])
205 print(gcf, 'Serato_padded', '-dpng', '-r300');
206
207 %% Amplitude shft keying demodulation
208
209 figure();
210 plot(t, xleft); grid on;
211 title({'Serato Control Signal';'Amplitude
212 shift keying'});
213 xlabel('Time (s)');
214 axis([0 0.2 -0.05 1.05]);
215 set(gcf, 'PaperUnits','centimeters',
216 'PaperPosition',[0 0 16 9])
217 print(gcf, 'Serato_ASK', '-dpng', '-r300');
218
219 % 1 kHz period in samples
220 period = 44100/1000; % = 44.1
221
222 figure();
223 plot(xleft); grid on;
224 title({'Serato Control Signal';'amplitude
225 shift keying'});
226 xlabel('Samples');
227 axis([439 1101 -0.05 1.05]);
228 set(gcf, 'PaperUnits','centimeters',
229 'PaperPosition',[0 0 16 9])
230 print(gcf, 'Serato_ASK2', '-dpng', '-r300');
231
232 % simple demodulation assuming every period
233 encodes one bit
234 bit_array = []; a = 1;
235 for i = 2:max(size(xleft))
236 % take one period of signal and convert to
237 bit value
238 if xleft(i-1) < 0 && xleft(i) >= 0
239 period = xleft(a:i); a = i; % one period
if any(period > 0.8) % has a value larger
than 0.8
bit_array = [bit_array 1]; % append 1
else
bit_array = [bit_array 0]; % append 0
end
end

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 19 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

end

% Convert bit array to square wave


representation
square = ones(441,1)*bit_array; % replicate
each value 441 times
square = square(:); % array to column

figure();
s = 1:132000; % sample vector
plot(s, xleft(1:132000)); hold on
plot(s/10, square(1:132000), 'r', 'LineWidth',
0.7); grid on;
title({'Serato Control Signal';'ASK
demodulation'});
xlabel('Bits'); axis([1 2205 -0.05 1.05]);
set(gca,'XTick', 0:44.1:2205);
set(gca,'XTickLabel',[]);
set(gca,'YTick', [0 1]); set(gca,'YTickLabel',
[0 1]);
set(gcf, 'PaperUnits','centimeters',
'PaperPosition',[0 0 16 9])
print(gcf, 'Serato_bitmask', '-dpng', '-
r300');

%% Bit array

x = 0:1:64;
figure();
stem(x, bit_array(1:max(size(x))), 'filled');
grid on;
title({'Serato Control Signal';'bit values'});
xlabel('bit'); axis([0 64 -0.1 1.1]);
set(gca,'XTick', 0:8:64);
set(gca,'YTick', [0 1]); set(gca,'YTickLabel',
[0 1]);
set(gcf, 'PaperUnits','centimeters',
'PaperPosition',[0 0 16 9])
print(gcf, 'Serato_bitvalues', '-dpng', '-
r300');

%% Direction

t = 0:1/60000:0.1;

right = sin(2*pi*1000.*t);
left = sin(2*pi*1000.*t - pi/2);

figure();
plot(t(16:121), left(16:121), 'b'); hold on;

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 20 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

plot(t, right, 'r'); grid on;


title({'Serato Control Signal';'direction
forward'});
xlabel('Time (ms)');
axis([0 0.002 -1.05 1.05]);
set(gca,'XTick',0:0.00025:0.002);
set(gca,'XTickLabel',{0 0.25 0.5 0.75 1 1.25
1.5 1.75 2});
legend('Left', 'Right', 'Location', 'Best');
set(gcf, 'PaperUnits','centimeters',
'PaperPosition',[0 0 16 9])
print(gcf, 'Serato_direction', '-dpng', '-
r300');

Share this:

4 

+ Leave a Reply
Enter your comment here...

* 2 thoughts on “Analysing the Serato


DJ timecode signal”
Reticuli Reply ↓

03.07.2016 at 20:51
Would having the two output signals from the deck/player 180
degrees out of absolute phase (i.e. inverted polarity) cause
Serato to play in reverse? Does its calibration mode and
settings have the ability to compensate for this?

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 21 de 22
Analysing the Serato DJ timecode signal – Esgrove 10/21/17 12'27 AM

Akseli Lukkarila Post author Reply ↓


04.07.2016 at 22:45
I think inverting the polarity of the stereo signal wouldn’t
affect the direction detection, but of course that depends
on how it is implemented in the software. It is definitely
possible to code it so that changing the polarity would not
matter, as the phase shift between the left and right
channel stays the same. It’s worth noting also that 180
degrees of phase shift in either direction is not strictly
speaking the same as inverted polarity, phase shift just
delays or advances the signal, whereas inverting the
polarity means mirroring the signal (negative values
become positive and vice versa). Sure, for a pure sine
tone the end result is essentially the same but for more
complex signals it is not.

If you mean delaying just the other channel, then yes it


will invert the direction. Crossing the inputs (RCA
connectors) does this also, meaning connecting the left
channel to the right channel input and vice versa. There
are no settings to combat this in the software, you just
have to connect everything correctly. If for some reason
the deck is running in the wrong direction, then it can be
fixed by swapping the left and right signal connectors as
mentioned above.

# $ % ( ' · © 2017 Esgrove · Powered by , · Designed with

& the Customizr theme ·

http://www.esgrove.fi/analysing-the-serato-dj-timecode-signal/ Página 22 de 22

Vous aimerez peut-être aussi