Greetings and salutations fellow coders,
I'm trying to parse a MIDI sequence and get note durations from it. When I get a note on command I do a look ahead to find either a note off command for the same key or a note on command with a velocity of 0. Here is the code block in question(probably not needed).
for (Track track : sequence.getTracks())
{
for (int i = 0; i < track.size(); i++)
{
MidiEvent event = track.get(i);
MidiMessage message = event.getMessage();
if (message instanceof ShortMessage)
{
ShortMessage sm = (ShortMessage) message;
long timeStamp = event.getTick();
String temp = "0x" + Integer.toHexString(sm.getCommand());
if (temp.contains(Definitions.NOTE_ON))
{
// look ahead for note off and find duration
for (int j = i; j < track.size(); j++)
{
MidiEvent event2 = track.get(j);
MidiMessage message2 = event2.getMessage();
if (message2 instanceof ShortMessage)
{
ShortMessage sm2 = (ShortMessage) message2;
long timeStamp2 = event2.getTick();
temp = "0x" + Integer.toHexString(sm2.getCommand());
if (temp.contains(Definitions.NOTE_OFF) && sm2.getData1() == sm.getData1())
{
song.addNote(trackNumber, sm.getData1(), timeStamp, timeStamp2 - timeStamp, sm.getData2());
break;
}
//another valid way of turning a note off is playing a note on with a velocity of 0
else if (temp.contains(Definitions.NOTE_ON) && sm2.getData1() == sm.getData1() && sm2.getData2() == 0)
{
song.addNote(trackNumber, sm.getData1(), timeStamp, timeStamp2 - timeStamp, sm.getData2());
break;
}
}
}
}
}
}
}
Definitions.NOTE_ON = "0x9"
Definitions.NOTE_OFF = "0x8"
The code is a little messy and definitely not optimized, but it shouldn't entirely be necessary for people with great expertise in midi. I should note that most MIDI files I read use note off for the corresponding note on. So most the songs I read are read successfully there are just a few that don't use note off and my application is not adding the notes.
My question is this:
What other ways than note off or note on with a velocity of 0 determines when a note stops playing?
These are the ways I know to stop a MIDI note:
Call "Note Off" (0x80)
Call "Note On" (0x90) with velocity of 0
Call "All Notes Off" (0x58)
Also, a second Note On event for a given channel and note can be received without having received a Note Off. In this case, I believe the original Note On should be considered finished.
Related
i'm using JNA to read some event logs delivered by my application. Im mostly interested in the description strings data.
I'm using the code below:
private static void readLog() {
Advapi32Util.EventLogIterator iter = new Advapi32Util.EventLogIterator("Application");
while (iter.hasNext()) {
Advapi32Util.EventLogRecord record = iter.next();
System.out.println("------------------------------------------------------------");
System.out.println(record.getRecordNumber()
+ ": Event ID: " + record.getInstanceId()
+ ", Event Type: " + record.getType()
+ ", Event Strings: " + Arrays.toString(record.getStrings())
+ ", Data: " + record.getRecord().toString());
System.out.println();
}
}
Example event my application produces:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-MyApp" Guid="{4d5ae6a1-c7c8-4e6d-b840-4d8080b42e1b}" />
<EventID>201</EventID>
<Version>0</Version>
<Level>2</Level>
<Task>2</Task>
<Opcode>30</Opcode>
<Keywords>0x4010000001000000</Keywords>
<TimeCreated SystemTime="2021-02-19T15:16:03.675690900Z" />
<EventRecordID>3622</EventRecordID>
<Correlation ActivityID="{e6ee2b3b-9b9a-4c9d-b39b-6c2bf2550000}" />
<Execution ProcessID="2108" ThreadID="8908" />
<Channel>Microsoft-Windows-MyApp/Operational</Channel>
<Computer>computer</Computer>
<Security UserID="S-1-5-20" />
</System>
<UserData>
<EventInfo xmlns="aag">
<Username>username</Username>
<IpAddress>127.0.0.1</IpAddress>
<AuthType>NTLM</AuthType>
<Resource />
<ConnectionProtocol>HTTP</ConnectionProtocol>
<ErrorCode>23003</ErrorCode>
</EventInfo>
</UserData>
</Event>
Other event UserData:
<UserData>
<EventInfo xmlns="aag">
<Username>otherUserName</Username>
<IpAddress>10.235.163.52:50427</IpAddress>
</EventInfo>
</UserData>
JNA provides event log records in EVENTLOGRECORD class which only contains methods to get only values of description strings. If i could get the record in XML format my problem would be gone.
Data in UserData is not always the same, it contains different values depending on the event type. I want to parse the data from UserData section to POJO (it can be just one POJO containing all available fields). I dont want to use fields order, because some events have different fields than other (as shown in example).
Is there any way to do this using xml tag names? I will consider even switching to other lang.
As I pointed out in my comment you need to render the event to get to the XML. Matthias Bläsing also pointed out that some sample code is available in the WevtapiTest test class in JNA.
Using that test class, I created the below program which reads the XML from the latest 50 events from the System log. Filtering events to what you want is left as an exercise for the reader.
public static void main(String[] args) {
EVT_HANDLE queryHandle = null;
// Requires elevation or shared access to the log.
String path = "C:\\Windows\\System32\\Winevt\\Logs\\System.evtx";
try {
queryHandle = Wevtapi.INSTANCE.EvtQuery(null, path, null, Winevt.EVT_QUERY_FLAGS.EvtQueryFilePath);
// Read 10 events at a time
int eventArraySize = 10;
int evtNextTimeout = 1000;
int arrayIndex = 0;
EVT_HANDLE[] eventArray = new EVT_HANDLE[eventArraySize];
IntByReference returned = new IntByReference();
while (Wevtapi.INSTANCE.EvtNext(queryHandle, eventArraySize, eventArray, evtNextTimeout, 0, returned)) {
Memory buff;
// This just needs to be 0. Kept same name from test sample
IntByReference propertyCount = new IntByReference();
Winevt.EVT_VARIANT evtVariant = new Winevt.EVT_VARIANT();
for (int i = 0; i < returned.getValue(); i++) {
buff = WevtapiUtil.EvtRender(null, eventArray[i], Winevt.EVT_RENDER_FLAGS.EvtRenderEventXml,
propertyCount);
// Output the XML!
System.out.println(buff.getWideString(0));
}
arrayIndex++;
// Quit after 5 x 10 events
if (arrayIndex >= 5) {
break;
}
}
if (Kernel32.INSTANCE.GetLastError() != WinError.ERROR_SUCCESS
&& Kernel32.INSTANCE.GetLastError() != WinError.ERROR_NO_MORE_ITEMS) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
} finally {
if (queryHandle != null) {
Wevtapi.INSTANCE.EvtClose(queryHandle);
}
}
}
I am using this routine to iterate over sentences in an OpenOffice document:
while (moreParagraphsOO) {
while (moreSentencesOO) {
xSentenceCursor.gotoEndOfSentence(true);
textSentence = xSentenceCursor.getString();
xTextViewCursor.gotoRange(xSentenceCursor.getStart(), false);
xTextViewCursor.gotoRange(xSentenceCursor.getEnd(), true);
if (!textSentence.equals("")) {
return textSentence;
}
moreSentencesOO = xSentenceCursor.gotoNextSentence(false);
}
moreParagraphsOO = xParagraphCursor.gotoNextParagraph(false);
moreSentencesOO = xSentenceCursor.gotoStartOfSentence(false);
}
It works fine unless it finds a paragraph which ends with ". ", this is, a period and one or several whitespaces after it. In that case it enters and infinite loop executing the
while (moreSentencesOO)
...
moreSentencesOO = xSentenceCursor.gotoNextSentence(false);
endlessly. I am not so proeficient with OpenOffice API, and I am quite stuck here. Any ideas?
Thanks.
EDIT: I have come with a somewhat awkward patch consisting in checking the current position of the cursor, and if it does not advance between two iterations, jump to next paragraph:
while (moreParagraphsOO) {
while (moreSentencesOO) {
/**********************************/
int previousPosX = xTextViewCursor.getPosition().X;
int previousPosY = xTextViewCursor.getPosition().Y;
/*********************************/
xSentenceCursor.gotoEndOfSentence(true);
textSentence = xSentenceCursor.getString();
xTextViewCursor.gotoRange(xSentenceCursor.getStart(), false);
xTextViewCursor.gotoRange(xSentenceCursor.getEnd(), true);
if (!textSentence.equals("")) {
return textSentence;
}
moreSentencesOO = xSentenceCursor.gotoNextSentence(false);
/**********************************/
if (previousPosX == xTextViewCursor.getPosition().X &&
previousPosY == xTextViewCursor.getPosition().Y){
xParagraphCursor.gotoNextParagraph(false);
}
/**********************************/
}
moreParagraphsOO = xParagraphCursor.gotoNextParagraph(false);
moreSentencesOO = xSentenceCursor.gotoStartOfSentence(false);
}
It seems to work, but I am unsure about whether it could introduce future problems. I would rather prefer an "elegant" solution.
According to gotoNextSentence(), it should only return true if the cursor was moved, so this is a bug. Consider filing a report.
The problem seems to occur when isEndOfSentence() but not isStartOfSentence(). So test for that instead of getPosition().
Here is Andrew Pitonyak's Basic macro that I modified to include this fix.
Sub CountSentences
oCursor = ThisComponent.Text.createTextCursor()
oCursor.gotoStart(False)
Do
nSentences = nSentences + 1
If oCursor.isEndOfSentence() And Not oCursor.isStartOfSentence() Then
oCursor.goRight(1, False)
End If
Loop While oCursor.gotoNextSentence(False)
MsgBox nSentences & " sentences."
End Sub
I maintain a small java servlet-based webapp that presents forms for input, and writes the contents of those forms to MariaDB.
The app runs on a Linux box, although the users visit the webapp from Windows.
Some users paste text into these forms that was copied from MSWord docs, and when that happens, they get internal exceptions like the following:
Caused by: org.mariadb.jdbc.internal.util.dao.QueryException:
Incorrect string value: '\xC2\x96 for...' for column 'ssimpact' at row
1
For instance, I tested it with text like the following:
Project – for
Where the dash is a "long dash" from the MSWord document.
I don't think it's possible to convert the wayward characters in this text to the "correct" characters, so I'm trying to figure out how to produce a reasonable error message that shows a substring of the bad text in question, along with the index of the first bad character.
I noticed postings like this: How to determine if a String contains invalid encoded characters .
I thought this would get me close, but it's not quite working.
I'm trying to use the following method:
private int findUnmappableCharIndex(String entireString) {
int charIndex;
for (charIndex = 0; charIndex < entireString.length(); ++ charIndex) {
String currentChar = entireString.substring(charIndex, charIndex + 1);
CharBuffer out = CharBuffer.wrap(new char[currentChar.length()]);
CharsetDecoder decoder = Charset.forName("utf-8").newDecoder();
CoderResult result = decoder.decode(ByteBuffer.wrap(currentChar.getBytes()), out, true);
if (result.isError() || result.isOverflow() || result.isUnderflow() || result.isMalformed() || result.isUnmappable()) {
break;
}
CoderResult flushResult = decoder.flush(out);
if (flushResult.isOverflow()) {
break;
}
}
if (charIndex == entireString.length() + 1) {
charIndex = -1;
}
return charIndex;
}
This doesn't work. I get "underflow" on the first character, which is a valid character. I'm sure I don't fully understand the decoder mechanism.
This is related with handling the scenario when some crazy user is holding down the F5 key to send unlimited requests to our server.
Our application is very much database and cache intensive and when such consecutive requests come in; our web application is crashing after some time. I know we need to fix the application cache handling and need to add some check at the web server but I am asked to take care of this issue in our code.
I am handling this on both Javascript and server side, but looks like still it is failing, so would like to know if you have any better solution.
My code is as follows:
Javascript Code:
function checkPageRefresh(e) {
e = e || window.event;
ar isPageRefreshed = false;
// detect if user tries to refresh
if ((e.keyCode == 116) /* F5 */ ||
(e.ctrlKey && (e.keyCode == 116)) /* Ctrl-F5 */ ||
(e.ctrlKey && (e.keyCode == 82)) /* Ctrl-R */) {
isPageRefreshed = true;
}
// only trigger special handling for page refresh
if (isPageRefreshed){
var lastRefreshTimeMillis= readCookie("last_refresh");
var currentTimeMillis = new Date().getTime();
// set cookie with now as last refresh time
createCookie(lastRefreshCookieName, currentTimeMillis);
var lastRefreshParsed = parseFloat(lastRefreshTimeMillis, 10);
var timeDiff = currentTimeMillis - lastRefreshParsed;
var F5RefreshTimeLimitMillis = <%=request.getAttribute("F5RefreshTimeLimitMillis")%>;
// if detected last refresh was within 1 second, abort refresh
if (timeDiff < F5RefreshTimeLimitMillis) {
if (e.preventDefault) {
e.preventDefault();
return;
}
}
} // end if (isPageRefreshed)
}
Java Code:
Queue<VisitsInfoHolder> recentlyVisitedUrls = (LinkedList<VisitsInfoHolder>)session.getAttribute(SupportWebKeys.RECENTLY_VISITED_URLS);
String urlBeingCalled = PageUrlUtils.getFullURL(request);
int maxCountOfRecentURLs = 3;
if(null != recentlyVisitedUrls){
//verify if last visit count is matching with the count provided
if(recentlyVisitedUrls.size() >= maxCountOfRecentURLs ) {
int noOfMatchingVisits = 0;
Long firstAccessedTime = 0l;
int count = 0;
for(VisitsInfoHolder urlIno : recentlyVisitedUrls) {
//Store the time stamp of the first record
if(count == 0 && null != urlIno) {
firstAccessedTime = urlIno.getTimeOfTheVisit();
}
count++;
//count how many visits to the current page
if(null != urlIno && null != urlIno.getUrl() && urlIno.getUrl().equalsIgnoreCase(urlBeingCalled)) {
noOfMatchingVisits++;
}
}
if (noOfMatchingVisits >= maxCountOfRecentURLs && (new Date().getTime() - firstAccessedTime) <= 1000){
LOGGER.error(">>>>> Redirecting the client to the warning page.");
VisitsInfoHolder currentVisitInfo = new VisitsInfoHolder(urlBeingCalled,new Date().getTime());
recentlyVisitedUrls.remove();
recentlyVisitedUrls.add(currentVisitInfo);
response.sendRedirect((String)request.getAttribute("F5IssueRedirectPage"));
LOGGER.error(">>>>> Redirected successfully.");
return;
}
else{
VisitsInfoHolder currentVisitInfo = new VisitsInfoHolder(urlBeingCalled,new Date().getTime());
recentlyVisitedUrls.remove();
recentlyVisitedUrls.add(currentVisitInfo);
session.setAttribute(SupportWebKeys.RECENTLY_VISITED_URLS, recentlyVisitedUrls);
}
}
else if (recentlyVisitedUrls.size() < maxCountOfRecentURLs) {
VisitsInfoHolder currentVisitInfo = new VisitsInfoHolder(urlBeingCalled,new Date().getTime());
recentlyVisitedUrls.add(currentVisitInfo);
session.setAttribute(SupportWebKeys.RECENTLY_VISITED_URLS, recentlyVisitedUrls);
}
}
else{
recentlyVisitedUrls = new LinkedList<VisitsInfoHolder>();
VisitsInfoHolder currentVisitInfo = new VisitsInfoHolder(urlBeingCalled,new Date().getTime());
recentlyVisitedUrls.add(currentVisitInfo);
session.setAttribute(SupportWebKeys.RECENTLY_VISITED_URLS, recentlyVisitedUrls);
}
Now I keep holding the F5 button then my Javascript is not understanding that the same key is held for longer time and server side code prints the following 2 loggers
Redirecting the client to the warning page.
Redirected successfully.
But in reality it is not redirecting any single time. I tried adding Thread.sleep(1000) before and after redirect, but still no luck.
Please let me know if you see any issue with my code or let me know if there is any better solution.
When you reproduce this problem are you the only person on your server? Can you reproduce this problem on your local dev instance? If so you really need to fix your server code such that it doesn't crash. You are doing something on your server that is too intensive and needs to be optimized.
Simply intercepting the F5 key on someone's browser is treating the symptoms not the disease. If you are having problems handling a single user hitting F5 really quickly it simply means you'll never be able to scale up to many simultaneous users because that's the exact same request/response pattern as a single user round tripping you with F5.
It's time to break out the profiler and check the timings on how long it takes to process a single request through the system. Then look for hotspots and optimize it. Also watch your memory usage see if you are cleaning things up or if they are growing off into infinity.
The problem is that when I use source code below, i receive cell id's only in 2G mode, if i switch to 3G mode i sometimes receive -1 for HSDPA or nothing for UMTS. Source code is:
for (int i = 0; i < neighCell.size(); i++) {
try {
NeighboringCellInfo thisCell = neighCell.get(i);
int thisNeighCID = thisCell.getCid();
int thisNeighRSSI = -113 + 2*thisCell.getRssi();
log("Base station "+(i+1)+":"+
"\nCellID: "+thisNeighCID+
"; RSSI: "+thisNeighRSSI+" dBm");
} catch (NumberFormatException e) {
e.printStackTrace();
NeighboringCellInfo thisCell = neighCell.get(i);
log(thisCell.toString());
}
}
Is there any way to get id's in 3G mode and especially for UMTS?
The -1 value you are getting corresponds to the value of the UNKNOWN_CID constant, which indicates the cell location is not available.
You can confirm this in the API here.
It also states that the get methods related with the information you want to acquire, only work in GSM. For UMTS and CDMA it treats them the same as unknown location.