Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

device_ds_stream.cpp

Go to the documentation of this file.
00001 #include "device_ds_stream.h"
00002 #include "device_ds.h"
00003 #include "debug.h"
00004 
00005 
00006 namespace audiere {
00007 
00008   DSOutputStream::DSOutputStream(
00009     DSAudioDevice* device,
00010     IDirectSoundBuffer* buffer,
00011     int buffer_length,
00012     SampleSource* source)
00013   {
00014     ADR_GUARD("DSOutputStream::DSOutputStream");
00015 
00016     m_device = device;
00017 
00018     m_buffer        = buffer;
00019     m_buffer_length = buffer_length;
00020     m_next_read     = 0;
00021     m_last_play     = 0;
00022 
00023     DWORD frequency;
00024     m_buffer->GetFrequency(&frequency);
00025     m_base_frequency = frequency;
00026 
00027     m_is_playing = false;
00028 
00029     m_source = new RepeatableStream(source);
00030 
00031     int channel_count, sample_rate;
00032     SampleFormat sample_format;
00033     source->getFormat(channel_count, sample_rate, sample_format);
00034     m_sample_size = GetSampleSize(sample_format) * channel_count;
00035 
00036     m_total_read    = 0;
00037     m_total_written = 0;
00038 
00039     m_last_sample = new BYTE[m_sample_size];
00040 
00041     setVolume(1);
00042     setPan(0);
00043 
00044     // fill the buffer with data
00045     fillStream();
00046   }
00047 
00048 
00049   DSOutputStream::~DSOutputStream() {
00050     ADR_GUARD("DSOutputStream::~DSOutputStream");
00051 
00052     m_device->removeStream(this);
00053 
00054     // destroy the sound buffer interface
00055     m_buffer->Release();
00056     delete[] m_last_sample;
00057   }
00058 
00059   
00060   void
00061   DSOutputStream::play() {
00062     ADR_GUARD("DSOutputStream::play");
00063     m_buffer->Play(0, 0, DSBPLAY_LOOPING);
00064     m_is_playing = true;
00065   }
00066 
00067 
00068   void
00069   DSOutputStream::stop() {
00070     ADR_GUARD("DSOutputStream::stop");
00071     m_buffer->Stop();
00072     m_is_playing = false;
00073   }
00074 
00075 
00076   bool
00077   DSOutputStream::isPlaying() {
00078     return m_is_playing;
00079   }
00080 
00081 
00082   void
00083   DSOutputStream::reset() {
00084     ADR_GUARD("DSOutputStream::reset");
00085     SYNCHRONIZED(this);
00086 
00087     // figure out if we're playing or not
00088     bool is_playing = isPlaying();
00089 
00090     // if we're playing, stop
00091     if (is_playing) {
00092       stop();
00093     }
00094 
00095     m_buffer->SetCurrentPosition(0);
00096     m_last_play = 0;
00097 
00098     m_source->reset();
00099     m_total_read = 0;
00100     m_total_written = 0;
00101     m_next_read = 0;
00102     fillStream();
00103 
00104     // if we were playing, restart
00105     if (is_playing) {
00106       play();
00107     }
00108   }
00109 
00110 
00111   void
00112   DSOutputStream::setRepeat(bool repeat) {
00113     SYNCHRONIZED(this);
00114     m_source->setRepeat(repeat);
00115   }
00116 
00117 
00118   bool
00119   DSOutputStream::getRepeat() {
00120     SYNCHRONIZED(this);
00121     return m_source->getRepeat();
00122   }
00123 
00124 
00125   void
00126   DSOutputStream::setVolume(float volume) {
00127     m_volume = volume;
00128     m_buffer->SetVolume(DSAudioDevice::Volume_AudiereToDirectSound(volume));
00129   }
00130 
00131 
00132   float
00133   DSOutputStream::getVolume() {
00134     return m_volume;
00135   }
00136 
00137 
00138   void
00139   DSOutputStream::setPan(float pan) {
00140     m_pan = pan;
00141     m_buffer->SetPan(DSAudioDevice::Pan_AudiereToDirectSound(pan));
00142   }
00143 
00144 
00145   float
00146   DSOutputStream::getPan() {
00147     return m_pan;
00148   }
00149 
00150 
00151   void
00152   DSOutputStream::setPitchShift(float shift) {
00153     m_buffer->SetFrequency(DWORD(m_base_frequency * shift));
00154   }
00155 
00156 
00157   float
00158   DSOutputStream::getPitchShift() {
00159     DWORD frequency;
00160     m_buffer->GetFrequency(&frequency);
00161     return float(frequency) / m_base_frequency;
00162   }
00163   
00164 
00165   bool
00166   DSOutputStream::isSeekable() {
00167     SYNCHRONIZED(this);
00168     return m_source->isSeekable();
00169   }
00170 
00171 
00172   int
00173   DSOutputStream::getLength() {
00174     SYNCHRONIZED(this);
00175     return m_source->getLength();
00176   }
00177 
00178 
00179   void
00180   DSOutputStream::setPosition(int position) {
00181     SYNCHRONIZED(this);
00182 
00183     // figure out if we're playing or not
00184     bool is_playing = isPlaying();
00185 
00186     // if we're playing, stop
00187     if (is_playing) {
00188       stop();
00189     }
00190 
00191     m_source->setPosition(position);
00192     m_last_play = 0;
00193 
00194     m_source->setPosition(position);
00195     m_total_read = 0;
00196     m_total_written = 0;
00197     m_next_read = 0;
00198     fillStream();
00199 
00200     // if we were playing, restart
00201     if (is_playing) {
00202       play();
00203     }
00204   }
00205 
00206 
00207   int
00208   DSOutputStream::getPosition() {
00209     SYNCHRONIZED(this);
00210     int pos = m_source->getPosition() - (m_total_read - m_total_written);
00211     if (pos < 0) {
00212       pos += m_source->getLength();
00213     }
00214     return pos;
00215   }
00216 
00217 
00218   void
00219   DSOutputStream::fillStream() {
00220     ADR_GUARD("DSOutputStream::fillStream");
00221 
00222     // we know the stream is stopped, so just lock the buffer and fill it
00223 
00224     void* buffer = NULL;
00225     DWORD buffer_length = 0;
00226 
00227     // lock
00228     HRESULT result = m_buffer->Lock(
00229       0,
00230       m_buffer_length * m_sample_size,
00231       &buffer,
00232       &buffer_length,
00233       NULL,
00234       NULL,
00235       0);
00236     if (FAILED(result) || !buffer) {
00237       ADR_LOG("FillStream failed!");
00238       return;
00239     }
00240 
00241     ADR_IF_DEBUG {
00242       char str[80];
00243       sprintf(str, "Buffer Length = %d", buffer_length);
00244       ADR_LOG(str);
00245     }
00246 
00247     // fill
00248     int samples_to_read = buffer_length / m_sample_size;
00249     int samples_read = streamRead(samples_to_read, buffer);
00250     if (samples_read != samples_to_read) {
00251       m_next_read = samples_read;
00252     } else {
00253       m_next_read = 0;
00254     }
00255 
00256     // unlock
00257     m_buffer->Unlock(buffer, buffer_length, NULL, 0);
00258   }
00259 
00260 
00261   void
00262   DSOutputStream::update() {
00263     SYNCHRONIZED(this);
00264 
00265     // if it's not playing, don't do anything
00266     if (!isPlaying()) {
00267       return;
00268     }
00269 
00270     ADR_GUARD("DSOutputStream::update");
00271 
00272     /* this method reads more PCM data into the stream if it is required */
00273 
00274     // read the stream's play and write cursors
00275     DWORD play, write;
00276     HRESULT result = m_buffer->GetCurrentPosition(&play, &write);
00277     if (FAILED(result)) {
00278       ADR_LOG("GetCurrentPosition failed");
00279       return;
00280     }
00281 
00282     ADR_IF_DEBUG {
00283       char str[160];
00284       sprintf(str,
00285         "play: %d  write: %d  nextread: %d",
00286         play, write, m_next_read);
00287       ADR_LOG(str);
00288     }
00289 
00290     // deal with them in samples, not bytes
00291     play  /= m_sample_size;
00292     write /= m_sample_size;
00293 
00294     // how many samples have we written since the last update?
00295     if (play < m_last_play) {
00296       m_total_written += play + m_buffer_length - m_last_play;
00297     } else {
00298       m_total_written += play - m_last_play;
00299     }
00300     m_last_play = play;
00301 
00302     // read from |m_next_read| to |play|
00303     int read_length = play - m_next_read;
00304     if (read_length < 0) {
00305       read_length += m_buffer_length;
00306     }
00307 
00308     if (read_length == 0) {
00309       return;
00310     }
00311 
00312     // lock the buffer
00313     void* buffer1;
00314     void* buffer2;
00315     DWORD buffer1_length;
00316     DWORD buffer2_length;
00317     result = m_buffer->Lock(
00318       m_next_read * m_sample_size,
00319       read_length * m_sample_size,
00320       &buffer1, &buffer1_length,
00321       &buffer2, &buffer2_length,
00322       0);
00323     if (FAILED(result)) {
00324       ADR_LOG("Lock() failed!");
00325       return;
00326     }
00327 
00328     ADR_IF_DEBUG {
00329       char str[160];
00330       sprintf(str, "buffer1: %d  buffer2: %d", buffer1_length, buffer2_length);
00331       ADR_LOG(str);
00332     }
00333 
00334     // now actually read samples
00335     int length1 = buffer1_length / m_sample_size;
00336     int length2 = buffer2_length / m_sample_size;
00337     int read = streamRead(length1, buffer1);
00338     if (length1 == read) {
00339       read += streamRead(length2, buffer2);
00340     }
00341 
00342     ADR_IF_DEBUG {
00343       char str[80];
00344       sprintf(str, "read: %d", read);
00345       ADR_LOG(str);
00346     }
00347 
00348     m_next_read = (m_next_read + read) % m_buffer_length;
00349 
00350     // unlock
00351     m_buffer->Unlock(buffer1, buffer1_length, buffer2, buffer2_length);
00352 
00353   
00354     // Should we stop?
00355     if (m_total_written > m_total_read) {
00356       ADR_LOG("Stopping stream!");
00357 
00358       stop();
00359       m_buffer->SetCurrentPosition(0);
00360       m_last_play = 0;
00361 
00362       m_source->reset();
00363 
00364       m_total_written = 0;
00365       m_total_read = 0;
00366       m_next_read = 0;
00367       fillStream();
00368 
00369       return;
00370     }
00371   }
00372 
00373 
00374   // read as much as possible from the stream source, fill the rest with 0
00375   int
00376   DSOutputStream::streamRead(int sample_count, void* samples) {
00377     ADR_GUARD("streamRead");
00378 
00379     // try to read from the stream
00380     int samples_read = m_source->read(sample_count, samples);
00381 
00382     // read the last sample
00383     if (samples_read > 0) {
00384       memcpy(
00385         m_last_sample,
00386         (BYTE*)samples + (samples_read - 1) * m_sample_size,
00387         m_sample_size);
00388     }
00389 
00390     // fill the rest with silence
00391     BYTE* out = (BYTE*)samples + m_sample_size * samples_read;
00392     int c = sample_count - samples_read;
00393     while (c--) {
00394       memcpy(out, m_last_sample, m_sample_size);
00395       out += m_sample_size;
00396     }
00397 
00398     m_total_read += samples_read;
00399     return samples_read;
00400   }
00401 
00402 }

Generated on Sat Oct 12 01:43:02 2002 for audiere by doxygen1.2.17