I want to make a simple editor to shift subtitle times around. A Subtitle of WebVTT is made of chunks like this:
1
00:02:15.000 --> 00:02:20.000
- Hello World!
So as you can see there is a time that the subtitle will apear and a time that it dissapears. This time is also can be clicked to jump to that specific point of the video file.
Now I want to create a simple application that can shift these times by a given amount to left or right in time domain. What would be the best way to store these timepoints for making easy calculation and changes?
For example:
struct SubtitleElement {
std::chrono< ?????? > begin; // What is a good candidate here?
std::chrono< ?????? > end; // What is a good candidate here?
std::string text;
}
Later I want to have functions that operate on these elements. E.g.:
void shiftTime(SubtitleElement element, int millisecs) {
// reduce begin and end of the element by millisecs
}
DURATION getDuration(SubtitleElement& element) {
//return end - begin
}
DURATION totalDuration(vector<SubtitleElement> elements) {
// sum all the durations of the elements in vector
}
So what would the most clean and modern way of doing this? Also important is that it will be easy to convert the string "hh:mm:ss:ZZZ" to that member. Please note that I think the hh can be much more than 24, because its amount of time, not time of the day! E.g. a vido file can be 120 hours long!!
Since these are time points relative to the beginning of the video, not to some clock, I suggest keeping it simple and using std::chrono::milliseconds. They support all operations you require, except im not sure there is an existing implementation for parsing them from a string. But that should be very easy to build.
Related
I'm using 3 command line tools via QProcesses to play music on my Linux (Mint) desktop via the Jack server. It's all working very well, but the input from one of the tools 'jack_showtime' arrives at about 12,000 lines per second.
I only need to see one line every 0.1 seconds, but the only way I've found to get a full recent line is like:
j_s->readAll(); // j_s is the jack_showtime QProcess
waitAbit(20); // a 20 mS delay
QString aShowtimeLine = j_s->readLine();
aShowtimeLine = j_s->readLine();
What would be a better way to deal with so much unwanted input? It seems that; without the readAll, a line will be much too old. Without the delay, I get a blank line and without the two readLines I get part of a line.
I'd also be interested in a Bash script that could absorb most of the input, or similar.
I suggest something like this, such that no matter how fast or how slow you get input from the child process, you always use the only most recent value, every 100mS:
// at startup or in your class constructor or wherever
connect(j_s, SIGNAL(readyRead()), this, SLOT(ReadDataFromJack()));
connect(&_myQTimer, SIGNAL(timeout()), this, SLOT(UseOneLine()));
_myQTimer.start(100);
void MyClass :: ReadDataFromJack()
{
while(j_s->canReadLine())
{
char buf[1024];
qint64 bytesRead = j_s->readLine(buf, sizeof(buf));
if ((bytes > 0)&&(CanParseText(buf))
{
this->_mostRecentResult = ParseText(buf);
}
}
}
void MyClass :: UseOneLine()
{
printf("100mS have elapsed, time to use _mostRecentResult=%i for something!\n", this->_mostRecentResult)
}
(Note that CanParseText(buf) and ParseText(buf) above are imaginary placeholders for whatever code you use to parse ASCII text coming from your child process into data to be used by your program)
Bulls eye! Thank you. You seem to know what I already had, so it was easy to add the bits I didn't have. Mainly the limited size buffer and, as I've never seen a line longer than 79 characters, I reduced it to 100. I may have been on the right track, while looking for a script solution, when I tried to use 'stdbuf', but dealing with it all in my program is much better.
Lines received are easy to parse. I only want the first number (which can be as low as zero) from something like this:
frame = 293532731 frame_time = 114978548 usecs = 2421437949 state: Rolling
I use the following, which seems reasonably minimal:
QString recentLine = QString::fromLocal8Bit(buf);
recentLine.remove(0,8);
recentLine.chop(recentLine.length() - recentLine.indexOf(" "));
int numSamples = recentLine.toInt();
I put a counter in the ReadDataFromJack() class and see between 2,000 and 3,000 visits per 100mS!
The number represents the position of the 'play head' in samples (at 48k per second) and wont exceed the integer range in Qt, but I see you use a qint64 (long long) in your example. Should I do the same for my number?
Sorry it's an answer (and a further question), but it's too long for a comment.
I am not hugely experienced in C++ coding, but I learn pretty well as I go. But, I have not been able to properly query how to do this, may be using wrong terms or insufficiently expressing my desire. Here's the situation.
I have a lot of variables (3x12) that I have set up under a structure:
struct Tracking
{
String Title;
BoolArray n24hr;
bool State;
unsigned char Days, Weeks;
uint16_t Minutes, TotalMinutes, Daily, Weekly, Monthly, n7d[7], n4w[4];
} Components[3];
I also have code that performs basically the same thing 3 times but on different "levels", e.g. daily, weekly, monthly. It keeps tracks of status over those time periods, filling arrays, finding totals, and duty cycles, etc. It fills the minutes into days, and when that reaches a week, it puts the totals into a week format, and repeats until it reaches monthly levels. So basically, I have it doing something like:
in my main loop:
//calls status formula
StatusFormula();
in a separate file:
//status formula defined
void StatusFormula()
{
// for each element of Components:
//determine current status
//for daily
//add it to the correct spot in the array
//perform calculations on it
//when it reaches a week:
//add it to the correct spot in the next array
//perform calculations on it
//when it reaches a month:
//add it to the correct spot in the next array
//perform calculations on it
}
These calculations are all basically the same, the only differences are the structure member names & the constants for the calculations (i.e., MinsADay, DaysAWk, etc.).
I can get it to work this way, it just means a lot more lines and if I want to change something, I have to repeat it 3 times. What I want is something like this:
in my main loop:
//calls status formula
StatusFormula("Daily"); //sends the status formula information to decide which level (daily, weekly, monthly), it supposed to work on
if (Components[i].Minutes == MinsADay)
{
StatusFormula("Weekly"); //sends the status formula information to decide which level (daily, weekly, monthly), it supposed to work on
if (Components[i].Daily == DaysAWk)
{
StatusFormula("Monthly");
}
}
in a separate file:
//status formula defined
void StatusFormula()
{
//determine which level & variables to use (I would probably use case for this), then
//add it to the correct spot in the correct array
//perform calculations on it
}
I tried passing the level using a string, but it didn't work:
in my main loop:
StatusFormula(i, "Daily"); //sending data to formula, where i is value 0 to 2 for the Components array & defined earlier in the for loop.
in a separate file:
//formula defined as:
void StatusFormula(uint8_t counter, string level)
{Components[counter].level -= //etc... performing calculations as desired.
//so I thought this should evaluate to "Components[i].Daily -=" (& i would be a value 0 to 2) & treat it like the structure, but it doesn't work that way apparently.
I tried passing the structure & variable itself, but that didn't work either:
in my main loop:
StatusFormula(i, Components[i].Daily); //sending data to formula
in a separate file:
//formula defined as:
void StatusFormula(uint8_t counter, Tracking& level)
{level -= //etc... //(level should be Components[i].Daily -=" (& i would be a value 0 to 2)) this didn't work either.
I couldn't find any google searches to help me, and I trialed-and-errored a bunch of ways, but I couldn't figure out how to do that in C++, let alone on the Arduino platform. In Excel VBA, I would just have the variable passed as a string to the formula, which would substitute the word and then treat it like the variable that it is, but I couldn't make that happen in C++. Also to note, I am going to try and define this a separate file/tab so that my massive code file is easier to read/edit, in case that makes a difference. I would paste my code directly, but it is long and super confusing.
I guess what I am asking is how would I pass the structure and/or structure member to the formula in a way that would say the equivalent of:
case 1: //"Daily"
//use Components[i].Daily & Components[i].Minutes & MinsaDay
break;
case 2: //"Weekly"
//use Components[i].Weekly & Components[i].Days & DaysaWk
break;
//etc.
I feel like there should be a way & that I am just missing a small, vital piece. Several people in the comments suggested enums, and after researching, it might possibly be what I want, but I am having trouble visualizing it at the moment and need to do more research and examples. Any suggestions or examples on how to send the appropriate structure & members to the formula to be modified in it?
I am using a chrono to get the time elapsed during a loop. I would like to display this time every loop run.
I can do this:
for(int i = 0;i<3;i++)
{
sleep(2 secs);
time= get_time();
cout<<"time is : "<<time;
}
But I have the output:
time is : 2 time is : 4 time is : 6
I could add an endl to have it in column but that is not what I want. My loop is about million times, so I don't really want to print a million lines.
I would just like to print like:
time is : 2
and then refresh it to
time is : 4
and so on. Is there a way to do this?
You can use endl with clrscr() .
printing to terminals is very easy, but it can be extremely hard at the same time. At its core, a terminal is simply a file, that you can use to write or read on. Performing tasks such as changing cursor's position is in fact system-specific and your code will have to be platform dependent.
But don't panic! People have done it before and even wrote libraries to do it. I think NCurses will do the job. https://www.gnu.org/software/ncurses/ncurses.html
I advice you to refer to this thread to see some issue related to your question: How to clear a specific line with NCurses?
I have never used ncurses my self, so I wish you best of luck!
Enjoy programming!
I am debugging some simulation software that has been written partly in C++ and partly in Ada. On the GUI, there are two values displaying the ETA & TimeToGo of an entity moving in the simulation on any given leg of its journey, and for the remainder of the whole journey. The TimeToGo & ETA values that are displayed for the current leg are correct (i.e. how long it will take the entity to reach its current target destination from its current location). However, the TimeToGo & ETA values for the remainder of the whole journey are incorrect- approximately 40-50s lagging behind.
I have come across a couple of assignments in the code, and I am wondering if they are the wrong way round:
if(some condition){
mFlightPlanData[0] = fpMiniToteData;
} else {
mFlightPlanData[1] = fpMiniToteData;
}
mFlightPlanData[] is an array of flightPlans, of size 2- because each aircraft can have up to two flight plans at any one time- a primary and a secondary. fpMiniToteData is the variable used to display the flight plan data on the GUI.
Now, it appears to me that these assignments are the wrong way round- these seem to be saying:
Set the first element in the flight plan array equal to the value of the display data
else
Set the second element in the flight plan array equal to the value of the display data
However, what should be happening is that the display data should be being set to the value of either the first or second element in the flight plan array...
I tried to do this, by switching the assignments around, i.e.
if(some condition){
fpMiniToteData = mFlightPlanData[0];
} else {
fpMiniToteData = mFlightPlanData[1];
}
But I now get a compile error that says:
error C2678: binary '=': no operator found which takes a left-hand operand of type 'const...' or there is no acceptable conversion)
What does this error mean? Do I need to have defined a function that will convert the data type held in the array to the data type of the fpMiniToteData?
Any help would be much appreciated.
Edit 12/02/2015 # 1645
fpMiniToteData is defined in the function definition- the function that the code above belongs to:
void FlightPlanInterface::setFlightPlanData(
const FlightPlanMinitoteTypes::FlightPlanPerformanceDataViewId_Type viewId,
const FlightPlanMinitoteTypes::FlightPlanMinitoteData_Variant& fpMiniToteData)
{
and mFlightPlanData is defined in a header file as follows:
private:
FlightPlanMinitoteTypes::FlightPlanMinitoteData_Variant mFlightPlanData[2];
I've read about the solutuon written here on a post a year ago
wx.TextCtrl.LoadFile()
Now I have a windows application that will generate color frequency statistics that are saved in 3D arrays. Here is a part of my code as you will see on the code below the printing of the statistics is dependent on a slider which specifies the threshold.
void Project1Frm::WxButton2Click(wxCommandEvent& event)
{
char stat[32] ="";
int ***report = pGLCanvas->GetPixel();
float max = pGLCanvas->GetMaxval();
float dist = WxSlider5->GetValue();
WxRichTextCtrl1->Clear();
WxRichTextCtrl1->SetMaxLength(100);
if(dist>0)
{
WxRichTextCtrl1->AppendText(wxT("Statistics\nR\tG\tB\t\n"));
for(int m=0; m<256; m++){
for(int n=0; n<256; n++){
for(int o=0; o<256; o++){
if((report[m][n][o]/max)>=(dist/100.0))
{
sprintf(stat,"%d\t%d\t%d\t%3.6f%%\n",m,n,o,report[m][n][o]/max*100.0);
WxRichTextCtrl1->AppendText(wxT(stat));
}
}
}
}
}
else if(dist==0) WxRichTextCtrl1->LoadFile("histodata.txt");
}
The solution I've tried so far is that when I am to print all the statistics I'll get it from a text file rather than going through the 3D array... I would like to ask if the Python implementation of the segmenting can be ported to C++ or are there better ways to deal with this problem. Thank you.
EDIT:
Another reason why I used a text file instead is that I observed that whenever I do sprintf only [with the line WxRichTextCtrl1->AppendText(wxT(stat)); was commented out] the computer starts to slow down.
-Ric
Disclaimer: My answer is more of an alternative than a solution.
I don't believe that there's any situation in which a user of this application is going to find it useful to have a scrolled text window containing ~16 million lines of numbers. It would be impossible to scroll to one specific location in the list that the user might need to see easily. This is all assuming that every single number you output here has some significance to the user of course (you are showing them on the screen for a reason). Providing the user with controls to look up specific, fixed (reasonable) ranges of those numbers would be a better solution, not only in regards to a better user experience, but also in helping to resolve your issue here.
On the other hand, if you still insist on one single window containing all 64 million numbers, you seem to have a very rigid data structure here, which means you can (and should) take advantage of using a virtual grid control (wxGrid), which is intended to work smoothly even with incredibly large data sets like this. The user will likely find this control easier to read and find the section of data they are looking for.