152a38012Sejakowatz/***********************************************************************
252a38012Sejakowatz * AUTHOR: Marcus Overhagen
352a38012Sejakowatz *   FILE: SoundFile.cpp
452a38012Sejakowatz *  DESCR:
552a38012Sejakowatz ***********************************************************************/
67e0c41c1Sshatty#include <MediaFile.h>
77e0c41c1Sshatty#include <MediaTrack.h>
852a38012Sejakowatz#include <SoundFile.h>
91942b3b1SAdrien Destugues
101942b3b1SAdrien Destugues#include <string.h>
111942b3b1SAdrien Destugues
12b84955d4SBarrett#include "MediaDebug.h"
1352a38012Sejakowatz
1452a38012Sejakowatz/*************************************************************
1552a38012Sejakowatz * public BSoundFile
1652a38012Sejakowatz *************************************************************/
1752a38012Sejakowatz
1852a38012SejakowatzBSoundFile::BSoundFile()
1952a38012Sejakowatz{
207e0c41c1Sshatty	_init_raw_stats();
2152a38012Sejakowatz}
2252a38012Sejakowatz
2352a38012Sejakowatz
2452a38012SejakowatzBSoundFile::BSoundFile(const entry_ref *ref,
2552a38012Sejakowatz					   uint32 open_mode)
2652a38012Sejakowatz{
277e0c41c1Sshatty	_init_raw_stats();
287e0c41c1Sshatty	SetTo(ref,open_mode);
2952a38012Sejakowatz}
3052a38012Sejakowatz
3152a38012Sejakowatz/* virtual */
3252a38012SejakowatzBSoundFile::~BSoundFile()
3352a38012Sejakowatz{
347e0c41c1Sshatty	delete fSoundFile;
35b0acb3feSStefano Ceccherini	delete fMediaFile;
36b0acb3feSStefano Ceccherini		// fMediaTrack will be deleted by the BMediaFile destructor
3752a38012Sejakowatz}
3852a38012Sejakowatz
3952a38012Sejakowatz
4052a38012Sejakowatzstatus_t
4152a38012SejakowatzBSoundFile::InitCheck() const
4252a38012Sejakowatz{
437e0c41c1Sshatty	if (!fSoundFile) {
447e0c41c1Sshatty		return B_NO_INIT;
457e0c41c1Sshatty	}
467e0c41c1Sshatty	return fSoundFile->InitCheck();
4752a38012Sejakowatz}
4852a38012Sejakowatz
4952a38012Sejakowatz
5052a38012Sejakowatzstatus_t
5152a38012SejakowatzBSoundFile::SetTo(const entry_ref *ref,
5252a38012Sejakowatz				  uint32 open_mode)
5352a38012Sejakowatz{
547e0c41c1Sshatty	if (fMediaTrack) {
557e0c41c1Sshatty		BMediaTrack * track = fMediaTrack;
567e0c41c1Sshatty		fMediaTrack = 0;
577e0c41c1Sshatty		fMediaFile->ReleaseTrack(track);
587e0c41c1Sshatty	}
597e0c41c1Sshatty	if (fMediaFile) {
607e0c41c1Sshatty		BMediaFile * file = fMediaFile;
617e0c41c1Sshatty		fMediaFile = 0;
627e0c41c1Sshatty		delete file;
637e0c41c1Sshatty	}
647e0c41c1Sshatty	if (fSoundFile) {
657e0c41c1Sshatty		BFile * file = fSoundFile;
667e0c41c1Sshatty		fSoundFile = 0;
677e0c41c1Sshatty		delete file;
687e0c41c1Sshatty	}
697e0c41c1Sshatty	if (open_mode == B_READ_ONLY) {
707e0c41c1Sshatty		return _ref_to_file(ref);
717e0c41c1Sshatty	} else {
727e0c41c1Sshatty		UNIMPLEMENTED();
737e0c41c1Sshatty		return B_ERROR;
747e0c41c1Sshatty	}
7552a38012Sejakowatz}
7652a38012Sejakowatz
7752a38012Sejakowatz
7852a38012Sejakowatzint32
7952a38012SejakowatzBSoundFile::FileFormat() const
8052a38012Sejakowatz{
817e0c41c1Sshatty	return fFileFormat;
8252a38012Sejakowatz}
8352a38012Sejakowatz
8452a38012Sejakowatz
8552a38012Sejakowatzint32
8652a38012SejakowatzBSoundFile::SamplingRate() const
8752a38012Sejakowatz{
887e0c41c1Sshatty	return fSamplingRate;
8952a38012Sejakowatz}
9052a38012Sejakowatz
9152a38012Sejakowatz
9252a38012Sejakowatzint32
9352a38012SejakowatzBSoundFile::CountChannels() const
9452a38012Sejakowatz{
957e0c41c1Sshatty	return fChannelCount;
9652a38012Sejakowatz}
9752a38012Sejakowatz
9852a38012Sejakowatz
9952a38012Sejakowatzint32
10052a38012SejakowatzBSoundFile::SampleSize() const
10152a38012Sejakowatz{
1027e0c41c1Sshatty	return fSampleSize;
10352a38012Sejakowatz}
10452a38012Sejakowatz
10552a38012Sejakowatz
10652a38012Sejakowatzint32
10752a38012SejakowatzBSoundFile::ByteOrder() const
10852a38012Sejakowatz{
1097e0c41c1Sshatty	return fByteOrder;
11052a38012Sejakowatz}
11152a38012Sejakowatz
11252a38012Sejakowatz
11352a38012Sejakowatzint32
11452a38012SejakowatzBSoundFile::SampleFormat() const
11552a38012Sejakowatz{
1167e0c41c1Sshatty	return fSampleFormat;
11752a38012Sejakowatz}
11852a38012Sejakowatz
11952a38012Sejakowatz
12052a38012Sejakowatzint32
12152a38012SejakowatzBSoundFile::FrameSize() const
12252a38012Sejakowatz{
1237e0c41c1Sshatty	return fSampleSize * fChannelCount;
12452a38012Sejakowatz}
12552a38012Sejakowatz
12652a38012Sejakowatz
12752a38012Sejakowatzoff_t
12852a38012SejakowatzBSoundFile::CountFrames() const
12952a38012Sejakowatz{
1307e0c41c1Sshatty	return fFrameCount;
13152a38012Sejakowatz}
13252a38012Sejakowatz
13352a38012Sejakowatz
13452a38012Sejakowatzbool
13552a38012SejakowatzBSoundFile::IsCompressed() const
13652a38012Sejakowatz{
1377e0c41c1Sshatty	return fIsCompressed;
13852a38012Sejakowatz}
13952a38012Sejakowatz
14052a38012Sejakowatz
14152a38012Sejakowatzint32
14252a38012SejakowatzBSoundFile::CompressionType() const
14352a38012Sejakowatz{
1447e0c41c1Sshatty	return fCompressionType;
14552a38012Sejakowatz}
14652a38012Sejakowatz
14752a38012Sejakowatz
14852a38012Sejakowatzchar *
14952a38012SejakowatzBSoundFile::CompressionName() const
15052a38012Sejakowatz{
1517e0c41c1Sshatty	return fCompressionName;
15252a38012Sejakowatz}
15352a38012Sejakowatz
15452a38012Sejakowatz
15552a38012Sejakowatz/* virtual */ int32
15652a38012SejakowatzBSoundFile::SetFileFormat(int32 format)
15752a38012Sejakowatz{
1587e0c41c1Sshatty	fFileFormat = format;
1597e0c41c1Sshatty	return fFileFormat;
16052a38012Sejakowatz}
16152a38012Sejakowatz
16252a38012Sejakowatz
16352a38012Sejakowatz/* virtual */ int32
16452a38012SejakowatzBSoundFile::SetSamplingRate(int32 fps)
16552a38012Sejakowatz{
1667e0c41c1Sshatty	fSamplingRate = fps;
1677e0c41c1Sshatty	return fSamplingRate;
16852a38012Sejakowatz}
16952a38012Sejakowatz
17052a38012Sejakowatz
17152a38012Sejakowatz/* virtual */ int32
17252a38012SejakowatzBSoundFile::SetChannelCount(int32 spf)
17352a38012Sejakowatz{
1747e0c41c1Sshatty	fChannelCount = spf;
1757e0c41c1Sshatty	return fChannelCount;
17652a38012Sejakowatz}
17752a38012Sejakowatz
17852a38012Sejakowatz
17952a38012Sejakowatz/* virtual */ int32
18052a38012SejakowatzBSoundFile::SetSampleSize(int32 bps)
18152a38012Sejakowatz{
1827e0c41c1Sshatty	fSampleSize = bps;
1837e0c41c1Sshatty	return fSampleSize;
18452a38012Sejakowatz}
18552a38012Sejakowatz
18652a38012Sejakowatz
18752a38012Sejakowatz/* virtual */ int32
18852a38012SejakowatzBSoundFile::SetByteOrder(int32 bord)
18952a38012Sejakowatz{
1907e0c41c1Sshatty	fByteOrder = bord;
1917e0c41c1Sshatty	return fByteOrder;
19252a38012Sejakowatz}
19352a38012Sejakowatz
19452a38012Sejakowatz
19552a38012Sejakowatz/* virtual */ int32
19652a38012SejakowatzBSoundFile::SetSampleFormat(int32 fmt)
19752a38012Sejakowatz{
1987e0c41c1Sshatty	fSampleFormat = fmt;
1997e0c41c1Sshatty	return fSampleFormat;
20052a38012Sejakowatz}
20152a38012Sejakowatz
20252a38012Sejakowatz
20352a38012Sejakowatz/* virtual */ int32
20452a38012SejakowatzBSoundFile::SetCompressionType(int32 type)
20552a38012Sejakowatz{
20648ff964fSbeveloper	return 0;
20752a38012Sejakowatz}
20852a38012Sejakowatz
20952a38012Sejakowatz
21052a38012Sejakowatz/* virtual */ char *
21152a38012SejakowatzBSoundFile::SetCompressionName(char *name)
21252a38012Sejakowatz{
21352a38012Sejakowatz	return NULL;
21452a38012Sejakowatz}
21552a38012Sejakowatz
21652a38012Sejakowatz
21752a38012Sejakowatz/* virtual */ bool
21852a38012SejakowatzBSoundFile::SetIsCompressed(bool tf)
21952a38012Sejakowatz{
22048ff964fSbeveloper	return false;
22152a38012Sejakowatz}
22252a38012Sejakowatz
22352a38012Sejakowatz
22452a38012Sejakowatz/* virtual */ off_t
22552a38012SejakowatzBSoundFile::SetDataLocation(off_t offset)
22652a38012Sejakowatz{
22752a38012Sejakowatz	UNIMPLEMENTED();
22852a38012Sejakowatz
22948ff964fSbeveloper	return 0;
23052a38012Sejakowatz}
23152a38012Sejakowatz
23252a38012Sejakowatz
23352a38012Sejakowatz/* virtual */ off_t
23452a38012SejakowatzBSoundFile::SetFrameCount(off_t count)
23552a38012Sejakowatz{
2367e0c41c1Sshatty	fFrameCount = count;
2377e0c41c1Sshatty	return fFrameCount;
23852a38012Sejakowatz}
23952a38012Sejakowatz
24052a38012Sejakowatz
24152a38012Sejakowatzsize_t
24252a38012SejakowatzBSoundFile::ReadFrames(char *buf,
24352a38012Sejakowatz					   size_t count)
24452a38012Sejakowatz{
245f621b750SAdrien Destugues	size_t frameRead = 0;
246f621b750SAdrien Destugues	int64 frames = count;
247f621b750SAdrien Destugues	while (count > 0) {
248f621b750SAdrien Destugues		status_t status = fMediaTrack->ReadFrames(
249f621b750SAdrien Destugues				reinterpret_cast<void *>(buf), &frames);
250f621b750SAdrien Destugues		count -= frames;
251f621b750SAdrien Destugues		frameRead += frames;
252f621b750SAdrien Destugues		buf += fSampleSize * fChannelCount * frames;
253f621b750SAdrien Destugues		if (status != B_OK) {
254f621b750SAdrien Destugues			if (frameRead > 0)
255f621b750SAdrien Destugues				break;
256f621b750SAdrien Destugues			return status;
257f621b750SAdrien Destugues		}
258f621b750SAdrien Destugues	}
259f621b750SAdrien Destugues	return frameRead;
26052a38012Sejakowatz}
26152a38012Sejakowatz
26252a38012Sejakowatz
26352a38012Sejakowatzsize_t
26452a38012SejakowatzBSoundFile::WriteFrames(char *buf,
26552a38012Sejakowatz						size_t count)
26652a38012Sejakowatz{
267f621b750SAdrien Destugues	return fMediaTrack->WriteFrames(
268f621b750SAdrien Destugues			reinterpret_cast<void *>(buf), count);
26952a38012Sejakowatz}
27052a38012Sejakowatz
27152a38012Sejakowatz
27252a38012Sejakowatz/* virtual */ off_t
27352a38012SejakowatzBSoundFile::SeekToFrame(off_t n)
27452a38012Sejakowatz{
275f621b750SAdrien Destugues	int64 frames = n;
276f621b750SAdrien Destugues	status_t status = fMediaTrack->SeekToFrame(&frames);
27752a38012Sejakowatz
278f621b750SAdrien Destugues	if (status != B_OK)
279f621b750SAdrien Destugues		return status;
280f621b750SAdrien Destugues
281f621b750SAdrien Destugues	return frames;
28252a38012Sejakowatz}
28352a38012Sejakowatz
28452a38012Sejakowatz
28552a38012Sejakowatzoff_t
28652a38012SejakowatzBSoundFile::FrameIndex() const
28752a38012Sejakowatz{
2887e0c41c1Sshatty	return fFrameIndex;
28952a38012Sejakowatz}
29052a38012Sejakowatz
29152a38012Sejakowatz
29252a38012Sejakowatzoff_t
29352a38012SejakowatzBSoundFile::FramesRemaining() const
29452a38012Sejakowatz{
2957e0c41c1Sshatty	return fFrameCount - FrameIndex();
29652a38012Sejakowatz}
29752a38012Sejakowatz
29852a38012Sejakowatz/*************************************************************
29952a38012Sejakowatz * private BSoundFile
30052a38012Sejakowatz *************************************************************/
30152a38012Sejakowatz
30252a38012Sejakowatz
30352a38012Sejakowatzvoid BSoundFile::_ReservedSoundFile1() {}
30452a38012Sejakowatzvoid BSoundFile::_ReservedSoundFile2() {}
30552a38012Sejakowatzvoid BSoundFile::_ReservedSoundFile3() {}
30652a38012Sejakowatz
30752a38012Sejakowatzvoid
30852a38012SejakowatzBSoundFile::_init_raw_stats()
30952a38012Sejakowatz{
3107e0c41c1Sshatty	fSoundFile = 0;
3117e0c41c1Sshatty	fMediaFile = 0;
3127e0c41c1Sshatty	fMediaTrack = 0;
3137e0c41c1Sshatty	fFileFormat = B_UNKNOWN_FILE;
3147e0c41c1Sshatty	fSamplingRate = 44100;
3157e0c41c1Sshatty	fChannelCount = 2;
3167e0c41c1Sshatty	fSampleSize = 2;
3177e0c41c1Sshatty	fByteOrder = B_BIG_ENDIAN;
3187e0c41c1Sshatty	fSampleFormat = B_LINEAR_SAMPLES;
3197e0c41c1Sshatty	fFrameCount = 0;
3207e0c41c1Sshatty	fFrameIndex = 0;
3217e0c41c1Sshatty	fIsCompressed = false;
3227e0c41c1Sshatty	fCompressionType = -1;
3237e0c41c1Sshatty	fCompressionName = NULL;
32452a38012Sejakowatz}
32552a38012Sejakowatz
32652a38012Sejakowatz
327f621b750SAdrien Destuguesstatic int32
328f621b750SAdrien Destugues_ParseMimeType(char *mime_type)
329f621b750SAdrien Destugues{
330f621b750SAdrien Destugues	if (strcmp(mime_type, "audio/x-aiff") == 0)
331f621b750SAdrien Destugues		return B_AIFF_FILE;
332f621b750SAdrien Destugues	if (strcmp(mime_type, "audio/x-wav") == 0)
333f621b750SAdrien Destugues		return B_WAVE_FILE;
334f621b750SAdrien Destugues	return B_UNKNOWN_FILE;
335f621b750SAdrien Destugues}
336f621b750SAdrien Destugues
337f621b750SAdrien Destugues
33852a38012Sejakowatzstatus_t
33952a38012SejakowatzBSoundFile::_ref_to_file(const entry_ref *ref)
34052a38012Sejakowatz{
3417e0c41c1Sshatty	status_t status;
3429e422461SPhilippe Saint-Pierre	BFile * file = new BFile(ref, B_READ_ONLY);
3437e0c41c1Sshatty	status = file->InitCheck();
3447e0c41c1Sshatty	if (status != B_OK) {
3457e0c41c1Sshatty		fSoundFile = file;
3467e0c41c1Sshatty		return status;
3477e0c41c1Sshatty	}
3487e0c41c1Sshatty	BMediaFile * media = new BMediaFile(file);
3497e0c41c1Sshatty	status = media->InitCheck();
3507e0c41c1Sshatty	if (status != B_OK) {
3517e0c41c1Sshatty		delete media;
3527e0c41c1Sshatty		delete file;
3537e0c41c1Sshatty		return status;
3547e0c41c1Sshatty	}
3557e0c41c1Sshatty	media_file_format mfi;
3567e0c41c1Sshatty	media->GetFileFormatInfo(&mfi);
3577e0c41c1Sshatty	switch (mfi.family) {
3589e422461SPhilippe Saint-Pierre		case B_AIFF_FORMAT_FAMILY: fFileFormat = B_AIFF_FILE; break;
3599e422461SPhilippe Saint-Pierre		case B_WAV_FORMAT_FAMILY:  fFileFormat = B_WAVE_FILE; break;
360f621b750SAdrien Destugues		default: fFileFormat = _ParseMimeType(mfi.mime_type); break;
3617e0c41c1Sshatty	}
3627e0c41c1Sshatty	int trackNum = 0;
3637e0c41c1Sshatty	BMediaTrack * track = 0;
3647e0c41c1Sshatty	media_format mf;
3657e0c41c1Sshatty	while (trackNum < media->CountTracks()) {
3667e0c41c1Sshatty		track = media->TrackAt(trackNum);
367f621b750SAdrien Destugues		status = track->DecodedFormat(&mf);
3687e0c41c1Sshatty		if (status != B_OK) {
3697e0c41c1Sshatty			media->ReleaseTrack(track);
3707e0c41c1Sshatty			delete media;
3717e0c41c1Sshatty			delete file;
3727e0c41c1Sshatty			return status;
3737e0c41c1Sshatty		}
3747e0c41c1Sshatty		if (mf.IsAudio()) {
3757e0c41c1Sshatty			break;
3767e0c41c1Sshatty		}
3777e0c41c1Sshatty		media->ReleaseTrack(track);
3787e0c41c1Sshatty		track = 0;
3797e0c41c1Sshatty	}
3807e0c41c1Sshatty	if (track == 0) {
3817e0c41c1Sshatty		delete media;
3827e0c41c1Sshatty		delete file;
3837e0c41c1Sshatty		return B_ERROR;
3847e0c41c1Sshatty	}
3859e422461SPhilippe Saint-Pierre	media_raw_audio_format * raw = 0;
3867e0c41c1Sshatty	if (mf.type == B_MEDIA_ENCODED_AUDIO) {
3877e0c41c1Sshatty		raw = &mf.u.encoded_audio.output;
3887e0c41c1Sshatty	}
3897e0c41c1Sshatty	if (mf.type == B_MEDIA_RAW_AUDIO) {
3907e0c41c1Sshatty		raw = &mf.u.raw_audio;
3917e0c41c1Sshatty	}
3929e422461SPhilippe Saint-Pierre
3932d5785baSPhilippe Saint-Pierre	if (raw == NULL) {
3942d5785baSPhilippe Saint-Pierre		delete media;
3952d5785baSPhilippe Saint-Pierre		delete file;
3969e422461SPhilippe Saint-Pierre		return B_ERROR;
3972d5785baSPhilippe Saint-Pierre	}
3989e422461SPhilippe Saint-Pierre
3997e0c41c1Sshatty	fSamplingRate = (int)raw->frame_rate;
4007e0c41c1Sshatty	fChannelCount = raw->channel_count;
4017e0c41c1Sshatty	fSampleSize = raw->format & 0xf;
4027e0c41c1Sshatty	fByteOrder = raw->byte_order;
4037e0c41c1Sshatty	switch (raw->format) {
4049e422461SPhilippe Saint-Pierre		case media_raw_audio_format::B_AUDIO_FLOAT:
4059e422461SPhilippe Saint-Pierre			fSampleFormat = B_FLOAT_SAMPLES;
4069e422461SPhilippe Saint-Pierre			break;
4079e422461SPhilippe Saint-Pierre		case media_raw_audio_format::B_AUDIO_INT:
4089e422461SPhilippe Saint-Pierre		case media_raw_audio_format::B_AUDIO_SHORT:
4099e422461SPhilippe Saint-Pierre		case media_raw_audio_format::B_AUDIO_UCHAR:
4109e422461SPhilippe Saint-Pierre		case media_raw_audio_format::B_AUDIO_CHAR:
4119e422461SPhilippe Saint-Pierre			fSampleFormat = B_LINEAR_SAMPLES;
4129e422461SPhilippe Saint-Pierre			break;
4139e422461SPhilippe Saint-Pierre		default:
4149e422461SPhilippe Saint-Pierre			fSampleFormat = B_UNDEFINED_SAMPLES;
4157e0c41c1Sshatty	}
4167e0c41c1Sshatty	fByteOffset = 0;
4177e0c41c1Sshatty	fFrameCount = track->CountFrames();
4187e0c41c1Sshatty	fFrameIndex = 0;
4197e0c41c1Sshatty	if (mf.type == B_MEDIA_ENCODED_AUDIO) {
4207e0c41c1Sshatty		fIsCompressed = true;
4217e0c41c1Sshatty		fCompressionType = mf.u.encoded_audio.encoding;
4227e0c41c1Sshatty	}
4237e0c41c1Sshatty	fMediaFile = media;
4247e0c41c1Sshatty	fMediaTrack = track;
425f621b750SAdrien Destugues	fSoundFile = file;
4267e0c41c1Sshatty	return B_OK;
42752a38012Sejakowatz}
42852a38012Sejakowatz
42952a38012Sejakowatz
430