Using JAudioTagger to get track duration? - java

I'm trying to use JAudioTagger in a media player like application to yoink the meta data for each song, but I don't see a field for track duration. I'm sure there must be one but I can't seem to find it and a couple searches haven't turned up anything. I'm looking at: http://www.jthink.com/jaudiotagger/tagmapping.html and at the java docs.
Does anyone have any idea? Thank you for any help!

As the earlier answer said the track length is not stored in the tag but can be derived from the audio itself, this is why it is accesible via the audioheader object rather than the tag itself i.e.
AudioFile audioFile = AudioFileIO.readFile("/somefile.mp3");
System.out.println(audioFile.getAudioHeader().getTrackLength());
If it is an mp3, you can all get the tracklength output nicel formatted as mm:ss
System.out.println((Mp3AudioHeader)audioFile.getHeader().getTrackLengthAsString());
or
new MP3File("/somefile.mp3").getMP3AudioHeader().getTrackLengthAsString();

For most formats, the length isn't in the tag.
Many libraries (and media players), like TagLib, estimate it for you by working out the length in seconds of a few hundred kilobytes of the file (the bitrate) and multiplying up. Sometimes this goes horrendously wrong, but, a surprising portion of the time, it works out fine.

I can recommend mp4parser library since it returns duration with expected precision (like ffmepg does).

Related

Downloading video file by streaming a certain part of the video

An online link gives me back a video in my browser, that is then streamed. In my browser, I don't need to download the whole video to visualize it - I can skip to a certain part, visualize that part, and even stop watching before the end.
How can I, from the very same link, start to stream from a specific time onwards until another specific time, and each time save every frame I received to a video file?
I do know that I need to decode the data I get.
I also know that I need to somehow access the metadata of the video file.
However, I don't know how to deal with it in practice.
I tried out JCodec, but could not find how to deal with internet streams instead of opening files.
How can I properly stream parts of an online video, frame-by-frame, while also having access to metadata such as total video length, resolution, and FPS?
To answer the first parts of your question:
Trim videos with start offset and either end offset or duration (in seconds, percentages, etc.), e.g. http://res.cloudinary.com/demo/video/upload/so_6.5,eo_10/dog.mp4
Grab frames at desired timestamps along the original video, e.g. http://res.cloudinary.com/demo/video/upload/so_8.5/dog.jpg to save a JPEG-format frame at 8.5 seconds from the start of the video.

Writing one file per group in Pig Latin

The Problem:
I have numerous files that contain Apache web server log entries. Those entries are not in date time order and are scattered across the files. I am trying to use Pig to read a day's worth of files, group and order the log entries by date time, then write them to files named for the day and hour of the entries it contains.
Setup:
Once I have imported my files, I am using Regex to get the date field, then I am truncating it to hour. This produces a set that has the record in one field, and the date truncated to hour in another. From here I am grouping on the date-hour field.
First Attempt:
My first thought was to use the STORE command while iterating through my groups using a FOREACH and quickly found out that is not cool with Pig.
Second Attempt:
My second try was to use the MultiStorage() method in the piggybank which worked great until I looked at the file. The problem is that MulitStorage wants to write all fields to the file, including the field I used to group on. What I really want is just the original record written to the file.
The Question:
So...am I using Pig for something it is not intended for, or is there a better way for me to approach this problem using Pig? Now that I have this question out there, I will work on a simple code example to further explain my problem. Once I have it, I will post it here. Thanks in advance.
Out of the box, Pig doesn't have a lot of functionality. It does the basic stuff, but more times than not I find myself having to write custom UDFs or load/store funcs to get form 95% of the way there to 100% of the way there. I usually find it worth it since just writing a small store function is a lot less Java than a whole MapReduce program.
Your second attempt is really close to what I would do. You should either copy/paste the source code for MultiStorage or use inheritance as a starting point. Then, modify the putNext method to strip out the group value, but still write to that file. Unfortunately, Tuple doesn't have a remove or delete method, so you'll have to rewrite the entire tuple. Or, if all you have is the original string, just pull that out and output that wrapped in a Tuple.
Some general documentation on writing Load/Store functions in case you need a bit more help: http://pig.apache.org/docs/r0.10.0/udf.html#load-store-functions

