examining audio file alternative to spotlight - cocoa

i'm looking for an efficient alternative to grabbing audio file attributes in case spotlight is turned off.
Spotlight's MDItem attributes: kMDItemDurationSeconds, kMDItemAudioEncodingApplication, kMDItemAudioBitRate, kMDItemAudioSampleRate,kMDItemAudioChannelCount, kMDItemCodecs, are possible.
however QTKit's movieAttributes (if the file can be a QTMovie type), are not as complete, only QTMovieDurationAttribute fills my spec.
should i use Audio Format Services : OSStatus AudioFormatGetProperty, or is there something else, perhaps more light-weight that will suffice in the absence of MDItem information ?
i don't need to modify or play any files, i only need to know the property values.
thanks.

Get attributes from the audio track's media, not the movie. Here is an example of how to get duration in seconds.
for (QTTrack* track in [movie tracks])
{
QTMedia* trackMedia = [track media];
if ([trackMedia hasCharacteristic:QTMediaCharacteristicAudio])
{
QTTime mediaDuration = [(NSValue*)[trackMedia attributeForKey:QTMediaDurationAttribute] QTTimeValue];
long long mediaDurationScaleValue = mediaDuration.timeScale;
long long mediaDurationTimeValue = mediaDuration.timeValue;
result = (double)mediaDurationTimeValue / (double)mediaDurationScaleValue;
break;
}
}
[trackMedia mediaAttributes] will give you other available attributes of the audio.

If you are not afraid of using the Terminal, mdls is probably the tool for you:
mdls /path/toYour/file

Related

AVFoundation - What is the best way to re-encode a video file (to add more keyframes)?

I have a mp4 file that doesn't seek accurately, and seeking backwards is slow. I believe it is caused by a heavily compressed encoding.
What is the best way to re-encode this file using AVFoundation so that I can make every frame a key frame?
The standard way to set the (max) key frame interval is AVVideoMaxKeyFrameIntervalKey.
The corresponding value is an instance of NSNumber. 1 means key frames
only.
You could apply it to an AVAssetWriter object, which might look similar to this:
NSDictionary *compProps = #{ AVVideoAverageBitRateKey : #(bitsPerSecond),
AVVideoExpectedSourceFrameRateKey : #(30),
AVVideoMaxKeyFrameIntervalKey : #(1) };
_videoInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo
outputSettings:compProps];
↳ AVVideoMaxKeyFrameIntervalKey

How does one discover [non-Apple] Audio Units with Audio Component Services?

In OS X, I am trying to find an example of how to discover all the Audio Units installed on an end-users system and get back that information for display and use.
I know that Audio Component is involved with that task, but I am completely baffled how to go about doing it. All the examples I come across are based around finding a 'known' Apple AU with AudioComponentFindNext, and I cannot find an example for discovering anything else.
Can anyone point me to an example?
Thanks
You can set up a AudioComponentDescription struct using 0 as a wildcard for type, subtype, and manufacturer. Pass that to AudioComponentFindNext:
AudioComponentDescription acd = { 0 };
AudioComponent comp = nullptr;
while((comp = AudioComponentFindNext(comp, &acd)) {
// Found an AU
}
Here is some relevant documentation from the header:
#function AudioComponentFindNext
#abstract Finds an audio component.
#discussion This function is used to find an audio component that is the closest match
to the provided values.
#param inComponent
If NULL, then the search starts from the beginning until an audio
component is found that matches the description provided by inDesc.
If non-NULL, then the search starts (continues) from the previously
found audio component specified by inComponent, and will return the next
found audio component.
#param inDesc
The type, subtype and manufacturer fields are used to specify the audio
component to search for. A value of 0 (zero) for any of these fields is
a wildcard, so the first match found is returned.
#result An audio component that matches the search parameters, or NULL if none found.
Simply use the provided AVAudioUnitComponentManager components function to get audio units.
It will return an array of audio units that match the AudioComponentDescription you pass.
Command click AudioComponentDescription and kAudioUnitType_MusicDevice to see the various values you can use.
// Exemple to get instruments audio units
var match = AudioComponentDescription()
match.componentType = kAudioUnitType_MusicDevice
let audioUnitComponents = AVAudioUnitComponentManager.shared().components(matching: match)

How to get file MFT entry/inode using Java or C++

I've written a duplicate finder in Java, but I need to include hard link support for it. Unfortunately, there seems to be no way to dig out a file's MFT entry in Java.
Although there is a method called fileKey() in the BasicFileAttributeView class, it won't work on the NTFS file system (I haven't tested it on ext yet).
I also found the method isSameFile() (in java.nio.file.Path). Does anyone know how this method works? It seems to be doing the right thing, but it returns a Boolean value, so it is worthless for me (I wish to put the results into a map and group them by their MFT entries).
I can always compare the creation times, modification times, etc. for each file, but this is just giving up.
Is there any way to accomplish what I am trying to do in either C++ or Java? I care more about making it work on NTFS than ext.
You would need to use the FILE_ID_FULL_DIRECTORY_INFORMATION structure along with the NtQueryDirectoryFile function (or the FILE_INTERNAL_INFORMATION structure along with the NtQueryInformationFile, if you already have a handle) inside ntdll.dll (available since Windows XP, if not earlier) to get the 8-byte file IDs and check if they are the same.
This will tell you if they are the same file, but not if they are the same stream of the same file.
I'm not sure how to detect if two files are the same stream from user-mode -- there is a structure named FILE_STREAM_INFORMATION which can return all the streams associated with a file, but it doesn't tell you which stream you have currently opened.
Detecting hard links is usually accomplished by calling FindFirstFileNameW. But there is a lower level way.
To get the NTFS equivalent to inodes, try the FSCTL_GET_OBJECT_ID ioctl code.
There's a unique (until the file is deleted) identifier in the BY_HANDLE_FILE_INFORMATION structure as well.
If the volume has an enabled USN Change Journal, you can issue the FSCTL_READ_FILE_USN_DATA ioctl code. Check the FileReferenceNumber member in the USN_RECORD structure
In Java you can use sun.nio.ch.FileKey which is a non-transparent enclosure for NTFS Inode. All the hard links share the same Inode.
Therefore, if you need to collect hard links, you can create FileKey from each suspect and compare them (e.g. by putting pairs of FileKey -> File into a Multimap)
I find fileKey is always null. Here is some code that can actually read the NTFS inode number. There remain many aspects I'm not happy with, not least, it relies on reflection.
import sun.nio.ch.FileKey;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Path;
class NTFS {
static long inodeFromPath(Path path) throws IOException, NoSuchFieldException, IllegalAccessException {
try (FileInputStream fi = new FileInputStream(path.toFile())) {
FileDescriptor fd = fi.getFD();
FileKey fk = FileKey.create(fd);
Field privateField = FileKey.class.getDeclaredField("nFileIndexHigh");
privateField.setAccessible(true);
long high = (long) privateField.get(fk);
privateField = FileKey.class.getDeclaredField("nFileIndexLow");
privateField.setAccessible(true);
long low = (long) privateField.get(fk);
long power = (long) 1 << 32;
long inode = high * power + low;
return inode;
}
}
}

