CASampledSP
Loading...
Searching...
No Matches
CAAudioFileReader.cpp
Go to the documentation of this file.
1/*
2 * =================================================
3 * Copyright 2011 tagtraum industries incorporated
4 * This file is part of CASampledSP.
5 *
6 * CASampledSP is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * CASampledSP is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with CASampledSP; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * =================================================
20 *
21 * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
22 */
23#include "com_tagtraum_casampledsp_CAAudioFileReader.h"
24#include "CAUtils.h"
25
26
32static jobject create_CoreAudioAudioFileFormat_object(JNIEnv *env, jstring file, jint dataFormat, jfloat sampleRate, jint sampleSize,
33 jint channels, jint frameSize, jfloat frameRate, jint frameLength,
34 jboolean bigEndian, jlong duration,
35 jint bitRate, jboolean vbr) {
36 jclass coreAudioAudioFileFormatClass;
37 jmethodID cid;
38 jobject result = NULL;
39
40 coreAudioAudioFileFormatClass = env->FindClass("com/tagtraum/casampledsp/CAAudioFileFormat");
41 if (coreAudioAudioFileFormatClass == NULL) {
42 return NULL; // exception thrown
43 }
44
45 // Get the method ID for the constructor
46 cid = env->GetMethodID(coreAudioAudioFileFormatClass, "<init>", "(Ljava/lang/String;IFIIIFIZJIZ)V");
47 if (cid == NULL) {
48 return NULL; // exception thrown
49 }
50
51 // Construct an CoreAudioAudioFormat object
52 result = env->NewObject(coreAudioAudioFileFormatClass, cid, file, dataFormat, sampleRate, sampleSize, channels,
53 frameSize, frameRate, frameLength, bigEndian, duration, bitRate, vbr);
54
55 // Free local references
56 env->DeleteLocalRef(coreAudioAudioFileFormatClass);
57 return result;
58}
59
69 (JNIEnv *env, jobject instance, jstring url) {
70
71 int res;
72 AudioFileID infile = NULL;
73 AudioStreamBasicDescription inputFormat;
74 jobject audioFormat = NULL;
75 jlong durationInMicroSeconds;
76 jfloat frameRate;
77 jboolean vbr = JNI_FALSE;
78 jint bitRate;
79 jboolean bigEndian = JNI_TRUE;
80 UInt32 size;
81 CFURLRef inputURLRef;
82 UInt64 dataPacketCount;
83 UInt64 frameLength = 0;
84 const Float64 bitsPerByte = 8.;
85
86 ca_create_url_ref(env, url, inputURLRef);
87 if (inputURLRef == NULL) {
88 throwUnsupportedAudioFileExceptionIfError(env, -1, "Malformed URL. Failed to create CFURL.");
89 goto bail;
90 }
91
92 res = AudioFileOpenURL(inputURLRef, 0x01, 0, &infile); // 0x01 = read only
93 if (res) {
94 if (res == fnfErr) {
95 throwFileNotFoundExceptionIfError(env, res, env->GetStringUTFChars(url, NULL));
96 } else {
97 throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to open audio file");
98 }
99 goto bail;
100 }
101
102 // get the input file format
103 size = sizeof(inputFormat);
104 res = AudioFileGetProperty(infile, kAudioFilePropertyDataFormat, &size, &inputFormat);
105 if (res) {
106 throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to obtain data format");
107 goto bail;
108 }
109
110 size = sizeof(dataPacketCount);
111 res = AudioFileGetProperty(infile, kAudioFilePropertyAudioDataPacketCount, &size, &dataPacketCount);
112 if (res) {
113 throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to obtain audio data packet count");
114 goto bail;
115 }
116 // frameLength = number of frames in javax.sound.sampled
117 frameLength = dataPacketCount;
118 frameRate = (jfloat)(inputFormat.mSampleRate/inputFormat.mFramesPerPacket);
119 durationInMicroSeconds = (jlong)((inputFormat.mFramesPerPacket * dataPacketCount * 1000L * 1000L) / inputFormat.mSampleRate);
120
121 if (inputFormat.mBytesPerPacket && inputFormat.mFramesPerPacket) {
122 bitRate = (jint)(bitsPerByte * (Float64)inputFormat.mBytesPerPacket * inputFormat.mSampleRate / (Float64)inputFormat.mFramesPerPacket);
123 vbr = JNI_FALSE;
124 } else {
125 bitRate = -1;
126 vbr = JNI_TRUE;
127 }
128 bigEndian = (inputFormat.mFormatID == kAudioFormatLinearPCM) && ((kAudioFormatFlagIsBigEndian & inputFormat.mFormatFlags) == kAudioFormatFlagIsBigEndian);
129#ifdef DEBUG
130 fprintf(stderr, "dataPackets: %llu\n", dataPacketCount);
131 fprintf(stderr, "Frames/Pckt: %llu\n", inputFormat.mFramesPerPacket);
132 fprintf(stderr, "sampleRate : %f\n", inputFormat.mSampleRate);
133 fprintf(stderr, "sampleSize : %i\n", inputFormat.mBitsPerChannel);
134 fprintf(stderr, "channels : %i\n", inputFormat.mChannelsPerFrame);
135 fprintf(stderr, "packetSize : %i\n", inputFormat.mBytesPerFrame);
136 fprintf(stderr, "dataFormat : %i\n", inputFormat.mFormatID);
137 fprintf(stderr, "duration : %ld\n", durationInMicroSeconds);
138 fprintf(stderr, "frameRate : %f\n", frameRate);
139 fprintf(stderr, "frameLength: %i\n", frameLength);
140 if (bigEndian) {
141 fprintf(stderr, "bigEndian : true\n");
142 } else {
143 fprintf(stderr, "bigEndian : false\n");
144 }
145#endif
146 audioFormat = create_CoreAudioAudioFileFormat_object(env, url,
147 inputFormat.mFormatID,
148 inputFormat.mSampleRate,
149 inputFormat.mBitsPerChannel,
150 inputFormat.mChannelsPerFrame,
151 inputFormat.mBytesPerFrame,
152 frameRate,
153 (jint)frameLength,
154 bigEndian,
155 durationInMicroSeconds,
156 bitRate,
157 vbr);
158bail:
159 if (infile != NULL) {
160 AudioFileClose(infile);
161 infile = NULL;
162 }
163 return audioFormat;
164}
165
170static void CAAudioFileReader_PacketsProc (
171 void *inClientData,
172 UInt32 inNumberBytes,
173 UInt32 inNumberPackets,
174 const void *inInputData,
175 AudioStreamPacketDescription *inPacketDescriptions
176 ){
177#ifdef DEBUG
178 fprintf(stderr, "CAAudioFileReader_PacketsProc\n");
179#endif
180}
181
186static void CAAudioFileReader_PropertyListenerProc (
187 void *inClientData,
188 AudioFileStreamID inAudioFileStream,
189 AudioFileStreamPropertyID inPropertyID,
190 UInt32 *ioFlags
191 ) {
192#ifdef DEBUG
193 fprintf(stderr, "CAAudioFileReader_PropertyListenerProc\n");
194 fprintf(stderr, "AudioFileStreamPropertyID %i\n", inPropertyID);
195#endif
196}
197
209 (JNIEnv *env, jobject instance, jbyteArray byteArray, jint length, jint hint) {
210 int res;
211 AudioFileStreamID stream = NULL;
212 jobject audioFormat = NULL;
213 jbyte *inBuf = NULL;
214 AudioStreamBasicDescription inputFormat;
215 UInt32 size;
216 jlong durationInMicroSeconds = -1;
217 jfloat frameRate = -1;
218 UInt64 dataPacketCount = -1;
219 UInt64 frameLength = -1;
220 jboolean bigEndian = JNI_TRUE;
221
222 inBuf = env->GetByteArrayElements(byteArray, NULL);
223 res = AudioFileStreamOpen(inBuf, CAAudioFileReader_PropertyListenerProc, CAAudioFileReader_PacketsProc, hint, &stream);
224 if (res) {
225 throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to open audio stream");
226 goto bail;
227 }
228
229 res = AudioFileStreamParseBytes(stream, length, inBuf, kAudioFileStreamPropertyFlag_CacheProperty);
230 if (res) {
231 throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to parse bytes");
232 goto bail;
233 }
234
235 // now check stuff
236 // get the input file format
237 size = sizeof(inputFormat);
238 res = AudioFileStreamGetProperty(stream, kAudioFileStreamProperty_DataFormat, &size, &inputFormat);
239 if (res) {
240 throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to get data format from stream");
241 goto bail;
242 }
243
244 size = sizeof(dataPacketCount);
245 res = AudioFileStreamGetProperty(stream, kAudioFileStreamProperty_AudioDataPacketCount, &size, &dataPacketCount);
246 if (!res) {
247 frameLength = dataPacketCount;
248 durationInMicroSeconds = (jlong)((inputFormat.mFramesPerPacket * dataPacketCount * 1000L * 1000L) / inputFormat.mSampleRate);
249 frameRate = (jfloat)(dataPacketCount*inputFormat.mSampleRate/frameLength);
250 }
251// if (!res && inputFormat.mFramesPerPacket) {
252// frameLength = inputFormat.mFramesPerPacket * dataPacketCount;
253// durationInMicroSeconds = (jlong)((frameLength * 1000L * 1000L) / inputFormat.mSampleRate);
254// frameRate = (jfloat)(dataPacketCount*inputFormat.mSampleRate/frameLength);
255// }
256 bigEndian = (inputFormat.mFormatID == kAudioFormatLinearPCM) && ((kAudioFormatFlagIsBigEndian & inputFormat.mFormatFlags) == kAudioFormatFlagIsBigEndian);
257 audioFormat = create_CoreAudioAudioFileFormat_object(env, NULL,
258 inputFormat.mFormatID,
259 inputFormat.mSampleRate,
260 inputFormat.mBitsPerChannel,
261 inputFormat.mChannelsPerFrame,
262 inputFormat.mBytesPerFrame,
263 frameRate,
264 (jint)frameLength,
265 bigEndian,
266 durationInMicroSeconds,
267 -1, //bitRate,
268 false //vbr
269 );
270
271bail:
272 if (inBuf != NULL) {
273 env->ReleaseByteArrayElements(byteArray, inBuf, JNI_ABORT);
274 }
275 if (stream != NULL) {
276 AudioFileStreamClose(stream);
277 stream = NULL;
278 }
279 return audioFormat;
280}
281
282
JNIEXPORT jobject JNICALL Java_com_tagtraum_casampledsp_CAAudioFileReader_intGetAudioFormat___3BII(JNIEnv *env, jobject instance, jbyteArray byteArray, jint length, jint hint)
Creates a CoreAudioFileFormat for the first X bytes of a stream.
JNIEXPORT jobject JNICALL Java_com_tagtraum_casampledsp_CAAudioFileReader_intGetAudioFormat__Ljava_lang_String_2(JNIEnv *env, jobject instance, jstring url)
Creates a CoreAudioFileFormat for a URL.
void throwFileNotFoundExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an IllegalArgumentException.
Definition CAUtils.cpp:90
void throwUnsupportedAudioFileExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an UnsupportedAudioFileException exception.
Definition CAUtils.cpp:39
void ca_create_url_ref(JNIEnv *env, jstring path, CFURLRef &urlRef)
Creates a CFURLRef from the given path.
Definition CAUtils.cpp:101