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

Generated on Mon Feb 13 23:07:46 2006 for audiere by  doxygen 1.4.6