Changing instruments in midi encoding?

I'm trying to write a function to dynamically create midi files on Android. Since there is no javax.sound.midi library I'm just writing the bytes out to file myself. I've found some great guides (see below) so I've been able to create multiple track midis. However I haven't been able to figure out how to switch instruments for any of the tracks so everythign is just using the default instrument.
I think from the documents I read the code I need is to "program change" followed by the program number.
What I've tried so far is writing the following out to a byteoutputstream array:
track.write((byte) 192); // 128 + 64
track.write((byte) x); // x is the instrument number between 1-128.
I've put this before the start of the note on/ note off track information, but it doesn't seem to do anything except make the midi take a long time to start. Am I on the right track here, or am I missing something? Any help is appreciated.
http://faydoc.tripod.com/formats/mid.htm
https://ccrma.stanford.edu/~craig/articles/linuxmidi/misc/essenmidi.html
Finally figured it out. It was a just a simple thing, but I forgot to include track time before the program change. Once I added the 0 byte it worked.

JAVA: gathering byte offsets of xml tags using an XmlStreamReader

Is there a way to accurately gather the byte offsets of xml tags using the XMLStreamReader?
I have a large xml file that I require random access to. Rather than writing the whole thing to a database, I would like to run through it once with an XMLStreamReader to gather the byte offsets of significant tags, and then be able to use a RandomAccessFile to retrieve the tag content later.
XMLStreamReader doesn't seem to have a way to track character offsets. Instead people recommend attaching the XmlStreamReader to a reader that tracks how many bytes have been read (the CountingInputStream provided by apache.commons.io, for example)
e.g:
CountingInputStream countingReader = new CountingInputStream(new FileInputStream(xmlFile)) ;
XMLStreamReader xmlStreamReader = xmlStreamFactory.createXMLStreamReader(countingReader, "UTF-8") ;
while (xmlStreamReader.hasNext()) {
int eventCode = xmlStreamReader.next();
switch (eventCode) {
case XMLStreamReader.END_ELEMENT :
System.out.println(xmlStreamReader.getLocalName() + " #" + countingReader.getByteCount()) ;
}
}
xmlStreamReader.close();
Unfortunately there must be some buffering going on, because the above code prints out the same byte offsets for several tags. Is there a more accurate way of tracking byte offsets in xml files (ideally without resorting to abandoning proper xml parsing)?
You could use getLocation() on the XMLStreamReader (or XMLEvent.getLocation() if you use XMLEventReader), but I remember reading somewhere that it is not reliable and precise. And it looks like it gives the endpoint of the tag, not the starting location.
I have a similar need to precisely know the location of tags within a file, and I'm looking at other parsers to see if there is one that guarantees to give the necessary level of location precision.
You could use a wrapper input stream around the actual input stream, simply deferring to the wrapped stream for actual I/O operations but keeping an internal counting mechanism with assorted code to retrieve current offset?
Unfortunatly Aalto doesn't implement the LocationInfo interface.
The last java VTD-XML ximpleware implementation, currently 2.11
on sourceforge or on github
provides some code maintaning a byte offset after each call to
the getChar() method of its IReader implementations.
IReader implementations for various caracter encodings
are available inside VTDGen.java and VTDGenHuge.java
IReader implementations are provided for the following encodings
ASCII;
ISO_8859_1
ISO_8859_10
ISO_8859_11
ISO_8859_12
ISO_8859_13
ISO_8859_14
ISO_8859_15
ISO_8859_16
ISO_8859_2
ISO_8859_3
ISO_8859_4
ISO_8859_5
ISO_8859_6
ISO_8859_7
ISO_8859_8
ISO_8859_9
UTF_16BE
UTF_16LE
UTF8;
WIN_1250
WIN_1251
WIN_1252
WIN_1253
WIN_1254
WIN_1255
WIN_1256
WIN_1257
WIN_1258
Updating IReader with a getCharOffset() method
and implementing it
by adding a charCount member along to the offset member of the
VTDGen and VTDGenHuge classes
and by incrementing it upon each getChar() and skipChar() call of each IReader implementation should give you the start of a solution.
I think I've found another option. If you replace your switch block with the following, it will dump the position immediately after the end element tag.
switch (eventCode) {
case XMLStreamReader.END_ELEMENT :
System.out.println(xmlStreamReader.getLocalName() + " end#" + xmlStreamReader.getLocation().getCharacterOffset()) ;
}
This solution also would require that the actual start position of the end tags would have to be manually calculated, and would have the advantage of not needing an external JAR file.
I was not able to track down some minor inconsistencies in the data management (I think it has to do with how I initialized my XMLStreamReader), but I always saw a consistent increase in the location as the reader moved through the content.
Hope this helps!
I recently worked out a solution for a similar question on How to find character offsets in big XML files using java?. I think it provides a good solution based on a ANTLR generated XML-Parser.
I just burned a day long weekend on this, and arrived at the solution partially thanks to some clues here. Remarkably I don't think this has gotten much easier in the 10 years since the OP posted this question.
TL;DR Use Woodstox and char offsets
The first problem to contend with is that most XMLStreamReader implementations seem to provide inaccurate results when you ask them for their current offsets. Woodstox however seems to be rock-solid in this regard.
The second problem is the actual type of offset you use. Unfortunately it seems that you have to use char offsets if you need to work with a multi-byte charset, which means the random-access retrieval from the file is not going to be very efficient - you can't just set a pointer into the file at your offset and start reading, you have to read through until you get to the offset, then start extracting. There may be a more efficient way to do this that I haven't though of, but the performance is acceptable for my case. 500MB files are pretty snappy.
[edit] So this turned into one of those splinter-in-my-mind things, and I ended up writing a FilterReader that keeps a buffer of byte offset to char offset mappings as the file is read. When we need to get the byte offset, we first ask Woodstox for the char offset, then get the custom reader to tell us the actual byte offset for the char offset. We can get the byte offset from the beginning and end of the element, giving us what we need to go in and surgically extract the element from the file by opening it as a RandomAccessFile.
I created a library for this, it's on GitHub and Maven Central. If you just want to get the important bits, the party trick is in the ByteTrackingReader.
[/edit]
There is another similar question on SO about this (but the accepted answer frightened and confused me), and some people commented about how this whole thing is a bad idea and why would you want to do it? XML is a transport mechanism, you should just import it to a DB and work with the data with more appropriate tools. For most cases this is true, but if you're building applications or integrations that communicate via XML (still going strong in 2020), you need tooling to analyze and operate on the files that are exchanged. I get daily requests to verify feed contents, having the ability to quickly extract a specific set of items from a massive file and verify not only the contents, but the format itself is essential.
Anyhow, hopefully this can save someone a few hours, or at least get them closer to a solution. God help you if you're finding this in 2030, trying to solve the same problem.

Change the volume of an audio file and save the file using java.sound.sampled

I want to change the volume of an audio file
and save the new file using java.sound.sampled.
I tried to use the mixer to create a source line
from the file given and a target line to the new file.
So that I can change the mixer settings to change the volume.
But the sound is being played to the system speaker.
Am I thinking along correct way or not?
Is there any other way to record a file from a line?
The code is available here
A solution I got is www.jsresources.org/examples/AmplitudeConverter.html.
But can the same be done within java.sound.sampled
without using external libraries.
To change the volume, if you don't use a "Control" (see the Java Sound Tutorials), there is the option of directly modifying the samples themselves.
In your innermost loop, convert the bytes in the innermost buffer into a sample (if it is WAV 16-bit encoding, then you need to put the two bytes together to make the single SHORT value), then multiply that value by a float that ranges from 0 to 1, where 0 is the quietest and 1 leaves the sound at full volume. Then take the result and break it back down into two bytes and pass it along.
Do you need the code to do this? There are several other posts here where folks convert from bytes to INTs or Float and back.
Hmmm. This question is pretty old. Well maybe my answer will help someone new to the same problem.

Categories

Resources