how do i find out duration/total play time of an mp3 file using java?

I am developing an application in Java. Part of it includes playing an mp3 file via another application. I need to find the duration (total play time) of the mp3 file. How do I do that?
You can do this very easily using JAudioTagger:
Tag tag;
java.util.logging.Logger.getLogger("org.jaudiotagger").setLevel(Level.OFF);
audioFile = AudioFileIO.read(new File(filePath));
System.out.println("Track length = " + audioFile.getAudioHeader().getTrackLength());
That will print out the track length of the file at filePath. The logger line is to remove a lot of (probably) unwanted info/debugging logging from JAudioTagger. Besides this, JAudioTagger supports getting all sorts of metadata tags from different audio file types (MP3, MP4, WMA, FLAC, Ogg Vorbis), both from file-embedded tags. You can even get MusicBrainz info easily, but I haven't tried that yet. For more info:
http://www.jthink.net/jaudiotagger/examples_read.jsp
You can get the jar files for it here:
http://download.java.net/maven/2/org/jaudiotagger/
For small .mp3 files you can use:
AudioFile audioFile = AudioFileIO.read(MyFileChooser.fileName);
int duration= audioFile.getAudioHeader().getTrackLength();
System.out.println(duration);
This will give a string containing the minute and second duration in it. eg: 316 for 3:16.
Note that This method is not suitable with larger files.

How can I find out all audio files whose formats are supported by AVAudioPlayer in Lion 10.7?

I want to use codes like this.
NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
[query setSearchScopes: [NSArray arrayWithObject: [NSURL fileURLWithPath:#"/Users/Someone/Music" isDirectory:YES]]];
[query setPredicate: predicate];
...
...
Now how do I suppose to set "predicate" to filter out those files with unsupported format??
kMDItemCodezs,kMDItemMediaTypes,kMDItemContentType,kMDItemKind?
Which one should I use? And what are all the possible values of these attibutes corresponding to the supported format in AVAudioPlayer in Lion 10.7? Thanks a lot.
To obtain a list of most supported formats, you can use AudioFileGetGlobalInfo in the AudioToolbox framework to get the UTIs supported by Core Audio (using kAudioFileGlobalInfo_AllUTIs):
UInt32 size;
NSArray *all;
OSStatus err;
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AllUTIs, 0, NULL, &size);
if (err == noErr)
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AllUTIs, 0, NULL, &size, &all);
if (err == noErr)
NSLog(#"UTIs: %#", all);
[all release];
On 10.7, this gives me:
"public.aiff-audio",
"public.ulaw-audio",
"org.3gpp.adaptive-multi-rate-audio",
"com.microsoft.waveform-audio",
"public.3gpp2",
"com.apple.coreaudio-format",
"public.3gpp",
"public.mp3",
"public.au-audio",
"public.mpeg-4-audio",
"public.mpeg-4",
"com.apple.m4a-audio",
"public.aifc-audio"
Unfortunately UTIs aren't defined for some of the more obscure data formats (e.g. .mp1/.mp2) Core Audio supports; if you're happy with the above subset, then just use the UTIs.
Then turn those into a NSMetadataQuery (kMDItemContentType for kAudioFileGlobalInfo_AllUTIs). If you want to cover the rest of the formats, you can match by HFS type and extension: kMDItemFSTypeCode for kAudioFileGlobalInfo_AllHFSTypeCodes, and a wildcard match of kMDItemFSName for kAudioFileGlobalInfo_AllExtensions. You can use afconvert -hf to display both of these.
Matching with NSMetadataQuery will of course not look inside all of the files, so it'll still find text files renamed with a .mp3 extension. Since Spotlight does try to index other audio attributes, you could try checking kMDItemAudioBitRate and so forth; these will be missing on a file that isn't actually an audio file. Depending on how accurate you want to be in filtering, you can also try opening each file to see if it's playable.
Use kMDItemContentTypeTree, and the audio type. This will match any audio files, ignoring movie files. If you want to include movie files, search for the audio-visual content type, which the audio type conforms to (descends from).
Edit: This will match all known audio types, regardless of whether Core Audio (let alone AVAudioPlayer) can play them. Nicholas Riley's solution is better.

Resources