How can I display progress and track length in the video stream of LiquidSoap - liquidsoap

I want to create a audio-video stream using Liquidsoap. And display the progess and total time of current track in the video. I wonder what is the best practice to achieve this. I am current using the following methods, in which:
Current progress is acquired with source.remaining function.
Total length is a global variable track_length, which is modified in on_track callback.
However, the current method has the following problems:
The return value of source.remaining does not change in a constant speed, as in the document metioned "estimation remaining time". In can be 19min, and suddenly jump to 19min20s, and then jump to 18min50. However, as the remaining time is less and less, the estimation becomes more accurate.
The track_length variable does get modified after the current track begins. However, the text drawing function which fetches the variable always get the initial value and never changed.
Thanks for your help!
Here is the relavant part of my script:
# Define the global variable to store the length of current track
track_length = 0
# Define the on_track callback which updates track_length
def process_metadata(metadata)
file_name = metadata["filename"]
track_length = file.duration(file_name)
end
# Define the audio source and hook on_track callback
audio = fallback([sequence([
single("/etc/liquidsoap/lssj1.mp3")
])])
audio = on_track(process_metadata, audio)
# Define the function which returns the text to render
def get_time()
"$(cur)/$(total)" % [("cur", string_of(source.remaining(audio))), ("total", string_of(track_length))]
end
# Create the video frame
video = fallback([blank()])
video = video.add_text.sdl(x=0, y=300, size=40, get_time, video)

There is no such term 'global variable' in liquidsoap
No assignment, only definitions. x = expr doesn't modify x, it just defines a new x. The expression (x = s1 ; def y = x = s2 ; (x,s3) end ; (y,x)) evaluates to ((s2,s3),s1).
Link: https://www.liquidsoap.info/doc-dev/language.html
So, you should use references:
Define:
track_length = ref 0
then modify it (note we also use int_of_float):
track_length := int_of_float(file.duration(file_name))
then get its value:
!track_length
I believe it will fix your problems

Related

Create an array that grows at a regular interval on Matlab

