SuperCollider: RecordNRT renders wrong duration - debugging

I want to render a sound sequence using RecordNRT.
It already works, but the duration of the rendered file is too short.
var p;
[\BPM, MasterSequencer.instance.globalBPM].postln;
[\BARS, this.bars].postln;
this.sequenceDuration = ((60 / MasterSequencer.instance.globalBPM) * 4) * this.bars;
[\duration, this.sequenceDuration].postln;
SynthDef(\sampler, { |out, buffer, rate=1, amp|
var snd = PlayBuf.ar(2, buffer, BufRateScale.kr(buffer)*rate, doneAction:2);
Out.ar(0, snd * amp)
}).store;
p = Pbind(
\instrument,\sampler,
\rate, this.slider2.value,
\buffer, this.id,
\dur, (1 / this.steps) * 4,
\amp, Pseq(binarySequence) * this.slider1.value,
).asScore(this.sequenceDuration);
p = p.score.insert(1, [0, ["/b_allocRead", this.id, this.samplePath, 0, -1]]);
p.postln;
Dialog.savePanel({ |path,score|
var header = path.basename.split($.);
if(header.size == 1){
header = "WAV";
path = path ++ ".wav";
}{
header = header.last;
};
if(header == "aif"){ header = "AIFF" };
if(header == "aiff"){ header = "AIFF" };
if(header == "wav"){ header = "WAV" };
Score.recordNRT(
p,
path.dirname +/+ path.basename ++ ".osc", path,
headerFormat:header,
duration: this.sequenceDuration
);
The calculation this.sequenceDuration=(60/BPM)*4*bars is right i guess,
this.sequenceDuration=(4*bars)/(BPM/60) would do it as well.
So the imput this.sequenceDurationdoes not match the duration of the outcoming file.
I have no idea what could be the problem. I check the duration and the BPM and the bars by posting them before. I post the duration, everything seems right.
Rendering finishes and the file and it has not the right duration.
File with bars=4 BPM=70 _should be 13.71 sec, but is 11.71 sec long.
File with bars=8 BPM=70 _should be 27.42 sec, but is 23.43 sec long.
File with bars=4 BPM=140 should be 06.85 sec, but is 02.94 sec long.
File with bars=8 BPM=140 should be 13.71 sec, but is 05.87 sec long.
File with bars=4 BPM=120 should be 08.00 sec, but is 04.00 sec long.
File with bars=8 BPM=120 should be 16.00 sec, but is 08.00 sec long.
File with bars=4 BPM=150 should be 06.40 sec, but is 02.56 sec long.
File with bars=8 BPM=150 should be 12.80 sec, but is 05.12 sec long.

You might be seeing a bug which is fixed in the upcoming 3.7 version, in which the last chunk of audio samples failed to get written to disk. The fix was 28th March 2015 here:
https://github.com/supercollider/supercollider/commit/73f779e
3.7 is not out yet but you can build from source or wait for the prerelease.
An obvious workaround is to use longer files than needed, and truncate them afterwards.

Related

How to automatically check time?

Is it possible to automatically check time then execute certain codes?
timer = os.date('%H:%M:%S', os.time() - 13 * 60 * 60 )
if timer == "18:04:40" then
print("hello")
end
I am trying to print hello on "18:04:40" everyday (os.date's time) without setting up a timer (which counts how much time past since the program's initiation) as I can't run the program 24 hours non-stop...
Thanks for reading.
This may not be the best solution but, when using a library like love2d for example you could run something like this:
function love.update(dt)
timer = os.date('%H:%M:%S', os.time() - 13 * 60 * 60 )
if timer >= value then
--stuff here
end
end
Or if you wanna make it so you have a whole number something like
tick = 0
function love.update(dt)
tick = tick + dt
if tick > 1 then
timer = os.date('%H:%M:%S', os.time() - 13 * 60 * 60 )
if timer >= value then
--stuff here
end
end
end
Lua has to check the time in some way.
Without a loop that can be realized with debug.sethook().
Example with Lua 5.1 typed in an interactive Lua (lua -i)...
> print(_VERSION)
Lua 5.1
> debug.sethook() -- This clears a defined hook
> -- Next set up a hook function that fires on 'line' events
> debug.sethook(function() local hour, min, sec = 23, 59, 59 print(os.date('%H:%M:%S', os.time({year = 2021, month = 12, day = 11, hour = hour, min = min, sec = sec}))) end, 'l')
-- just hit return/enter or do other things
23:59:59
5.9 - The Debug Library
https://www.lua.org/manual/5.1/manual.html#5.9

Convert TMediaPlayer->Duration to min:sec (FMX)

I'm working with the TMediaPlayer1 control in an FMX app using C++ Builder 10.2 Version 25.0.29899.2631. The code below runs fine in Win32 and gives the expected result after loading an mp3 file that is 35 minutes, 16 seconds long.
When i run this same code targeting iOS i get the following error:
[bcciosarm64 Error] Unit1.cpp(337): use of overloaded operator '/' is ambiguous (with operand types 'Fmx::Media::TMediaTime' and 'int')
Here is my code that takes the TMediaPlayer1->Duration and converts it to min:sec,
UnicodeString S = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(),"43506.mp3");
if (FileExists(S)) {
MediaPlayer1->FileName = S;
int sec = MediaPlayer1->Duration / 10000000; // <-- this is problem line
int min = sec / 60;
sec = sec - (60 * min);
lblEndTime->Text = IntToStr(min) + ":" + IntToStr(sec);
}
How should i be doing that division?
UPDATE 1: I fumbled around and figured out how to see the values with this code below. When i run on Win32 i get 21169987500 for the Duration (35 min, 16 seconds) and i get 10000000 for MediaTimeScale - both correct. When i run on iOS i get 0 for Duration and 10000000 for MediaTimeScale. But, if i start the audio playing (e.g. MediaPlayer1->Play();) first and THEN run those 2 showmessages i get the correct result for Duration.
MediaPlayer1->FileName = S; // load the mp3
ShowMessage(IntToStr((__int64) Form1->MediaPlayer1->Media->Duration));
ShowMessage(IntToStr((__int64) MediaTimeScale));
It looks like the Duration does not get set on iOS until the audio actually starts playing. I tried a 5 second delay after setting MediaPlayer1->Filename but that doesn't work. I tried a MediaPlayer1->Play(); followed by MediaPlayer->Stop(); but that didn't work either.
Why isn't Duration set when the FileName is assigned? I'd like to show the Duration before the user ever starts playing the audio.

ExSetTimerResolution does not work

I have got Windows XP installed on my computer.
I want my DPC routine to be called every 10 ms.
That is why I wrote this code:
ASSERT( KeGetCurrentIrql() <= APC_LEVEL );
KeRaiseIrql( APC_LEVEL, &level );
resolution = ExSetTimerResolution( 100000, TRUE );
KdPrint((DRIVERNAME " - RESOLUTION = %d\n", resolution));
KeLowerIrql( level );
KeSetTimerEx( &pExt->timer, duetime, 10, &pExt->dpc );
DebugView shows me that return value (RESOLUTION) equals 156250.
As a result my DPC routine is called every 15.5 ms
What am I doing wrong?
Out of curiosity I tried ExSetTimerResolution with different values.
Here is what I got:
10000 -> 9766
50000 -> 39063
75000 -> 39063
90000 -> 156250
Left column contains values that I used as DesiredTime parameter.
Right column contains return values.
As you can see, it looks like Windows cannot change global timer resolution to any desired number.

Ruby time subtraction

There is the following task: I need to get minutes between one time and another one: for example, between "8:15" and "7:45". I have the following code:
(Time.parse("8:15") - Time.parse("7:45")).minute
But I get result as "108000.0 seconds".
How can I fix it?
The result you get back is a float of the number of seconds not a Time object. So to get the number of minutes and seconds between the two times:
require 'time'
t1 = Time.parse("8:15")
t2 = Time.parse("7:45")
total_seconds = (t1 - t2) # => 1800.0
minutes = (total_seconds / 60).floor # => 30
seconds = total_seconds.to_i % 60 # => 0
puts "difference is #{minutes} minute(s) and #{seconds} second(s)"
Using floor and modulus (%) allows you to split up the minutes and seconds so it's more human readable, rather than having '6.57 minutes'
You can avoid weird time parsing gotchas (Daylight Saving, running the code around midnight) by simply doing some math on the hours and minutes instead of parsing them into Time objects. Something along these lines (I'd verify the math with tests):
one = "8:15"
two = "7:45"
h1, m1 = one.split(":").map(&:to_i)
h2, m2 = two.split(":").map(&:to_i)
puts (h1 - h2) * 60 + m1 - m2
If you do want to take Daylight Saving into account (e.g. you sometimes want an extra hour added or subtracted depending on today's date) then you will need to involve Time, of course.
Time subtraction returns the value in seconds. So divide by 60 to get the answer in minutes:
=> (Time.parse("8:15") - Time.parse("7:45")) / 60
#> 30.0

Rolling list over unequal times in XTS

I have stock data at the tick level and would like to create a rolling list of all ticks for the previous 10 seconds. The code below works, but takes a very long time for large amounts of data. I'd like to vectorize this process or otherwise make it faster, but I'm not coming up with anything. Any suggestions or nudges in the right direction would be appreciated.
library(quantmod)
set.seed(150)
# Create five minutes of xts example data at .1 second intervals
mins <- 5
ticks <- mins * 60 * 10 + 1
times <- xts(runif(seq_len(ticks),1,100), order.by=seq(as.POSIXct("1973-03-17 09:00:00"),
as.POSIXct("1973-03-17 09:05:00"), length = ticks))
# Randomly remove some ticks to create unequal intervals
times <- times[runif(seq_along(times))>.3]
# Number of seconds to look back
lookback <- 10
dist.list <- list(rep(NA, nrow(times)))
system.time(
for (i in 1:length(times)) {
dist.list[[i]] <- times[paste(strptime(index(times[i])-(lookback-1), format = "%Y-%m-%d %H:%M:%S"), "/",
strptime(index(times[i])-1, format = "%Y-%m-%d %H:%M:%S"), sep = "")]
}
)
> user system elapsed
6.12 0.00 5.85
You should check out the window function, it will make your subselection of dates a lot easier. The following code uses lapply to do the work of the for loop.
# Your code
system.time(
for (i in 1:length(times)) {
dist.list[[i]] <- times[paste(strptime(index(times[i])-(lookback-1), format = "%Y-%m-%d %H:%M:%S"), "/",
strptime(index(times[i])-1, format = "%Y-%m-%d %H:%M:%S"), sep = "")]
}
)
# user system elapsed
# 10.09 0.00 10.11
# My code
system.time(dist.list<-lapply(index(times),
function(x) window(times,start=x-lookback-1,end=x))
)
# user system elapsed
# 3.02 0.00 3.03
So, about a third faster.
But, if you really want to speed things up, and you are willing to forgo millisecond accuracy (which I think your original method implicitly does), you could just run the loop on unique date-hour-second combinations, because they will all return the same time window. This should speed things up roughly twenty or thirty times:
dat.time=unique(as.POSIXct(as.character(index(times)))) # Cheesy method to drop the ms.
system.time(dist.list.2<-lapply(dat.time,function(x) window(times,start=x-lookback-1,end=x)))
# user system elapsed
# 0.37 0.00 0.39

Resources