1 /*
2  * Copyright (c) 2012, The MilkyTracker Team.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  *   this list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * - Neither the name of the <ORGANIZATION> nor the names of its contributors
14  *   may be used to endorse or promote products derived from this software
15  *   without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "AudioDriver_Haiku.h"
31 #include "MasterMixer.h"
32 
33 #include <MediaDefs.h>
34 #include <MediaRoster.h>
35 #include <OS.h>
36 #include <SoundPlayer.h>
37 
38 #include <stdio.h>
39 #include <string.h>
40 
41 
AudioDriver_Haiku()42 AudioDriver_Haiku::AudioDriver_Haiku()
43 	:
44 	AudioDriverBase(),
45 	fSoundPlayer(NULL)
46 {
47 }
48 
49 
~AudioDriver_Haiku()50 AudioDriver_Haiku::~AudioDriver_Haiku()
51 {
52 	delete fSoundPlayer;
53 }
54 
55 
56 // #pragma mark - AudioDriverBase API
57 
58 
59 mp_sint32
initDevice(mp_sint32 bufferSizeInWords,mp_uint32 mixFrequency,MasterMixer * mixer)60 AudioDriver_Haiku::initDevice(mp_sint32 bufferSizeInWords,
61 	mp_uint32 mixFrequency, MasterMixer* mixer)
62 {
63 	mp_sint32 result = AudioDriverBase::initDevice(bufferSizeInWords,
64 		mixFrequency, mixer);
65 	if (result < 0)
66 		return result;
67 
68 	media_raw_audio_format format;
69 	format.frame_rate    = mixFrequency;
70 	format.channel_count = kChannelCount;
71 	format.format        = media_raw_audio_format::B_AUDIO_SHORT;
72 	format.byte_order    = B_MEDIA_LITTLE_ENDIAN;
73 	format.buffer_size   = bufferSizeInWords * sizeof(mp_sword);
74 
75 	fSoundPlayer = new BSoundPlayer(&format, "Milky sound", _FillBuffer, NULL,
76 		this);
77 
78 	status_t status = fSoundPlayer->InitCheck();
79 	if (status != B_OK) {
80 		fprintf(stderr, "AudioDriver_Haiku: failed to initialize "
81 			 "BSoundPlayer\n");
82 		return MP_DEVICE_ERROR;
83 	}
84 
85 	return MP_OK;
86 }
87 
88 
89 mp_sint32
closeDevice()90 AudioDriver_Haiku::closeDevice()
91 {
92 	fSoundPlayer->SetHasData(false);
93 	fSoundPlayer->Stop(true);
94 	delete fSoundPlayer;
95 	fSoundPlayer = NULL;
96 	return MP_OK;
97 }
98 
99 
100 mp_sint32
start()101 AudioDriver_Haiku::start()
102 {
103 	status_t status =  fSoundPlayer->Start();
104 	if (status != B_OK) {
105 		fprintf(stderr, "AudioDriver_Haiku: failed to start BSoundPlayer\n");
106 		return MP_DEVICE_ERROR;
107 	}
108 	fSoundPlayer->SetHasData(true);
109 	return MP_OK;
110 }
111 
112 
113 mp_sint32
stop()114 AudioDriver_Haiku::stop()
115 {
116 	fSoundPlayer->SetHasData(false);
117 	fSoundPlayer->Stop(true);
118 	return MP_OK;
119 }
120 
121 
122 mp_sint32
pause()123 AudioDriver_Haiku::pause()
124 {
125 	fSoundPlayer->SetHasData(false);
126 }
127 
128 
129 mp_sint32
resume()130 AudioDriver_Haiku::resume()
131 {
132 	fSoundPlayer->SetHasData(true);
133 }
134 
135 
136 mp_uint32
getNumPlayedSamples() const137 AudioDriver_Haiku::getNumPlayedSamples() const
138 {
139 	bigtime_t time = fSoundPlayer->CurrentTime();
140 	float samples = ((float)time / 1000000.0f) * mixFrequency;
141 	return (mp_uint32)samples;
142 }
143 
144 
145 mp_sint32
getPreferredBufferSize() const146 AudioDriver_Haiku::getPreferredBufferSize() const
147 {
148 	float frameRate = getPreferredSampleRate();
149 	return BMediaRoster::Roster()->AudioBufferSizeFor(kChannelCount,
150 		media_raw_audio_format::B_AUDIO_SHORT, frameRate, B_UNKNOWN_BUS);
151 }
152 
153 
154 // #pragma mark - MediaKit playback
155 
156 
157 void
_FillBuffer(void * theCookie,void * buffer,size_t size,const media_raw_audio_format & format)158 AudioDriver_Haiku::_FillBuffer(void* theCookie, void* buffer, size_t size,
159 	const media_raw_audio_format& format)
160 {
161 	AudioDriver_Haiku* audioDriver = (AudioDriver_Haiku*)theCookie;
162 
163 	MasterMixer* mixer = audioDriver->mixer;
164 
165 	if (audioDriver->isMixerActive())
166 		mixer->mixerHandler((mp_sword*)buffer);
167 	else
168 		memset(buffer, 0, size);
169 }
170