I have been thinking about how to create an array that grows at a regular interval of time (for instance every 5 seconds) on Matlab.
I figured out 2 ways, either using tic/ toc or timer function. Later this program will be complexified. I am not sure which way is the best but so far I am trying with using timer.
Here is what I have tried :
clc;
period=5;%period at which the file should be updated
freq=4;
l=freq*period;
time=[0];
a = timer('ExecutionMode','fixedRate','Period',period,'TimerFcn',{#time_append, time,l,freq},'TasksToExecute',3 );
start(a);
function [time]=time_append(obj,event,time,l,freq)
time_append=zeros(l,1);
last_time=time(end)
for i=1:1:l
time_append(i)=last_time+i/freq;
end
time=[time;time_append];
end
After compiling this code, I only get a time array of length 1 containing the value 0 wheras it should contain values from 0 to 3x5 =15 I think it is a stupid mistake but I can't see why. I have tried the debug mode and it seems that at the end of the line time=[time;time_append], the concatenation works but the time array is reinitialised when we go out of the function. Also I have read that callback function can't have output. Does someone would know how I could proceed? Using globals? Any other suggestion?
Thank you for reading
You can do this by using nested functions. Nested functions allow you to access "uplevel variables", and you can modify those. Here's one way to do it:
function [a, fcn] = buildTimer()
period=5;%period at which the file should be updated
freq=4;
l=freq*period;
time=0;
function time_append(~,~,l,freq)
time_append=zeros(l,1);
last_time=time(end);
for i=1:1:l
time_append(i)=last_time+i/freq;
end
time=[time;time_append];
end
function out = time_get()
out = time;
end
fcn = #time_get;
a = timer('ExecutionMode','fixedRate',...
'Period',period,...
'TimerFcn',{#time_append,l,freq},...
'TasksToExecute',3 );
start(a);
end
Note that the variable time is shared by time_append and time_get. The timer object invokes time_append, and updates time. You need to hand out the function handle time_get to retrieve the current value of time.
>> [a,fcn] = buildTimer; size(fcn()), pause(10); size(fcn())
ans =
21 1
ans =
61 1

Can't get variable out of Callback function. Already defined as global. Matlab

I have a serialport bytesavailable callback function.
function readFrame(src,~)
global data
global payloadBytes
message = read(src,payloadBytes,"uint8");
src.UserData = message;
data = message;
return
I read the buffer into the variable message and then save it as global variable data.
i get the variable in my workspace. Then something happens that I can't explain. I try to save this global variable in a local variable in my Mainscript. Notice: global data is defined in mainscript.
global data;
global payloadBytes;
msg=[];
frameCount = 1;
numFrames = 10;
messageByte = zeros(numFrames,payloadBytes)
while(app)
%wait till callback triggered and serial data read
while isempty(msg)
%save global variable data in local variable msg
msg = data;
disp("wait for data")
end
%save msg in an expanding 2D Variable messagebyte
messageByte(frameCount,:) = msg;
%empty msg variable
msg =[]
frameCount = frameCount +1
%stop when 10 frames are caught
if frameCount == 11
app = 0;
end
end
Problem is processedData is always empty. So when i want to make a 2D Matrice to save different data like this:
processedData(frameCount,:) = data;
I get an exception: indices doesn't match. Thats no wonder.
Can somebody tell me what I am doing wrong.
Thank you.
MATLAB is single-threaded. Stuff doesn’t run in parallel unless you explicitly use the Parallel Processing Toolbox. So for your callback to write to data, your main loop must give the callback a chance to execute. Add a pause to your loop, this will allow callbacks to execute, as well as timer objects.
while isempty(msg)
pause(0.1) % find a suitable pause length here
%save global variable data in local variable msg
msg = data;
disp("wait for data")
end
The pause doesn’t need to be long, but make it as long as you can tolerate, since that will make your wait less processor intensive.

How to automatically change variable names given a new input file name

I am importing data from a .mat file and then extracting certain signals from it and I call this data, data. data is a 1x1 struct with 1 field, FT_est_X, where X is the the particular run that I collected the samples from. Here is the code snippet of how I do that.
data = load('site_data_all_2.mat');
t = data.FT_est_2.time;
% estimated data
Fx = data.FT_est_2.signals(1).values;
Fy = data.FT_est_2.signals(2).values;
Fz = data.FT_est_2.signals(3).values;
Mx = data.FT_est_2.signals(4).values;
My = data.FT_est_2.signals(5).values;
Mz = data.FT_est_2.signals(6).values;
So, you can see that this data was collected from run 2. Now, let's say I want to load in a file named site_data_all_3.mat (run 3), what happens is that all the data below %estimated data changes its name--everything stays the same, except the 2 becomes a 3 (e.g. Fx would be Fx = data.FT_est_3.signals(1).values;. Currently, I have to manually enter in the 3 for each variable; can anyone tell me how I can only change the file name and it will automatically change the variable names for me? Essentially, I just want it to be Fx = data.name_of_struct_field.signals(1).values.
Thank you!
You could construct the string some programmatic way (maybe with an iteration variable), but here's the simple answer of defining the fieldname as a string and simply using it. At the next iteration, update the fieldname variable and repeat.
fieldname = 'FT_est_2';
Fx = data.(fieldname).signals(1).values;

Will returned array be copied by value or returned as reference in MATLAB?

I wanted to ask how values in MATLAB are returned? Are they copied or passed by reference?
take a look at this example with matrix A:
function main
A = foo(10);
return;
end
function [resultMatrix] = foo(count)
resultMatrix = zeros(count, count);
return;
end
Does the copy operation take place when function returns matrix and assigns it to variable A ?
MATLAB uses a system known as copy-on-write in which a copy of the data is only made when it is necessary (i.e. when the data is modified). When returning a variable from a function, it is not modified between when it was created inside of the function and when it was stored in a different variable by the calling function. So in your case, you can think of the variable as being passed by reference. Once the data is modified, however, a copy will be made
You can check this behavior using format debug which will actually tell us the memory location of the data (detailed more in this post)
So if we modify your code slightly so that we print the memory location of each variable we can track when a copy is made
function main()
A = foo(10);
% Print the address of the variable A
fprintf('Address of A in calling function: %s\n', address(A));
% Modify A
B = A + 1;
% Print the address of the variable B
fprintf('Address of B in calling function: %s\n', address(B));
end
function result = foo(count)
result = zeros(count);
% Print the address of the variable inside of the function
fprintf('Address of result in foo: %s\n', address(result));
end
function loc = address(x)
% Store the current display format
fmt = get(0, 'format');
% Turn on debugging display and parse it
format debug
loc = regexp(evalc('disp(x)'), '(?<=pr\s*=\s*)[a-z0-9]*', 'match', 'once');
% Revert the display format to what it was
format(fmt);
end
And this yields the following (or similar) output
Address of result in foo: 7f96d9d591c0
Address of A in calling function: 7f96d9d591c0
Address of B in calling function: 7f96d9c74400
As a side-note, you don't need to explicitly use return in your case since the function will naturally return when it encounters the end. return is only necessary when you need to use it to alter the flow of your program and exit a function pre-maturely.

Race condition using a code segment

Please help me to get an idea to solve this question.I have tried several sequence to race condition, but i couldn't get a correct one.
every time the value of x is same.
This is the way I've tried
Under the assumption that a line isn't to be considered an atomic operation, you can split up any of the lines modifying x based on its own value into a read and write part. Doing this only for one, for example from the increase function, yields:
y = 5;
int temporary = x; // read value
temporary += y;
x = temporary; // write modified value back
x++; // this could be split up similarly
z = /* whatever */;
With this "expanded" code sequence you should have no problem finding sequences of operations with different result values for x.