I have made good progress on my video analysis tool. So much so that I feel upgrading its status to "version 0.2.0" is warranted. Here are the major tasks I've tackled:
Please note that I won't be providing any LiveCode files to download as I did in previous posts for this project. For each of those posts, I had created a second and unique version of the project to make clearer the various LiveCode skills and principles I was demonstrating. The project has now progressed to the point where continuing to update and share this second LiveCode file is too time prohibitive. However, I'll continue to share important code where appropriate. And, I think those previous files will help anyone just getting into the use of video within LiveCode.
In the previous versions, the user could only add one tag per clip. I knew all along this would be insufficient. Of course, any one video clip could have many tags or no tags, so I needed to account for an uneven number in the design. I debated on the best way to approach this, deciding in the end to just have the tags continue to be added as separate items in the field "log." Doing so created a dilemma about where to put the user comments as they had been also part of this field. I decided to create a separate field for "project comments." This opened up other possibilities for comments, which I'll discuss later in this blog posting.
In previous posts I described the basics of how the tagging system works. Recall that users can create a list of unique tags. Each tag is just a copy and paste of a template button found on the "Library" card where the name and label of the button is changed to whatever tag name the user entered. I revised the script of that template button:
global gActivity
on mouseUp
//Check to make sure that a clip has been chosen
if the selectedtext of field "log2" is empty then
answer "You first have to select an entry from the log."
exit mouseUp
end if
put the label of me into gActivity
put the hilitedLine of field "log2" into l // read as "line lower case L"; assume this in remaining lines
//count the number of items in the line
put the number of items of line l of field "log" into varItemsCount
//check to see if tag is already there
repeat with i = 5 to varItemsCount
if gActivity = item i of line l of field "log" then
set the hilitedLine of field "log2" to l
exit mouseUp
end if
end repeat
put the label of me into item varItemsCount+1 of line l of field "log"
//Update the display of tags
put "Tags: " into varShowTags
put the number of items in line l of field "log" into varItemsCount
if varItemsCount<5 then put "Tags: No tags for this clip" into varShowTags
//all tags begin with item 5
repeat with i = 5 to varItemsCount
put varShowTags&item i of line l of field "log" into varShowTags
if i<varItemsCount then put varShowTags&", " into varShowTags
end repeat
put varShowTags into line 1 of field "Tags"
set the hilitedLine of field "log2" to l
end mouseUp
The commented lines show the main parts of this script. It begins by checking to see if the user has chosen a clip and if not, it reminds the user to do so, followed by the command "exit mouseUp." This command tells LiveCode to do just that, exit the script triggered by the mouseUp without executing any other of the lines that follow. I highlighted this line in red. (Notice that I use this command again later in the script.)
The next task is to see if the user has already chosen that tag because we obviously don't want duplicate tags listed for a clip. First, I check to see how many items are in the highlighted line of field "log" and store this number in the local variable "varItemsCount." That number will be used for the upper limit of a repeat loop coming up, plus we will use it to determine where to put the next unique tag.
Next is the repeat loop, triggered by this line:
repeat with i = 5 to varItemsCount
The local variable i increments by one in each loop, starting with 5 and ending with the value in varItemsCount. I start with 5 because I know the first four item slots are already taken. Item 1 now contains a clip number and item 2 now contains a short description of the clip -- two things I address briefly below. Items 3 and 4 contain the starting and ending time code of the clip in user friendly terms (this was the subject of my most previous post). This repeat loop then checks to see if the tag button just pressed matches any of the tags listed in items 5 and onward. If it finds a match, it exits the mouseUp script. If it doesn't, it adds this tag as the very next item (i.e. varItemsCount + 1).
The next block of script updates the display of the tags in the video clip dashboard. This dashboard is a new feature. Let's address that next.
One of the big improvements in version 0.2.0 is the video clip dashboard. Recall that I included some screen placeholders for this video dashboard in the previous versions of the prototype. Well, I finally tackled the implementation of the dashboard here.
I created four fields for the dashboard titled "time code," "Description," "tags," and "display comment." These four fields are populated with the respective information. To populate the tags field, I use another repeat loop to create a string variable called "varShowTags." This contains a list of all the tags with a comma and space in-between, all concatenated as the repeat loops works its magic.
The script ends by highlighting the video clip line in the field "log2."
Let's continue to look at the video clip dashboard. When the user clicks on a video entry in the field "log2," the dashboard immediately updates with the information for that clip using the following script attached to the field itself:
on mouseDown
if the number of lines in me is 0 then exit mouseDown
stop player "player"
set the playSelection of player "player" to true
put the hilitedLine of me into l
set the currentTime of player "player" to item 3 of line l of field "log"
displayClipInformation l
displayComment l
end mouseDown
Yes, that's right, you can treat a field like a button and have events triggered if it is clicked. This short script does a lot, thanks to two new commands I created titled "displayClipInformation" and "displayComment." Commands are close relatives to functions. The idea is the same -- you are inventing your own vocabulary and adding them to LiveCode's dictionary. The difference is that a command simply does something without returning any value like a function would (review my description of functions in my previous post). The command displayClipInformation does some magic to populate the fields "time code," "Description," and "tags." The function displayComment is used to populate the field "display comment." Both functions are shown below in their entirety, but I won't try to describe them in any depth here.
Let's address the design behind the improvement to user comments. I knew I needed to give the user the opportunity to make in-depth comments about any of the clips. This would have to include a basic narrative structure using sentences and paragraphs, along with standard narrative symbols, such as commas and periods. It was clear that the only way to do this was by creating yet another field titled "Project Comments" to store the comments. The tricky part is connecting the right comment to the correct video clip. Since any one comment would potentially contains multiple lines, perhaps dozens, some sort of indexing system would be needed beyond just using the line number of the clip in the field "log2."
So, I used an approach that is adapted from how relational database work. I merely created an indexing system where each clip gets a unique number. I then put the term "VATComment" as item 1 on a line and the index number as item 2 on the very same line. That way, every time the user clicks on a video entry LiveCode searches the "Project Comments" field for that term as item 1 on a line. If it finds it, it then notes the index number. All lines after that and up to the next time the term VATComment is found (or the end of the field is reached), is assumed to be the entire comment for that video clip. Pretty clever if I say so myself.
I also had to design a way for a user to update a particular comment. The best strategy I came up with was to create yet another command to first "seek out and destroy"all lines associated with a particular comment when the user updates a comment, followed immediately by creating a new set of lines for the updated comment. In a sense, every update is really a new comment, as far as LiveCode is concerned. This command is titled "deleteComment" and I've also listed the entire script below.
I also wrote a bunch of other small scripts here and there to have everything run smoothly and to catch user errors. It's really amazing the number of situations one must address when trying to anticipate a user's interaction.
One thing I have not yet done is program a way for the user to delete tags. That will come in the next version of the program. I'm currently mulling over a few ways of doing this, so you'll have to check back later to see how I decide to tackle this issue. Also, I think it is high time I address the need to let the user select any video for analysis. Yes, it is time to put my placeholder video to rest. But, you can always view it here if you miss it.
Appendix: Scripts for the Commands "displayClipInformation" and "displayComment"
Both scripts are defined in the card script. Both scripts take the number corresponding to the selected video clip as input.
command displayClipInformation videoEntryLine
//Display entry information
put videoEntryLine into l
put item 2 of line l of field "log" into field "Description"
//Construct time code string
put the timescale of player "Player" into ts
put item 3 of line l of field "log" into tcStart
put item 4 of line l of field "log" into tcEnd
put (tcEnd - tcStart)/ts into varCliplength
put round(varCliplength,1) into varCliplength
put convertTimeCode (tcStart) into tcStart2
put convertTimeCode (tcEnd) into tcEnd2
put "Clip length: "&tcStart2&" to "&tcEnd2&" ("&varCliplength&" sec)" into line 1 of field "Time Code"
//Determine tags for display
put "Tags: " into varShowTags
put the number of items in line l of field "log" into varItemsCount
if varItemsCount<5 then put "Tags: No tags for this clip" into varShowTags
//all tags begin with item 5
repeat with i = 5 to varItemsCount
put varShowTags&item i of line l of field "log" into varShowTags
if i<varItemsCount then put varShowTags&", " into varShowTags
end repeat
put varShowTags into line 1 of field "Tags"
end displayClipInformation
command displayComment videoEntryLine
put empty into field "display comment"
put videoEntryLine into l
put item 1 of line videoEntryLine of field "log" into videoEntryNumber
repeat with i = 1 to the number of lines in field "project comments"
if item 1 of line i of field "project comments" is "VATComment" and item 2 of line i of field "project comments" is videoEntryNumber then
put line i+1 of field "project comments" into line 1 of field "display comment"
repeat with j = i+2 to the number of lines in field "project comments"
if item 1 of line j of field "project comments" <> "VATComment" then
put line j of field "project comments" into line (number of lines in field "display comment"+1) of field "display comment"
else
exit displayComment
end if
end repeat
exit displayComment
end if
end repeat
put "No comments yet for this video entry" into line 1 of field "display comment"
end displayComment
command deleteComment videoEntryLine
//put empty into field "display comment"
put videoEntryLine into l
put item 1 of line videoEntryLine of field "log" into videoEntryNumber
repeat with i = 1 to the number of lines in field "project comments"
if item 1 of line i of field "project comments" is "VATComment" and item 2 of line i of field "project comments" is videoEntryNumber then
//put line i+1 of field "project comments" into line 1 of field "display comment"
delete line i of field "project comments"
repeat with j = i to the number of lines in field "project comments"
if item 1 of line i of field "project comments" <> "VATComment" then
delete line i of field "project comments"
else
exit deleteComment
end if
end repeat
exit deleteComment
end if
end repeat
//put "No comments yet for this video entry" into line 1 of field "display comment"
end deleteComment
- Users can now add as many tags as they wish for each video clip;
- Users can now add a comment that is as long as they wish, extending over as many lines (i.e. paragraphs) as they wish.
- Users have the option of adding a brief description for each clip.
- I created a video clip dashboard to display all important important about the selected video clip.
Please note that I won't be providing any LiveCode files to download as I did in previous posts for this project. For each of those posts, I had created a second and unique version of the project to make clearer the various LiveCode skills and principles I was demonstrating. The project has now progressed to the point where continuing to update and share this second LiveCode file is too time prohibitive. However, I'll continue to share important code where appropriate. And, I think those previous files will help anyone just getting into the use of video within LiveCode.
Attaching Multiple Tags for Each Video Clip
In the previous versions, the user could only add one tag per clip. I knew all along this would be insufficient. Of course, any one video clip could have many tags or no tags, so I needed to account for an uneven number in the design. I debated on the best way to approach this, deciding in the end to just have the tags continue to be added as separate items in the field "log." Doing so created a dilemma about where to put the user comments as they had been also part of this field. I decided to create a separate field for "project comments." This opened up other possibilities for comments, which I'll discuss later in this blog posting.
In previous posts I described the basics of how the tagging system works. Recall that users can create a list of unique tags. Each tag is just a copy and paste of a template button found on the "Library" card where the name and label of the button is changed to whatever tag name the user entered. I revised the script of that template button:
global gActivity
on mouseUp
//Check to make sure that a clip has been chosen
if the selectedtext of field "log2" is empty then
answer "You first have to select an entry from the log."
exit mouseUp
end if
put the label of me into gActivity
put the hilitedLine of field "log2" into l // read as "line lower case L"; assume this in remaining lines
//count the number of items in the line
put the number of items of line l of field "log" into varItemsCount
//check to see if tag is already there
repeat with i = 5 to varItemsCount
if gActivity = item i of line l of field "log" then
set the hilitedLine of field "log2" to l
exit mouseUp
end if
end repeat
put the label of me into item varItemsCount+1 of line l of field "log"
//Update the display of tags
put "Tags: " into varShowTags
put the number of items in line l of field "log" into varItemsCount
if varItemsCount<5 then put "Tags: No tags for this clip" into varShowTags
//all tags begin with item 5
repeat with i = 5 to varItemsCount
put varShowTags&item i of line l of field "log" into varShowTags
if i<varItemsCount then put varShowTags&", " into varShowTags
end repeat
put varShowTags into line 1 of field "Tags"
set the hilitedLine of field "log2" to l
end mouseUp
The commented lines show the main parts of this script. It begins by checking to see if the user has chosen a clip and if not, it reminds the user to do so, followed by the command "exit mouseUp." This command tells LiveCode to do just that, exit the script triggered by the mouseUp without executing any other of the lines that follow. I highlighted this line in red. (Notice that I use this command again later in the script.)
The next task is to see if the user has already chosen that tag because we obviously don't want duplicate tags listed for a clip. First, I check to see how many items are in the highlighted line of field "log" and store this number in the local variable "varItemsCount." That number will be used for the upper limit of a repeat loop coming up, plus we will use it to determine where to put the next unique tag.
Next is the repeat loop, triggered by this line:
repeat with i = 5 to varItemsCount
The local variable i increments by one in each loop, starting with 5 and ending with the value in varItemsCount. I start with 5 because I know the first four item slots are already taken. Item 1 now contains a clip number and item 2 now contains a short description of the clip -- two things I address briefly below. Items 3 and 4 contain the starting and ending time code of the clip in user friendly terms (this was the subject of my most previous post). This repeat loop then checks to see if the tag button just pressed matches any of the tags listed in items 5 and onward. If it finds a match, it exits the mouseUp script. If it doesn't, it adds this tag as the very next item (i.e. varItemsCount + 1).
The next block of script updates the display of the tags in the video clip dashboard. This dashboard is a new feature. Let's address that next.
Video Clip Dashboard
One of the big improvements in version 0.2.0 is the video clip dashboard. Recall that I included some screen placeholders for this video dashboard in the previous versions of the prototype. Well, I finally tackled the implementation of the dashboard here.
I created four fields for the dashboard titled "time code," "Description," "tags," and "display comment." These four fields are populated with the respective information. To populate the tags field, I use another repeat loop to create a string variable called "varShowTags." This contains a list of all the tags with a comma and space in-between, all concatenated as the repeat loops works its magic.
The script ends by highlighting the video clip line in the field "log2."
Updating the Video Clip Dashboard When the User Selects a New Clip
Let's continue to look at the video clip dashboard. When the user clicks on a video entry in the field "log2," the dashboard immediately updates with the information for that clip using the following script attached to the field itself:
on mouseDown
if the number of lines in me is 0 then exit mouseDown
stop player "player"
set the playSelection of player "player" to true
put the hilitedLine of me into l
set the currentTime of player "player" to item 3 of line l of field "log"
displayClipInformation l
displayComment l
end mouseDown
Yes, that's right, you can treat a field like a button and have events triggered if it is clicked. This short script does a lot, thanks to two new commands I created titled "displayClipInformation" and "displayComment." Commands are close relatives to functions. The idea is the same -- you are inventing your own vocabulary and adding them to LiveCode's dictionary. The difference is that a command simply does something without returning any value like a function would (review my description of functions in my previous post). The command displayClipInformation does some magic to populate the fields "time code," "Description," and "tags." The function displayComment is used to populate the field "display comment." Both functions are shown below in their entirety, but I won't try to describe them in any depth here.
Improvement to User Comments
Let's address the design behind the improvement to user comments. I knew I needed to give the user the opportunity to make in-depth comments about any of the clips. This would have to include a basic narrative structure using sentences and paragraphs, along with standard narrative symbols, such as commas and periods. It was clear that the only way to do this was by creating yet another field titled "Project Comments" to store the comments. The tricky part is connecting the right comment to the correct video clip. Since any one comment would potentially contains multiple lines, perhaps dozens, some sort of indexing system would be needed beyond just using the line number of the clip in the field "log2."
So, I used an approach that is adapted from how relational database work. I merely created an indexing system where each clip gets a unique number. I then put the term "VATComment" as item 1 on a line and the index number as item 2 on the very same line. That way, every time the user clicks on a video entry LiveCode searches the "Project Comments" field for that term as item 1 on a line. If it finds it, it then notes the index number. All lines after that and up to the next time the term VATComment is found (or the end of the field is reached), is assumed to be the entire comment for that video clip. Pretty clever if I say so myself.
I also had to design a way for a user to update a particular comment. The best strategy I came up with was to create yet another command to first "seek out and destroy"all lines associated with a particular comment when the user updates a comment, followed immediately by creating a new set of lines for the updated comment. In a sense, every update is really a new comment, as far as LiveCode is concerned. This command is titled "deleteComment" and I've also listed the entire script below.
Final Thoughts
I also wrote a bunch of other small scripts here and there to have everything run smoothly and to catch user errors. It's really amazing the number of situations one must address when trying to anticipate a user's interaction.
One thing I have not yet done is program a way for the user to delete tags. That will come in the next version of the program. I'm currently mulling over a few ways of doing this, so you'll have to check back later to see how I decide to tackle this issue. Also, I think it is high time I address the need to let the user select any video for analysis. Yes, it is time to put my placeholder video to rest. But, you can always view it here if you miss it.
Appendix: Scripts for the Commands "displayClipInformation" and "displayComment"
Both scripts are defined in the card script. Both scripts take the number corresponding to the selected video clip as input.
command displayClipInformation videoEntryLine
//Display entry information
put videoEntryLine into l
put item 2 of line l of field "log" into field "Description"
//Construct time code string
put the timescale of player "Player" into ts
put item 3 of line l of field "log" into tcStart
put item 4 of line l of field "log" into tcEnd
put (tcEnd - tcStart)/ts into varCliplength
put round(varCliplength,1) into varCliplength
put convertTimeCode (tcStart) into tcStart2
put convertTimeCode (tcEnd) into tcEnd2
put "Clip length: "&tcStart2&" to "&tcEnd2&" ("&varCliplength&" sec)" into line 1 of field "Time Code"
//Determine tags for display
put "Tags: " into varShowTags
put the number of items in line l of field "log" into varItemsCount
if varItemsCount<5 then put "Tags: No tags for this clip" into varShowTags
//all tags begin with item 5
repeat with i = 5 to varItemsCount
put varShowTags&item i of line l of field "log" into varShowTags
if i<varItemsCount then put varShowTags&", " into varShowTags
end repeat
put varShowTags into line 1 of field "Tags"
end displayClipInformation
command displayComment videoEntryLine
put empty into field "display comment"
put videoEntryLine into l
put item 1 of line videoEntryLine of field "log" into videoEntryNumber
repeat with i = 1 to the number of lines in field "project comments"
if item 1 of line i of field "project comments" is "VATComment" and item 2 of line i of field "project comments" is videoEntryNumber then
put line i+1 of field "project comments" into line 1 of field "display comment"
repeat with j = i+2 to the number of lines in field "project comments"
if item 1 of line j of field "project comments" <> "VATComment" then
put line j of field "project comments" into line (number of lines in field "display comment"+1) of field "display comment"
else
exit displayComment
end if
end repeat
exit displayComment
end if
end repeat
put "No comments yet for this video entry" into line 1 of field "display comment"
end displayComment
command deleteComment videoEntryLine
//put empty into field "display comment"
put videoEntryLine into l
put item 1 of line videoEntryLine of field "log" into videoEntryNumber
repeat with i = 1 to the number of lines in field "project comments"
if item 1 of line i of field "project comments" is "VATComment" and item 2 of line i of field "project comments" is videoEntryNumber then
//put line i+1 of field "project comments" into line 1 of field "display comment"
delete line i of field "project comments"
repeat with j = i to the number of lines in field "project comments"
if item 1 of line i of field "project comments" <> "VATComment" then
delete line i of field "project comments"
else
exit deleteComment
end if
end repeat
exit deleteComment
end if
end repeat
//put "No comments yet for this video entry" into line 1 of field "display comment"
end deleteComment