1/***********************************************************************
2 * AUTHOR: Marcus Overhagen
3 *   FILE: SoundFile.cpp
4 *  DESCR:
5 ***********************************************************************/
6#include <MediaFile.h>
7#include <MediaTrack.h>
8#include <SoundFile.h>
9
10#include <string.h>
11
12#include "MediaDebug.h"
13
14/*************************************************************
15 * public BSoundFile
16 *************************************************************/
17
18BSoundFile::BSoundFile()
19{
20	_init_raw_stats();
21}
22
23
24BSoundFile::BSoundFile(const entry_ref *ref,
25					   uint32 open_mode)
26{
27	_init_raw_stats();
28	SetTo(ref,open_mode);
29}
30
31/* virtual */
32BSoundFile::~BSoundFile()
33{
34	delete fSoundFile;
35	delete fMediaFile;
36		// fMediaTrack will be deleted by the BMediaFile destructor
37}
38
39
40status_t
41BSoundFile::InitCheck() const
42{
43	if (!fSoundFile) {
44		return B_NO_INIT;
45	}
46	return fSoundFile->InitCheck();
47}
48
49
50status_t
51BSoundFile::SetTo(const entry_ref *ref,
52				  uint32 open_mode)
53{
54	if (fMediaTrack) {
55		BMediaTrack * track = fMediaTrack;
56		fMediaTrack = 0;
57		fMediaFile->ReleaseTrack(track);
58	}
59	if (fMediaFile) {
60		BMediaFile * file = fMediaFile;
61		fMediaFile = 0;
62		delete file;
63	}
64	if (fSoundFile) {
65		BFile * file = fSoundFile;
66		fSoundFile = 0;
67		delete file;
68	}
69	if (open_mode == B_READ_ONLY) {
70		return _ref_to_file(ref);
71	} else {
72		UNIMPLEMENTED();
73		return B_ERROR;
74	}
75}
76
77
78int32
79BSoundFile::FileFormat() const
80{
81	return fFileFormat;
82}
83
84
85int32
86BSoundFile::SamplingRate() const
87{
88	return fSamplingRate;
89}
90
91
92int32
93BSoundFile::CountChannels() const
94{
95	return fChannelCount;
96}
97
98
99int32
100BSoundFile::SampleSize() const
101{
102	return fSampleSize;
103}
104
105
106int32
107BSoundFile::ByteOrder() const
108{
109	return fByteOrder;
110}
111
112
113int32
114BSoundFile::SampleFormat() const
115{
116	return fSampleFormat;
117}
118
119
120int32
121BSoundFile::FrameSize() const
122{
123	return fSampleSize * fChannelCount;
124}
125
126
127off_t
128BSoundFile::CountFrames() const
129{
130	return fFrameCount;
131}
132
133
134bool
135BSoundFile::IsCompressed() const
136{
137	return fIsCompressed;
138}
139
140
141int32
142BSoundFile::CompressionType() const
143{
144	return fCompressionType;
145}
146
147
148char *
149BSoundFile::CompressionName() const
150{
151	return fCompressionName;
152}
153
154
155/* virtual */ int32
156BSoundFile::SetFileFormat(int32 format)
157{
158	fFileFormat = format;
159	return fFileFormat;
160}
161
162
163/* virtual */ int32
164BSoundFile::SetSamplingRate(int32 fps)
165{
166	fSamplingRate = fps;
167	return fSamplingRate;
168}
169
170
171/* virtual */ int32
172BSoundFile::SetChannelCount(int32 spf)
173{
174	fChannelCount = spf;
175	return fChannelCount;
176}
177
178
179/* virtual */ int32
180BSoundFile::SetSampleSize(int32 bps)
181{
182	fSampleSize = bps;
183	return fSampleSize;
184}
185
186
187/* virtual */ int32
188BSoundFile::SetByteOrder(int32 bord)
189{
190	fByteOrder = bord;
191	return fByteOrder;
192}
193
194
195/* virtual */ int32
196BSoundFile::SetSampleFormat(int32 fmt)
197{
198	fSampleFormat = fmt;
199	return fSampleFormat;
200}
201
202
203/* virtual */ int32
204BSoundFile::SetCompressionType(int32 type)
205{
206	return 0;
207}
208
209
210/* virtual */ char *
211BSoundFile::SetCompressionName(char *name)
212{
213	return NULL;
214}
215
216
217/* virtual */ bool
218BSoundFile::SetIsCompressed(bool tf)
219{
220	return false;
221}
222
223
224/* virtual */ off_t
225BSoundFile::SetDataLocation(off_t offset)
226{
227	UNIMPLEMENTED();
228
229	return 0;
230}
231
232
233/* virtual */ off_t
234BSoundFile::SetFrameCount(off_t count)
235{
236	fFrameCount = count;
237	return fFrameCount;
238}
239
240
241size_t
242BSoundFile::ReadFrames(char *buf,
243					   size_t count)
244{
245	size_t frameRead = 0;
246	int64 frames = count;
247	while (count > 0) {
248		status_t status = fMediaTrack->ReadFrames(
249				reinterpret_cast<void *>(buf), &frames);
250		count -= frames;
251		frameRead += frames;
252		buf += fSampleSize * fChannelCount * frames;
253		if (status != B_OK) {
254			if (frameRead > 0)
255				break;
256			return status;
257		}
258	}
259	return frameRead;
260}
261
262
263size_t
264BSoundFile::WriteFrames(char *buf,
265						size_t count)
266{
267	return fMediaTrack->WriteFrames(
268			reinterpret_cast<void *>(buf), count);
269}
270
271
272/* virtual */ off_t
273BSoundFile::SeekToFrame(off_t n)
274{
275	int64 frames = n;
276	status_t status = fMediaTrack->SeekToFrame(&frames);
277
278	if (status != B_OK)
279		return status;
280
281	return frames;
282}
283
284
285off_t
286BSoundFile::FrameIndex() const
287{
288	return fFrameIndex;
289}
290
291
292off_t
293BSoundFile::FramesRemaining() const
294{
295	return fFrameCount - FrameIndex();
296}
297
298/*************************************************************
299 * private BSoundFile
300 *************************************************************/
301
302
303void BSoundFile::_ReservedSoundFile1() {}
304void BSoundFile::_ReservedSoundFile2() {}
305void BSoundFile::_ReservedSoundFile3() {}
306
307void
308BSoundFile::_init_raw_stats()
309{
310	fSoundFile = 0;
311	fMediaFile = 0;
312	fMediaTrack = 0;
313	fFileFormat = B_UNKNOWN_FILE;
314	fSamplingRate = 44100;
315	fChannelCount = 2;
316	fSampleSize = 2;
317	fByteOrder = B_BIG_ENDIAN;
318	fSampleFormat = B_LINEAR_SAMPLES;
319	fFrameCount = 0;
320	fFrameIndex = 0;
321	fIsCompressed = false;
322	fCompressionType = -1;
323	fCompressionName = NULL;
324}
325
326
327static int32
328_ParseMimeType(char *mime_type)
329{
330	if (strcmp(mime_type, "audio/x-aiff") == 0)
331		return B_AIFF_FILE;
332	if (strcmp(mime_type, "audio/x-wav") == 0)
333		return B_WAVE_FILE;
334	return B_UNKNOWN_FILE;
335}
336
337
338status_t
339BSoundFile::_ref_to_file(const entry_ref *ref)
340{
341	status_t status;
342	BFile * file = new BFile(ref, B_READ_ONLY);
343	status = file->InitCheck();
344	if (status != B_OK) {
345		fSoundFile = file;
346		return status;
347	}
348	BMediaFile * media = new BMediaFile(file);
349	status = media->InitCheck();
350	if (status != B_OK) {
351		delete media;
352		delete file;
353		return status;
354	}
355	media_file_format mfi;
356	media->GetFileFormatInfo(&mfi);
357	switch (mfi.family) {
358		case B_AIFF_FORMAT_FAMILY: fFileFormat = B_AIFF_FILE; break;
359		case B_WAV_FORMAT_FAMILY:  fFileFormat = B_WAVE_FILE; break;
360		default: fFileFormat = _ParseMimeType(mfi.mime_type); break;
361	}
362	int trackNum = 0;
363	BMediaTrack * track = 0;
364	media_format mf;
365	while (trackNum < media->CountTracks()) {
366		track = media->TrackAt(trackNum);
367		status = track->DecodedFormat(&mf);
368		if (status != B_OK) {
369			media->ReleaseTrack(track);
370			delete media;
371			delete file;
372			return status;
373		}
374		if (mf.IsAudio()) {
375			break;
376		}
377		media->ReleaseTrack(track);
378		track = 0;
379	}
380	if (track == 0) {
381		delete media;
382		delete file;
383		return B_ERROR;
384	}
385	media_raw_audio_format * raw = 0;
386	if (mf.type == B_MEDIA_ENCODED_AUDIO) {
387		raw = &mf.u.encoded_audio.output;
388	}
389	if (mf.type == B_MEDIA_RAW_AUDIO) {
390		raw = &mf.u.raw_audio;
391	}
392
393	if (raw == NULL) {
394		delete media;
395		delete file;
396		return B_ERROR;
397	}
398
399	fSamplingRate = (int)raw->frame_rate;
400	fChannelCount = raw->channel_count;
401	fSampleSize = raw->format & 0xf;
402	fByteOrder = raw->byte_order;
403	switch (raw->format) {
404		case media_raw_audio_format::B_AUDIO_FLOAT:
405			fSampleFormat = B_FLOAT_SAMPLES;
406			break;
407		case media_raw_audio_format::B_AUDIO_INT:
408		case media_raw_audio_format::B_AUDIO_SHORT:
409		case media_raw_audio_format::B_AUDIO_UCHAR:
410		case media_raw_audio_format::B_AUDIO_CHAR:
411			fSampleFormat = B_LINEAR_SAMPLES;
412			break;
413		default:
414			fSampleFormat = B_UNDEFINED_SAMPLES;
415	}
416	fByteOffset = 0;
417	fFrameCount = track->CountFrames();
418	fFrameIndex = 0;
419	if (mf.type == B_MEDIA_ENCODED_AUDIO) {
420		fIsCompressed = true;
421		fCompressionType = mf.u.encoded_audio.encoding;
422	}
423	fMediaFile = media;
424	fMediaTrack = track;
425	fSoundFile = file;
426	return B_OK;
427}
428
429
430