xref: /haiku/src/kits/media/SoundFile.cpp (revision b84955d416f92e89c9d73999f545a2dec353d988)
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 
12*b84955d4SBarrett17 #include "MediaDebug.h"
1352a38012Sejakowatz 
1452a38012Sejakowatz /*************************************************************
1552a38012Sejakowatz  * public BSoundFile
1652a38012Sejakowatz  *************************************************************/
1752a38012Sejakowatz 
BSoundFile()1852a38012Sejakowatz BSoundFile::BSoundFile()
1952a38012Sejakowatz {
207e0c41c1Sshatty 	_init_raw_stats();
2152a38012Sejakowatz }
2252a38012Sejakowatz 
2352a38012Sejakowatz 
BSoundFile(const entry_ref * ref,uint32 open_mode)2452a38012Sejakowatz BSoundFile::BSoundFile(const entry_ref *ref,
2552a38012Sejakowatz 					   uint32 open_mode)
2652a38012Sejakowatz {
277e0c41c1Sshatty 	_init_raw_stats();
287e0c41c1Sshatty 	SetTo(ref,open_mode);
2952a38012Sejakowatz }
3052a38012Sejakowatz 
3152a38012Sejakowatz /* virtual */
~BSoundFile()3252a38012Sejakowatz BSoundFile::~BSoundFile()
3352a38012Sejakowatz {
347e0c41c1Sshatty 	delete fSoundFile;
35b0acb3feSStefano Ceccherini 	delete fMediaFile;
36b0acb3feSStefano Ceccherini 		// fMediaTrack will be deleted by the BMediaFile destructor
3752a38012Sejakowatz }
3852a38012Sejakowatz 
3952a38012Sejakowatz 
4052a38012Sejakowatz status_t
InitCheck() const4152a38012Sejakowatz BSoundFile::InitCheck() const
4252a38012Sejakowatz {
437e0c41c1Sshatty 	if (!fSoundFile) {
447e0c41c1Sshatty 		return B_NO_INIT;
457e0c41c1Sshatty 	}
467e0c41c1Sshatty 	return fSoundFile->InitCheck();
4752a38012Sejakowatz }
4852a38012Sejakowatz 
4952a38012Sejakowatz 
5052a38012Sejakowatz status_t
SetTo(const entry_ref * ref,uint32 open_mode)5152a38012Sejakowatz BSoundFile::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 {
7252a38012Sejakowatz 		UNIMPLEMENTED();
7348ff964fSbeveloper 		return B_ERROR;
7452a38012Sejakowatz 	}
757e0c41c1Sshatty }
7652a38012Sejakowatz 
7752a38012Sejakowatz 
7852a38012Sejakowatz int32
FileFormat() const7952a38012Sejakowatz BSoundFile::FileFormat() const
8052a38012Sejakowatz {
817e0c41c1Sshatty 	return fFileFormat;
8252a38012Sejakowatz }
8352a38012Sejakowatz 
8452a38012Sejakowatz 
8552a38012Sejakowatz int32
SamplingRate() const8652a38012Sejakowatz BSoundFile::SamplingRate() const
8752a38012Sejakowatz {
887e0c41c1Sshatty 	return fSamplingRate;
8952a38012Sejakowatz }
9052a38012Sejakowatz 
9152a38012Sejakowatz 
9252a38012Sejakowatz int32
CountChannels() const9352a38012Sejakowatz BSoundFile::CountChannels() const
9452a38012Sejakowatz {
957e0c41c1Sshatty 	return fChannelCount;
9652a38012Sejakowatz }
9752a38012Sejakowatz 
9852a38012Sejakowatz 
9952a38012Sejakowatz int32
SampleSize() const10052a38012Sejakowatz BSoundFile::SampleSize() const
10152a38012Sejakowatz {
1027e0c41c1Sshatty 	return fSampleSize;
10352a38012Sejakowatz }
10452a38012Sejakowatz 
10552a38012Sejakowatz 
10652a38012Sejakowatz int32
ByteOrder() const10752a38012Sejakowatz BSoundFile::ByteOrder() const
10852a38012Sejakowatz {
1097e0c41c1Sshatty 	return fByteOrder;
11052a38012Sejakowatz }
11152a38012Sejakowatz 
11252a38012Sejakowatz 
11352a38012Sejakowatz int32
SampleFormat() const11452a38012Sejakowatz BSoundFile::SampleFormat() const
11552a38012Sejakowatz {
1167e0c41c1Sshatty 	return fSampleFormat;
11752a38012Sejakowatz }
11852a38012Sejakowatz 
11952a38012Sejakowatz 
12052a38012Sejakowatz int32
FrameSize() const12152a38012Sejakowatz BSoundFile::FrameSize() const
12252a38012Sejakowatz {
1237e0c41c1Sshatty 	return fSampleSize * fChannelCount;
12452a38012Sejakowatz }
12552a38012Sejakowatz 
12652a38012Sejakowatz 
12752a38012Sejakowatz off_t
CountFrames() const12852a38012Sejakowatz BSoundFile::CountFrames() const
12952a38012Sejakowatz {
1307e0c41c1Sshatty 	return fFrameCount;
13152a38012Sejakowatz }
13252a38012Sejakowatz 
13352a38012Sejakowatz 
13452a38012Sejakowatz bool
IsCompressed() const13552a38012Sejakowatz BSoundFile::IsCompressed() const
13652a38012Sejakowatz {
1377e0c41c1Sshatty 	return fIsCompressed;
13852a38012Sejakowatz }
13952a38012Sejakowatz 
14052a38012Sejakowatz 
14152a38012Sejakowatz int32
CompressionType() const14252a38012Sejakowatz BSoundFile::CompressionType() const
14352a38012Sejakowatz {
1447e0c41c1Sshatty 	return fCompressionType;
14552a38012Sejakowatz }
14652a38012Sejakowatz 
14752a38012Sejakowatz 
14852a38012Sejakowatz char *
CompressionName() const14952a38012Sejakowatz BSoundFile::CompressionName() const
15052a38012Sejakowatz {
1517e0c41c1Sshatty 	return fCompressionName;
15252a38012Sejakowatz }
15352a38012Sejakowatz 
15452a38012Sejakowatz 
15552a38012Sejakowatz /* virtual */ int32
SetFileFormat(int32 format)15652a38012Sejakowatz BSoundFile::SetFileFormat(int32 format)
15752a38012Sejakowatz {
1587e0c41c1Sshatty 	fFileFormat = format;
1597e0c41c1Sshatty 	return fFileFormat;
16052a38012Sejakowatz }
16152a38012Sejakowatz 
16252a38012Sejakowatz 
16352a38012Sejakowatz /* virtual */ int32
SetSamplingRate(int32 fps)16452a38012Sejakowatz BSoundFile::SetSamplingRate(int32 fps)
16552a38012Sejakowatz {
1667e0c41c1Sshatty 	fSamplingRate = fps;
1677e0c41c1Sshatty 	return fSamplingRate;
16852a38012Sejakowatz }
16952a38012Sejakowatz 
17052a38012Sejakowatz 
17152a38012Sejakowatz /* virtual */ int32
SetChannelCount(int32 spf)17252a38012Sejakowatz BSoundFile::SetChannelCount(int32 spf)
17352a38012Sejakowatz {
1747e0c41c1Sshatty 	fChannelCount = spf;
1757e0c41c1Sshatty 	return fChannelCount;
17652a38012Sejakowatz }
17752a38012Sejakowatz 
17852a38012Sejakowatz 
17952a38012Sejakowatz /* virtual */ int32
SetSampleSize(int32 bps)18052a38012Sejakowatz BSoundFile::SetSampleSize(int32 bps)
18152a38012Sejakowatz {
1827e0c41c1Sshatty 	fSampleSize = bps;
1837e0c41c1Sshatty 	return fSampleSize;
18452a38012Sejakowatz }
18552a38012Sejakowatz 
18652a38012Sejakowatz 
18752a38012Sejakowatz /* virtual */ int32
SetByteOrder(int32 bord)18852a38012Sejakowatz BSoundFile::SetByteOrder(int32 bord)
18952a38012Sejakowatz {
1907e0c41c1Sshatty 	fByteOrder = bord;
1917e0c41c1Sshatty 	return fByteOrder;
19252a38012Sejakowatz }
19352a38012Sejakowatz 
19452a38012Sejakowatz 
19552a38012Sejakowatz /* virtual */ int32
SetSampleFormat(int32 fmt)19652a38012Sejakowatz BSoundFile::SetSampleFormat(int32 fmt)
19752a38012Sejakowatz {
1987e0c41c1Sshatty 	fSampleFormat = fmt;
1997e0c41c1Sshatty 	return fSampleFormat;
20052a38012Sejakowatz }
20152a38012Sejakowatz 
20252a38012Sejakowatz 
20352a38012Sejakowatz /* virtual */ int32
SetCompressionType(int32 type)20452a38012Sejakowatz BSoundFile::SetCompressionType(int32 type)
20552a38012Sejakowatz {
20648ff964fSbeveloper 	return 0;
20752a38012Sejakowatz }
20852a38012Sejakowatz 
20952a38012Sejakowatz 
21052a38012Sejakowatz /* virtual */ char *
SetCompressionName(char * name)21152a38012Sejakowatz BSoundFile::SetCompressionName(char *name)
21252a38012Sejakowatz {
21352a38012Sejakowatz 	return NULL;
21452a38012Sejakowatz }
21552a38012Sejakowatz 
21652a38012Sejakowatz 
21752a38012Sejakowatz /* virtual */ bool
SetIsCompressed(bool tf)21852a38012Sejakowatz BSoundFile::SetIsCompressed(bool tf)
21952a38012Sejakowatz {
22048ff964fSbeveloper 	return false;
22152a38012Sejakowatz }
22252a38012Sejakowatz 
22352a38012Sejakowatz 
22452a38012Sejakowatz /* virtual */ off_t
SetDataLocation(off_t offset)22552a38012Sejakowatz BSoundFile::SetDataLocation(off_t offset)
22652a38012Sejakowatz {
22752a38012Sejakowatz 	UNIMPLEMENTED();
22852a38012Sejakowatz 
22948ff964fSbeveloper 	return 0;
23052a38012Sejakowatz }
23152a38012Sejakowatz 
23252a38012Sejakowatz 
23352a38012Sejakowatz /* virtual */ off_t
SetFrameCount(off_t count)23452a38012Sejakowatz BSoundFile::SetFrameCount(off_t count)
23552a38012Sejakowatz {
2367e0c41c1Sshatty 	fFrameCount = count;
2377e0c41c1Sshatty 	return fFrameCount;
23852a38012Sejakowatz }
23952a38012Sejakowatz 
24052a38012Sejakowatz 
24152a38012Sejakowatz size_t
ReadFrames(char * buf,size_t count)24252a38012Sejakowatz BSoundFile::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 
26352a38012Sejakowatz size_t
WriteFrames(char * buf,size_t count)26452a38012Sejakowatz BSoundFile::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
SeekToFrame(off_t n)27352a38012Sejakowatz BSoundFile::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 
28552a38012Sejakowatz off_t
FrameIndex() const28652a38012Sejakowatz BSoundFile::FrameIndex() const
28752a38012Sejakowatz {
2887e0c41c1Sshatty 	return fFrameIndex;
28952a38012Sejakowatz }
29052a38012Sejakowatz 
29152a38012Sejakowatz 
29252a38012Sejakowatz off_t
FramesRemaining() const29352a38012Sejakowatz BSoundFile::FramesRemaining() const
29452a38012Sejakowatz {
2957e0c41c1Sshatty 	return fFrameCount - FrameIndex();
29652a38012Sejakowatz }
29752a38012Sejakowatz 
29852a38012Sejakowatz /*************************************************************
29952a38012Sejakowatz  * private BSoundFile
30052a38012Sejakowatz  *************************************************************/
30152a38012Sejakowatz 
30252a38012Sejakowatz 
_ReservedSoundFile1()30352a38012Sejakowatz void BSoundFile::_ReservedSoundFile1() {}
_ReservedSoundFile2()30452a38012Sejakowatz void BSoundFile::_ReservedSoundFile2() {}
_ReservedSoundFile3()30552a38012Sejakowatz void BSoundFile::_ReservedSoundFile3() {}
30652a38012Sejakowatz 
30752a38012Sejakowatz void
_init_raw_stats()30852a38012Sejakowatz BSoundFile::_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 Destugues static int32
_ParseMimeType(char * mime_type)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 
33852a38012Sejakowatz status_t
_ref_to_file(const entry_ref * ref)33952a38012Sejakowatz BSoundFile::_ref_to_file(const entry_ref *ref)
34052a38012Sejakowatz {
3417e0c41c1Sshatty 	status_t status;
3427e0c41c1Sshatty 	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) {
3587e0c41c1Sshatty 		case B_AIFF_FORMAT_FAMILY: fFileFormat = B_AIFF_FILE; break;
3597e0c41c1Sshatty 		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;
38348ff964fSbeveloper 		return B_ERROR;
38452a38012Sejakowatz 	}
3857e0c41c1Sshatty 	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) {
4047e0c41c1Sshatty 		case media_raw_audio_format::B_AUDIO_FLOAT:
4057e0c41c1Sshatty 			fSampleFormat = B_FLOAT_SAMPLES;
4067e0c41c1Sshatty 			break;
4077e0c41c1Sshatty 		case media_raw_audio_format::B_AUDIO_INT:
4087e0c41c1Sshatty 		case media_raw_audio_format::B_AUDIO_SHORT:
4097e0c41c1Sshatty 		case media_raw_audio_format::B_AUDIO_UCHAR:
4107e0c41c1Sshatty 		case media_raw_audio_format::B_AUDIO_CHAR:
4117e0c41c1Sshatty 			fSampleFormat = B_LINEAR_SAMPLES;
4127e0c41c1Sshatty 			break;
4137e0c41c1Sshatty 		default:
4147e0c41c1Sshatty 			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;
4277e0c41c1Sshatty }
42852a38012Sejakowatz 
42952a38012Sejakowatz 
430