CASampledSP
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  * FFSampledSP 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  * FFSampledSP 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 FFSampledSP; 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  */
24 #include "CAUtils.h"
25 
26 
32 static jobject create_CoreAudioAudioFormat_object(JNIEnv *env, jstring file, jint dataFormat, jfloat sampleRate, jint sampleSize,
33  jint channels, jint frameSize, jfloat frameRate, jboolean bigEndian, jlong duration,
34  jint bitRate, jboolean vbr) {
35  jclass coreAudioAudioFormatClass;
36  jmethodID cid;
37  jobject result = NULL;
38 
39  coreAudioAudioFormatClass = env->FindClass("com/tagtraum/casampledsp/CAAudioFileFormat");
40  if (coreAudioAudioFormatClass == NULL) {
41  return NULL; // exception thrown
42  }
43 
44  // Get the method ID for the constructor
45  cid = env->GetMethodID(coreAudioAudioFormatClass, "<init>", "(Ljava/lang/String;IFIIIFZJIZ)V");
46  if (cid == NULL) {
47  return NULL; // exception thrown
48  }
49 
50  // Construct an CoreAudioAudioFormat object
51  result = env->NewObject(coreAudioAudioFormatClass, cid, file, dataFormat, sampleRate, sampleSize, channels, frameSize, frameRate, bigEndian, duration, bitRate, vbr);
52 
53  // Free local references
54  env->DeleteLocalRef(coreAudioAudioFormatClass);
55  return result;
56 }
57 
67  (JNIEnv *env, jobject instance, jstring url) {
68 
69  int res;
70  AudioFileID infile = NULL;
71  AudioStreamBasicDescription inputFormat;
72  jobject audioFormat = NULL;
73  jlong durationInMs;
74  jfloat frameRate;
75  jboolean vbr = JNI_FALSE;
76  jint bitRate;
77  jboolean bigEndian = JNI_TRUE;
78  UInt32 size;
79  CFURLRef inputURLRef;
80  UInt64 dataPacketCount;
81  UInt64 frames = 0;
82  const Float64 bitsPerByte = 8.;
83 
84  ca_create_url_ref(env, url, inputURLRef);
85  if (inputURLRef == NULL) {
86  throwUnsupportedAudioFileExceptionIfError(env, -1, "Malformed URL. Failed to create CFURL.");
87  goto bail;
88  }
89 
90  res = AudioFileOpenURL(inputURLRef, 0x01, 0, &infile); // 0x01 = read only
91  if (res) {
92  if (res == fnfErr) {
93  throwFileNotFoundExceptionIfError(env, res, env->GetStringUTFChars(url, NULL));
94  } else {
95  throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to open audio file");
96  }
97  goto bail;
98  }
99 
100  // get the input file format
101  size = sizeof(inputFormat);
102  res = AudioFileGetProperty(infile, kAudioFilePropertyDataFormat, &size, &inputFormat);
103  if (res) {
104  throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to obtain data format");
105  goto bail;
106  }
107 
108  size = sizeof(dataPacketCount);
109  res = AudioFileGetProperty(infile, kAudioFilePropertyAudioDataPacketCount, &size, &dataPacketCount);
110  if (res) {
111  throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to obtain audio data packet count");
112  goto bail;
113  }
114  if (inputFormat.mFramesPerPacket) {
115  frames = inputFormat.mFramesPerPacket * dataPacketCount;
116  }
117  durationInMs = (jlong)((frames * 1000) / inputFormat.mSampleRate);
118  frameRate = (jfloat)(dataPacketCount*inputFormat.mSampleRate/frames);
119 
120  if (inputFormat.mBytesPerPacket && inputFormat.mFramesPerPacket) {
121  bitRate = (jint)(bitsPerByte * (Float64)inputFormat.mBytesPerPacket * inputFormat.mSampleRate / (Float64)inputFormat.mFramesPerPacket);
122  vbr = JNI_FALSE;
123  } else {
124  bitRate = -1;
125  vbr = JNI_TRUE;
126  }
127  bigEndian = (inputFormat.mFormatID == kAudioFormatLinearPCM) && ((kAudioFormatFlagIsBigEndian & inputFormat.mFormatFlags) == kAudioFormatFlagIsBigEndian);
128 #ifdef DEBUG
129  fprintf(stderr, "sampleRate: %f\n", inputFormat.mSampleRate);
130  fprintf(stderr, "sampleSize: %i\n", inputFormat.mBitsPerChannel);
131  fprintf(stderr, "channels : %i\n", inputFormat.mChannelsPerFrame);
132  fprintf(stderr, "packetSize: %i\n", inputFormat.mBytesPerFrame);
133  fprintf(stderr, "dataFormat: %i\n", inputFormat.mFormatID);
134  fprintf(stderr, "duration : %ld\n", durationInMs);
135  fprintf(stderr, "frameRate : %f\n", frameRate);
136  if (bigEndian) {
137  fprintf(stderr, "bigEndian : true\n");
138  } else {
139  fprintf(stderr, "bigEndian : false\n");
140  }
141 #endif
142  audioFormat = create_CoreAudioAudioFormat_object(env, url,
143  inputFormat.mFormatID,
144  inputFormat.mSampleRate,
145  inputFormat.mBitsPerChannel,
146  inputFormat.mChannelsPerFrame,
147  inputFormat.mBytesPerFrame,
148  frameRate,
149  bigEndian,
150  durationInMs,
151  bitRate,
152  vbr);
153 bail:
154  if (infile != NULL) {
155  AudioFileClose(infile);
156  infile = NULL;
157  }
158  return audioFormat;
159 }
160 
165 static void CAAudioFileReader_PacketsProc (
166  void *inClientData,
167  UInt32 inNumberBytes,
168  UInt32 inNumberPackets,
169  const void *inInputData,
170  AudioStreamPacketDescription *inPacketDescriptions
171  ){
172 #ifdef DEBUG
173  fprintf(stderr, "CAAudioFileReader_PacketsProc\n");
174 #endif
175 }
176 
181 static void CAAudioFileReader_PropertyListenerProc (
182  void *inClientData,
183  AudioFileStreamID inAudioFileStream,
184  AudioFileStreamPropertyID inPropertyID,
185  UInt32 *ioFlags
186  ) {
187 #ifdef DEBUG
188  fprintf(stderr, "CAAudioFileReader_PropertyListenerProc\n");
189  fprintf(stderr, "AudioFileStreamPropertyID %i\n", inPropertyID);
190 #endif
191 }
192 
204  (JNIEnv *env, jobject instance, jbyteArray byteArray, jint length, jint hint) {
205  int res;
206  AudioFileStreamID stream = NULL;
207  jobject audioFormat = NULL;
208  jbyte *inBuf = NULL;
209  AudioStreamBasicDescription inputFormat;
210  UInt32 size;
211  jlong durationInMs = -1;
212  jfloat frameRate = -1;
213  UInt64 dataPacketCount = -1;
214  UInt64 frames = -1;
215  jboolean bigEndian = JNI_TRUE;
216 
217  inBuf = env->GetByteArrayElements(byteArray, NULL);
218  res = AudioFileStreamOpen(inBuf, CAAudioFileReader_PropertyListenerProc, CAAudioFileReader_PacketsProc, hint, &stream);
219  if (res) {
220  throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to open audio stream");
221  goto bail;
222  }
223 
224  res = AudioFileStreamParseBytes(stream, length, inBuf, kAudioFileStreamPropertyFlag_CacheProperty);
225  if (res) {
226  throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to parse bytes");
227  goto bail;
228  }
229 
230  // now check stuff
231  // get the input file format
232  size = sizeof(inputFormat);
233  res = AudioFileStreamGetProperty(stream, kAudioFileStreamProperty_DataFormat, &size, &inputFormat);
234  if (res) {
235  throwUnsupportedAudioFileExceptionIfError(env, res, "Failed to get data format from stream");
236  goto bail;
237  }
238 
239  size = sizeof(dataPacketCount);
240  res = AudioFileStreamGetProperty(stream, kAudioFileStreamProperty_AudioDataPacketCount, &size, &dataPacketCount);
241  if (!res && inputFormat.mFramesPerPacket) {
242  frames = inputFormat.mFramesPerPacket * dataPacketCount;
243  durationInMs = (jlong)((frames * 1000) / inputFormat.mSampleRate);
244  frameRate = (jfloat)(dataPacketCount*inputFormat.mSampleRate/frames);
245  }
246  bigEndian = (inputFormat.mFormatID == kAudioFormatLinearPCM) && ((kAudioFormatFlagIsBigEndian & inputFormat.mFormatFlags) == kAudioFormatFlagIsBigEndian);
247  audioFormat = create_CoreAudioAudioFormat_object(env, NULL,
248  inputFormat.mFormatID,
249  inputFormat.mSampleRate,
250  inputFormat.mBitsPerChannel,
251  inputFormat.mChannelsPerFrame,
252  inputFormat.mBytesPerFrame,
253  frameRate,
254  bigEndian,
255  durationInMs,
256  -1, //bitRate,
257  false //vbr
258  );
259 
260 bail:
261  if (inBuf != NULL) {
262  env->ReleaseByteArrayElements(byteArray, inBuf, JNI_ABORT);
263  }
264  if (stream != NULL) {
265  AudioFileStreamClose(stream);
266  stream = NULL;
267  }
268  return audioFormat;
269 }
270 
271 
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 ca_create_url_ref(JNIEnv *env, jstring path, CFURLRef &urlRef)
Creates a CFURLRef from the given path.
Definition: CAUtils.cpp:101
void throwUnsupportedAudioFileExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an UnsupportedAudioFileException exception.
Definition: CAUtils.cpp:39
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.
void throwFileNotFoundExceptionIfError(JNIEnv *env, int err, const char *message)
Throws an IllegalArgumentException.
Definition: CAUtils.cpp:90