Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
448 lines (343 sloc) 8.84 KB
#include "device_ds_stream.h"
#include "device_ds.h"
#include "debug.h"
namespace audiere {
DSOutputStream::DSOutputStream(
DSAudioDevice* device,
IDirectSoundBuffer* buffer,
int buffer_length,
SampleSource* source)
{
ADR_GUARD("DSOutputStream::DSOutputStream");
m_device = device;
m_buffer = buffer;
m_buffer_length = buffer_length;
m_next_read = 0;
m_last_play = 0;
DWORD frequency;
m_buffer->GetFrequency(&frequency);
m_base_frequency = frequency;
m_is_playing = false;
m_source = source;
m_frame_size = GetFrameSize(m_source);
m_total_read = 0;
m_total_played = 0;
m_last_frame = new BYTE[m_frame_size];
setVolume(1);
setPan(0);
// fill the buffer with data
fillStream();
}
DSOutputStream::~DSOutputStream() {
ADR_GUARD("DSOutputStream::~DSOutputStream");
m_device->removeStream(this);
// destroy the sound buffer interface
m_buffer->Release();
delete[] m_last_frame;
}
void
DSOutputStream::play() {
ADR_GUARD("DSOutputStream::play");
m_buffer->Play(0, 0, DSBPLAY_LOOPING);
m_is_playing = true;
}
void
DSOutputStream::stop() {
ADR_GUARD("DSOutputStream::stop");
doStop(false);
}
bool
DSOutputStream::isPlaying() {
return m_is_playing;
}
void
DSOutputStream::reset() {
ADR_GUARD("DSOutputStream::reset");
SYNCHRONIZED(this);
doReset();
}
void
DSOutputStream::setRepeat(bool repeat) {
SYNCHRONIZED(this);
m_source->setRepeat(repeat);
if (!isPlaying()) {
doReset();
}
}
bool
DSOutputStream::getRepeat() {
SYNCHRONIZED(this);
return m_source->getRepeat();
}
void
DSOutputStream::setVolume(float volume) {
m_volume = volume;
m_buffer->SetVolume(DSAudioDevice::Volume_AudiereToDirectSound(volume));
}
float
DSOutputStream::getVolume() {
return m_volume;
}
void
DSOutputStream::setPan(float pan) {
m_pan = pan;
m_buffer->SetPan(DSAudioDevice::Pan_AudiereToDirectSound(pan));
}
float
DSOutputStream::getPan() {
return m_pan;
}
void
DSOutputStream::setPitchShift(float shift) {
m_buffer->SetFrequency(DWORD(m_base_frequency * shift));
}
float
DSOutputStream::getPitchShift() {
DWORD frequency;
m_buffer->GetFrequency(&frequency);
return float(frequency) / m_base_frequency;
}
bool
DSOutputStream::isSeekable() {
SYNCHRONIZED(this);
return m_source->isSeekable();
}
int
DSOutputStream::getLength() {
SYNCHRONIZED(this);
return m_source->getLength();
}
void
DSOutputStream::setPosition(int position) {
SYNCHRONIZED(this);
// figure out if we're playing or not
bool is_playing = isPlaying();
// if we're playing, stop
if (is_playing) {
doStop(true);
}
m_last_play = 0;
m_source->setPosition(position);
m_total_read = 0;
m_total_played = 0;
m_next_read = 0;
fillStream();
// if we were playing, restart
if (is_playing) {
play();
}
}
int
DSOutputStream::getPosition() {
SYNCHRONIZED(this);
int pos = m_source->getPosition() - (m_total_read - m_total_played);
while (pos < 0) {
pos += m_source->getLength();
}
return pos;
}
void
DSOutputStream::doStop(bool internal) {
m_buffer->Stop();
if (m_is_playing) {
m_is_playing = false;
if (!internal) {
m_device->fireStopEvent(this, StopEvent::STOP_CALLED);
}
} else {
m_is_playing = false;
}
}
void
DSOutputStream::doReset() {
// figure out if we're playing or not
bool is_playing = isPlaying();
// if we're playing, stop
if (is_playing) {
doStop(true);
}
m_buffer->SetCurrentPosition(0);
m_last_play = 0;
m_source->reset();
m_total_read = 0;
m_total_played = 0;
m_next_read = 0;
fillStream();
// if we were playing, restart
if (is_playing) {
play();
}
}
void
DSOutputStream::fillStream() {
ADR_GUARD("DSOutputStream::fillStream");
// we know the stream is stopped, so just lock the buffer and fill it
void* buffer = NULL;
DWORD buffer_length = 0;
// lock
HRESULT result = m_buffer->Lock(
0,
m_buffer_length * m_frame_size,
&buffer,
&buffer_length,
NULL,
NULL,
0);
if (FAILED(result) || !buffer) {
ADR_LOG("FillStream failed!");
return;
}
ADR_IF_DEBUG {
char str[80];
sprintf(str, "Buffer Length = %d", buffer_length);
ADR_LOG(str);
}
// fill
int samples_to_read = buffer_length / m_frame_size;
int samples_read = streamRead(samples_to_read, buffer);
if (samples_read != samples_to_read) {
m_next_read = samples_read;
} else {
m_next_read = 0;
}
ADR_IF_DEBUG {
char str[80];
sprintf(str, "samples_to_read = %d", samples_to_read); ADR_LOG(str);
sprintf(str, "samples_read = %d", samples_read); ADR_LOG(str);
sprintf(str, "m_next_read = %d", m_next_read); ADR_LOG(str);
}
// unlock
m_buffer->Unlock(buffer, buffer_length, NULL, 0);
m_buffer->SetCurrentPosition(0);
}
void
DSOutputStream::update() {
SYNCHRONIZED(this);
// if it's not playing, don't do anything
if (!isPlaying()) {
return;
}
ADR_GUARD("DSOutputStream::update");
/* this method reads more PCM data into the stream if it is required */
// read the stream's play and write cursors
DWORD play, write;
HRESULT result = m_buffer->GetCurrentPosition(&play, &write);
if (FAILED(result)) {
ADR_LOG("GetCurrentPosition failed");
return;
}
// deal with them in samples, not bytes
play /= m_frame_size;
write /= m_frame_size;
ADR_IF_DEBUG {
char str[160];
sprintf(str,
"play: %d write: %d nextread: %d",
play, write, m_next_read);
ADR_LOG(str);
}
// how many samples have we playen since the last update?
if (int(play) < m_last_play) {
m_total_played += play + m_buffer_length - m_last_play;
} else {
m_total_played += play - m_last_play;
}
m_last_play = play;
// read from |m_next_read| to |play|
int read_length = play - m_next_read;
if (read_length < 0) {
read_length += m_buffer_length;
}
if (read_length == 0) {
return;
}
// lock the buffer
void* buffer1;
void* buffer2;
DWORD buffer1_length;
DWORD buffer2_length;
result = m_buffer->Lock(
m_next_read * m_frame_size,
read_length * m_frame_size,
&buffer1, &buffer1_length,
&buffer2, &buffer2_length,
0);
if (FAILED(result)) {
ADR_LOG("Lock() failed!");
return;
}
ADR_IF_DEBUG {
char str[160];
sprintf(str, "buffer1: %d buffer2: %d", buffer1_length, buffer2_length);
ADR_LOG(str);
}
// now actually read samples
int length1 = buffer1_length / m_frame_size;
int length2 = buffer2_length / m_frame_size;
int read = streamRead(length1, buffer1);
if (buffer2) {
if (length1 == read) {
read += streamRead(length2, buffer2);
} else {
fillSilence(length2, buffer2);
}
}
ADR_IF_DEBUG {
char str[80];
sprintf(str, "read: %d", read);
ADR_LOG(str);
}
m_next_read = (m_next_read + read) % m_buffer_length;
// unlock
m_buffer->Unlock(buffer1, buffer1_length, buffer2, buffer2_length);
// Should we stop?
if (m_total_played > m_total_read) {
ADR_LOG("Stopping stream!");
doStop(true);
m_buffer->SetCurrentPosition(0);
m_last_play = 0;
m_source->reset();
m_total_played = 0;
m_total_read = 0;
m_next_read = 0;
fillStream();
m_device->fireStopEvent(this, StopEvent::STREAM_ENDED);
return;
}
}
// read as much as possible from the stream source, fill the rest
// with silence
int
DSOutputStream::streamRead(int sample_count, void* samples) {
ADR_GUARD("streamRead");
// try to read from the stream
int samples_read = m_source->read(sample_count, samples);
ADR_IF_DEBUG {
char str[80];
sprintf(str, "samples_read = %d\n", samples_read);
ADR_LOG(str);
}
// remember the last sample
if (samples_read > 0) {
memcpy(
m_last_frame,
(BYTE*)samples + (samples_read - 1) * m_frame_size,
m_frame_size);
}
// fill the rest with silence
BYTE* out = (BYTE*)samples + m_frame_size * samples_read;
int c = sample_count - samples_read;
fillSilence(c, out);
m_total_read += samples_read;
return samples_read;
}
void
DSOutputStream::fillSilence(int sample_count, void* samples) {
int c = sample_count;
BYTE* out = (BYTE*)samples;
while (c--) {
memcpy(out, m_last_frame, m_frame_size);
out += m_frame_size;
}
}
}
Jump to Line
Something went wrong with that request. Please try again.