From: <pst...@us...> - 2008-04-05 23:43:44
|
Revision: 399 http://jazzplusplus.svn.sourceforge.net/jazzplusplus/?rev=399&view=rev Author: pstieber Date: 2008-04-05 16:43:43 -0700 (Sat, 05 Apr 2008) Log Message: ----------- 1. Changes JZPlayer::samples to mSamples. 2. Made several stylistic changes in the Windows audio interface code. 3. Started making similar changes to the Linux version. 4. Made cosmetic changes. Modified Paths: -------------- trunk/jazz/src/AlsaDriver.cpp trunk/jazz/src/AlsaDriver.h trunk/jazz/src/AudioDriver.cpp trunk/jazz/src/AudioDriver.h trunk/jazz/src/Player.cpp trunk/jazz/src/Player.h trunk/jazz/src/mswin/WindowsAudioInterface.cpp trunk/jazz/src/mswin/WindowsAudioInterface.h Modified: trunk/jazz/src/AlsaDriver.cpp =================================================================== --- trunk/jazz/src/AlsaDriver.cpp 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/AlsaDriver.cpp 2008-04-05 23:43:43 UTC (rev 399) @@ -45,89 +45,100 @@ using namespace std; -#define snd_pcm_write(pcm,data,size) snd_pcm_writei(pcm,data,size) -#define snd_pcm_read(pcm,data,size) snd_pcm_readi(pcm,data,size) - #define MAX_FRAGS 16 // enough large? - - class tAlsaAudioListener : public wxTimer { public: - tAlsaAudioListener(tAlsaAudioPlayer *p, int key) + + tAlsaAudioListener(tAlsaAudioPlayer* pPlayer, int key) + : wxTimer(), + mpPlayer(pPlayer), { - hard_exit = TRUE; - player = p; - player->listener = this; - player->rec_info = 0; // not recording! - player->running_mode = 0; - + mHardExit = TRUE; + mpPlayer->mpListener = this; + mpPlayer->rec_info = 0; // not recording! + mpPlayer->running_mode = 0; + // SYNC seems not to work?? so add 8 more silent buffers // to hear the end of the sample too. - player->OpenDsp(tAlsaAudioPlayer::PLAYBACK, 0); - count = 8 + player->samples.PrepareListen(key); + mpPlayer->OpenDsp(tAlsaAudioPlayer::PLAYBACK, 0); + mCount = 8 + mpPlayer->mSamples.PrepareListen(key); Start(20); } - tAlsaAudioListener(tAlsaAudioPlayer *p, tSample &spl, long fr_smpl, long to_smpl) + tAlsaAudioListener( + tAlsaAudioPlayer* pPlayer, + tSample& spl, + long fr_smpl, + long to_smpl) + : wxTimer(), + mpPlayer(pPlayer), { - hard_exit = TRUE; - player = p; - player->listener = this; - player->rec_info = 0; // not recording! - player->running_mode = 0; + mHardExit = TRUE; + mpPlayer->mpListener = this; + mpPlayer->rec_info = 0; // not recording! + mpPlayer->running_mode = 0; - player->OpenDsp(tAlsaAudioPlayer::PLAYBACK, 0); - player->samples.ResetBufferSize(player->frag_byte_size[tAlsaAudioPlayer::PLAYBACK]); - count = 8 + player->samples.PrepareListen(&spl, fr_smpl, to_smpl); + mpPlayer->OpenDsp(tAlsaAudioPlayer::PLAYBACK, 0); + + mpPlayer->mSamples.ResetBufferSize( + mpPlayer->frag_byte_size[tAlsaAudioPlayer::PLAYBACK]); + + mCount = 8 + mpPlayer->mSamples.PrepareListen(&spl, fr_smpl, to_smpl); + Start(20); } ~tAlsaAudioListener() { Stop(); - player->CloseDsp(hard_exit); - player->listener = 0; + mpPlayer->CloseDsp(mHardExit); + mpPlayer->mpListener = 0; } virtual void Notify() { - count -= player->WriteSamples(); - count += player->samples.ContinueListen(); - if (count <= 0) + mCount -= mpPlayer->WriteSamples(); + mCount += mpPlayer->mSamples.ContinueListen(); + if (mCount <= 0) { - hard_exit = FALSE; + mHardExit = FALSE; delete this; } } long GetPlayPosition() { - return player->GetCurrentPosition(tAlsaAudioPlayer::PLAYBACK); + return mpPlayer->GetCurrentPosition(tAlsaAudioPlayer::PLAYBACK); } private: - tAlsaAudioPlayer *player; - int count; - int hard_exit; + + tAlsaAudioPlayer* mpPlayer; + + int mCount; + + int mHardExit; }; -tAlsaAudioPlayer::tAlsaAudioPlayer(JZSong *song) - : tAlsaPlayer(song) +tAlsaAudioPlayer::tAlsaAudioPlayer(JZSong* pSong) + : tAlsaPlayer(pSong) { AudioBuffer = new tEventArray(); installed = 0; audio_enabled = 0; - listener = 0; - can_duplex = 0; // no duplex yet. + mpListener = 0; + mCanDuplex = 0; // no duplex yet. pcm[PLAYBACK] = NULL; pcm[CAPTURE] = NULL; dev[PLAYBACK] = gpConfig->StrValue(C_AlsaAudioOutputDevice); dev[CAPTURE] = gpConfig->StrValue(C_AlsaAudioInputDevice); - can_duplex = 1; /* FIXME */ + + // FIXME + mCanDuplex = 1; installed = 1; audio_enabled = 1; } @@ -135,7 +146,7 @@ tAlsaAudioPlayer::~tAlsaAudioPlayer() { - delete listener; + delete mpListener; delete AudioBuffer; if (pcm[PLAYBACK]) { @@ -152,7 +163,7 @@ int tAlsaAudioPlayer::LoadSamples(const char *filename) { - return samples.Load(filename); + return mSamples.Load(filename); } int tAlsaAudioPlayer::RecordMode() const @@ -167,8 +178,8 @@ void tAlsaAudioPlayer::StartPlay(long clock, long loopClock, int cont) { - delete listener; - samples.StartPlay(clock); + delete mpListener; + mSamples.StartPlay(clock); tAlsaPlayer::StartPlay(clock, loopClock, cont); if (!audio_enabled) @@ -177,7 +188,7 @@ } long ticks_per_minute = Song->TicksPerQuarter * Song->Speed(); - samples.ResetBuffers(AudioBuffer, clock, ticks_per_minute); + mSamples.ResetBuffers(AudioBuffer, clock, ticks_per_minute); last_scount = 0; cur_pos = 0; audio_clock_offset = clock; @@ -191,11 +202,11 @@ recbuffers.ResetBufferSize(frag_byte_size[CAPTURE]); } - if (dev[CAPTURE] != dev[PLAYBACK] || can_duplex || running_mode == 0) + if (dev[CAPTURE] != dev[PLAYBACK] || mCanDuplex || running_mode == 0) { OpenDsp(PLAYBACK, 1); - samples.ResetBufferSize(frag_byte_size[PLAYBACK]); - samples.FillBuffers(OutClock); + mSamples.ResetBufferSize(frag_byte_size[PLAYBACK]); + mSamples.FillBuffers(OutClock); } if (running_mode == 0) @@ -216,31 +227,42 @@ void tAlsaAudioPlayer::StartAudio() { if (pcm[PLAYBACK]) + { snd_pcm_start(pcm[PLAYBACK]); + } if (pcm[CAPTURE]) + { snd_pcm_start(pcm[CAPTURE]); + } } void tAlsaAudioPlayer::OpenDsp(int mode, int sync_mode) { if (!audio_enabled) + { return; + } unsigned int channels; snd_pcm_format_t format; snd_pcm_uframes_t buffer_size, period_size; frame_shift[mode] = 0; - if (samples.BitsPerSample() == 8) + if (mSamples.BitsPerSample() == 8) + { format = SND_PCM_FORMAT_U8; - else { + } + else + { format = SND_PCM_FORMAT_S16_LE; frame_shift[mode]++; } - channels = samples.GetChannels(); + channels = mSamples.GetChannels(); if (channels > 1) + { frame_shift[mode]++; + } snd_pcm_stream_t stream = (mode == PLAYBACK) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE; @@ -269,20 +291,22 @@ perror("cannot set audio channels"); goto __error; } - if (snd_pcm_hw_params_set_rate(pcm[mode], hw, samples.GetSpeed(), 0) < 0) + if (snd_pcm_hw_params_set_rate(pcm[mode], hw, mSamples.GetSpeed(), 0) < 0) { - cerr << "cannot set audio rate: " << samples.GetSpeed() << endl; + cerr << "cannot set audio rate: " << mSamples.GetSpeed() << endl; goto __error; } period_size = FRAGBYTES >> frame_shift[mode]; - if ((period_size = snd_pcm_hw_params_set_period_size_near(pcm[mode], hw, &period_size, 0)) < 0) + if ( + (period_size = snd_pcm_hw_params_set_period_size_near(pcm[mode], hw, &period_size, 0)) < 0) { perror("cannot set audio period"); goto __error; } buffer_size = period_size * MAX_FRAGS; - if ((buffer_size = snd_pcm_hw_params_set_buffer_size_near(pcm[mode], hw, &buffer_size)) < 0) + if ( + (buffer_size = snd_pcm_hw_params_set_buffer_size_near(pcm[mode], hw, &buffer_size)) < 0) { perror("cannot set audio buffer"); goto __error; @@ -302,9 +326,14 @@ snd_pcm_sw_params_alloca(&sw); snd_pcm_sw_params_current(pcm[mode], sw); if (sync_mode) - snd_pcm_sw_params_set_start_threshold(pcm[mode], sw, 0x7fffffff); /* FIXME */ + { + // FIXME + snd_pcm_sw_params_set_start_threshold(pcm[mode], sw, 0x7fffffff); + } else + { snd_pcm_sw_params_set_start_threshold(pcm[mode], sw, 1); + } if (snd_pcm_sw_params(pcm[mode], sw) < 0) { perror("snd_pcm_sw_params"); @@ -323,41 +352,47 @@ } -void tAlsaAudioPlayer::CloseDsp(int reset) +void tAlsaAudioPlayer::CloseDsp(bool Reset) { if (pcm) { - if (reset) + if (Reset) { if (pcm[PLAYBACK]) { if (snd_pcm_drop(pcm[PLAYBACK]) < 0) + { perror("playback drop"); + } } } else { if (pcm[PLAYBACK]) { - if (snd_pcm_drain(pcm[PLAYBACK]) < 0 ) + if (snd_pcm_drain(pcm[PLAYBACK]) < 0) + { perror("playback drain"); + } } if (pcm[CAPTURE]) { - if (snd_pcm_drain(pcm[CAPTURE]) < 0 ) + if (snd_pcm_drain(pcm[CAPTURE]) < 0) + { perror("capture drain"); + } } } if (pcm[PLAYBACK]) { snd_pcm_close(pcm[PLAYBACK]); pcm[PLAYBACK] = NULL; - } + } if (pcm[CAPTURE]) { snd_pcm_close(pcm[CAPTURE]); pcm[CAPTURE] = NULL; - } + } } } @@ -368,15 +403,22 @@ if (pcm[PLAYBACK]) { WriteSamples(); - // here it may hang when swapping in pages - samples.FillBuffers(OutClock); + + // The code may hang here when swapping in pages. + mSamples.FillBuffers(OutClock); + WriteSamples(); } + if (pcm[CAPTURE]) + { ReadSamples(); + } - if (pcm[PLAYBACK] && samples.softsync) + if (pcm[PLAYBACK] && mSamples.softsync) + { MidiSync(); + } } tAlsaPlayer::Notify(); } @@ -398,7 +440,9 @@ int tAlsaAudioPlayer::WriteSamples() { if (!audio_enabled || pcm[PLAYBACK] == NULL) + { return 0; + } int blocks_written = 0; int room; @@ -407,11 +451,19 @@ for (; room > frag_size[PLAYBACK]; room -= frag_size[PLAYBACK]) { - tAudioBuffer *buf = samples.full_buffers.Get(); + tAudioBuffer *buf = mSamples.full_buffers.Get(); if (buf == 0) + { break; - ssize_t written = snd_pcm_writei(pcm[PLAYBACK], buf->Data(), frag_size[PLAYBACK]); - if (written < 0) { + } + + ssize_t written = snd_pcm_writei( + pcm[PLAYBACK], + buf->Data(), + frag_size[PLAYBACK]); + + if (written < 0) + { if (written == -EPIPE) { cerr << "xrun!!" << endl; @@ -423,9 +475,11 @@ } } if (written > 0) + { cur_scount += written; + } blocks_written++; - samples.free_buffers.Put(buf); + mSamples.free_buffers.Put(buf); } return blocks_written; @@ -435,14 +489,16 @@ void tAlsaAudioPlayer::ReadSamples() { if (!audio_enabled || pcm[CAPTURE] == NULL) + { return; + } int room = GetFreeSpace(CAPTURE); for (; room > frag_size[CAPTURE]; room -= frag_size[CAPTURE]) { short *b = recbuffers.RequestBuffer()->data; - if (snd_pcm_read(pcm[CAPTURE], b, frag_size[CAPTURE]) != + if (snd_pcm_readi(pcm[CAPTURE], b, frag_size[CAPTURE]) != frag_size[CAPTURE]) { recbuffers.UndoRequest(); @@ -459,7 +515,7 @@ { snd_pcm_drop(pcm[PLAYBACK]); //long ticks_per_minute = Song->TicksPerQuarter * Song->Speed(); - //samples.ResetBuffers(AudioBuffer, clock, ticks_per_minute); + //mSamples.ResetBuffers(AudioBuffer, clock, ticks_per_minute); } audio_clock_offset = clock; cur_pos = 0; @@ -473,15 +529,23 @@ void tAlsaAudioPlayer::MidiSync() { if (!audio_enabled) + { return; + } int mode; if (pcm[PLAYBACK]) + { mode = PLAYBACK; + } else if (pcm[CAPTURE]) + { mode = CAPTURE; + } else + { return; // disabled + } long scount = GetCurrentPosition(mode); @@ -499,12 +563,17 @@ qtick = snd_seq_queue_status_get_tick_time(status); int samplediff; if (scount < last_scount) + { samplediff = frame_boundary[mode] - (last_scount - scount); + } else + { samplediff = scount - last_scount; + } last_scount = scount; cur_pos += samplediff; - long audio_clock = (long)samples.Samples2Ticks(cur_pos) + audio_clock_offset; + long audio_clock = + (long)mSamples.Samples2Ticks(cur_pos) + audio_clock_offset; int delta_clock = audio_clock - qtick; int new_speed = midi_speed + delta_clock; @@ -527,26 +596,24 @@ snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); snd_seq_ev_set_fixed(&ev); - int us = (int)( 60.0E6 / (double)new_speed ); + int us = (int)(60.0E6 / new_speed); snd_seq_ev_set_queue_tempo(&ev, queue, us); write(&ev, 1); curr_speed = new_speed; - // xview has reentrancy problems!! - // gpTrackWindow->DrawSpeed(curr_speed); } } } void tAlsaAudioPlayer::StopPlay() { - samples.StopPlay(); + mSamples.StopPlay(); tAlsaPlayer::StopPlay(); if (!audio_enabled) { return; } - CloseDsp(TRUE); + CloseDsp(true); if (RecordMode()) { long frc = rec_info->mFromClock; @@ -559,53 +626,67 @@ { toc = recd_clock; } - samples.SaveRecordingDlg(frc, toc, recbuffers); + mSamples.SaveRecordingDlg(frc, toc, recbuffers); } recbuffers.Clear(); - // xview has reentrancy problems!! - // gpTrackWindow->DrawSpeed(midi_speed); } void tAlsaAudioPlayer::ListenAudio(int key, int start_stop_mode) { if (!audio_enabled) + { return; + } - // when already listening then stop listening - if (listener) + // If already listening then stop listening. + if (mpListener) { - delete listener; - listener = 0; + delete mpListener; + mpListener = 0; if (start_stop_mode) + { return; + } } if (key < 0) + { return; + } if (pcm[PLAYBACK]) // device busy (playing) + { return; - listener = new tAlsaAudioListener(this, key); + } + + mpListener = new tAlsaAudioListener(this, key); } -void tAlsaAudioPlayer::ListenAudio(tSample &spl, long fr_smpl, long to_smpl) +void tAlsaAudioPlayer::ListenAudio(tSample& spl, long fr_smpl, long to_smpl) { if (!audio_enabled) + { return; + } - // when already listening then stop listening - if (listener) + // If already listening then stop listening. + if (mpListener) { - delete listener; - listener = 0; + delete mpListener; + mpListener = 0; } + if (pcm[PLAYBACK]) // device busy (playing) + { return; - listener = new tAlsaAudioListener(this, spl, fr_smpl, to_smpl); + } + mpListener = new tAlsaAudioListener(this, spl, fr_smpl, to_smpl); } long tAlsaAudioPlayer::GetListenerPlayPosition() { - if (!listener) + if (!mpListener) + { return -1L; - return listener->GetPlayPosition(); + } + return mpListener->GetPlayPosition(); } Modified: trunk/jazz/src/AlsaDriver.h =================================================================== --- trunk/jazz/src/AlsaDriver.h 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/AlsaDriver.h 2008-04-05 23:43:43 UTC (rev 399) @@ -48,31 +48,39 @@ virtual void SetAudioEnabled(int x) { audio_enabled = x; } virtual void ListenAudio(int key, int start_stop_mode = 1); virtual void ListenAudio(tSample &spl, long fr_smpl, long to_smpl); - virtual bool IsListening() const { - return listener != 0; + virtual bool IsListening() const + { + return mpListener != 0; } virtual long GetListenerPlayPosition(); virtual void StartAudio(); virtual void ResetPlay(long clock); - enum { PLAYBACK = 0, CAPTURE }; + enum + { + PLAYBACK = 0, + CAPTURE + }; // for recording int RecordMode() const; int PlayBackMode() const; private: - int can_duplex; // TRUE = can do full duplex record/play int WriteSamples(); void ReadSamples(); void MidiSync(); void OpenDsp(int mode, int sync_mode); - void CloseDsp(int reset); + void CloseDsp(bool Reset); + long GetCurrentPosition(int mode); int GetFreeSpace(int mode); + // If true can do full duplex record/play. + int mCanDuplex; + snd_pcm_t *pcm[2]; int installed; @@ -92,7 +100,7 @@ int frame_shift[2]; long frame_boundary[2]; - tAlsaAudioListener *listener; + tAlsaAudioListener* mpListener; tAudioRecordBuffer recbuffers; }; Modified: trunk/jazz/src/AudioDriver.cpp =================================================================== --- trunk/jazz/src/AudioDriver.cpp 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/AudioDriver.cpp 2008-04-05 23:43:43 UTC (rev 399) @@ -34,63 +34,83 @@ #include <fcntl.h> - #define AUDIO_DEVICE "/dev/dsp" class tAudioListener : public wxTimer { public: - tAudioListener(tAudioPlayer *p, int key) { - hard_exit = TRUE; - player = p; - player->listener = this; - player->rec_info = 0; // not recording! + tAudioListener(tAudioPlayer* pPlayer, int key) + : wxTimer(), + mpPlayer(pPlayer), + mCount(0), + mHardExit(true) + { + mpPlayer->mpListener = this; + + mpPlayer->rec_info = 0; // not recording! + // SYNC seems not to work?? so add 8 more silent buffers // to hear the end of the sample too. - count = 8 + player->samples.PrepareListen(key); - player->OpenDsp(); + mCount = 8 + mpPlayer->samples.PrepareListen(key); + mpPlayer->OpenDsp(); Start(20); } - tAudioListener(tAudioPlayer *p, tSample &spl, long fr_smpl, long to_smpl) { - hard_exit = TRUE; - player = p; - player->listener = this; - player->rec_info = 0; // not recording! + tAudioListener( + tAudioPlayer* pPlayer, + tSample& spl, + long fr_smpl, + long to_smpl) + : wxTimer(), + mpPlayer(pPlayer), + mCount(0), + mHardExit(true), + { + mpPlayer = p; + mpPlayer->mpListener = this; + mpPlayer->rec_info = 0; // not recording! - count = 8 + player->samples.PrepareListen(&spl, fr_smpl, to_smpl); - player->OpenDsp(); + mCount = 8 + mpPlayer->samples.PrepareListen(&spl, fr_smpl, to_smpl); + mpPlayer->OpenDsp(); Start(20); } - ~tAudioListener() { + ~tAudioListener() + { Stop(); - player->CloseDsp(hard_exit); - player->listener = 0; + mpPlayer->CloseDsp(mHardExit); + mpPlayer->mpListener = 0; } - virtual void Notify() { - count -= player->WriteSamples(); - count += player->samples.ContinueListen(); - if (count <= 0) + virtual void Notify() + { + mCount -= mpPlayer->WriteSamples(); + mCount += mpPlayer->samples.ContinueListen(); + if (mCount <= 0) { - hard_exit = FALSE; + mHardExit = false; delete this; } } - long GetPlayPosition() { + long GetPlayPosition() + { count_info cinfo; - if (ioctl(player->dev, SNDCTL_DSP_GETOPTR, &cinfo) == -1) + if (ioctl(mpPlayer->dev, SNDCTL_DSP_GETOPTR, &cinfo) == -1) + { perror("SNDCTL_DSP_GETOPTR"); + } return (cinfo.bytes - cinfo.ptr) / sizeof(short); } private: - tAudioPlayer *player; - int count; - int hard_exit; + + tAudioPlayer* mpPlayer; + + int mCount; + + int mHardExit; }; @@ -99,41 +119,55 @@ : tSeq2Player(song) { long dummy = 0; - AudioBuffer = new tEventArray(); - installed = 0; + AudioBuffer = new tEventArray(); + installed = 0; dummy = gpConfig->GetValue(C_EnableAudio); audio_enabled = dummy; - listener = 0; - can_duplex = 0; // no duplex yet. - dev = -1; + mpListener = 0; + mCanDuplex = 0; // no duplex yet. + dev = -1; // check for device dev = open(AUDIO_DEVICE, O_WRONLY, 0); - if (dev >= 0) { + if (dev >= 0) + { // check device caps int caps; ioctl(dev, SNDCTL_DSP_GETCAPS, &caps); if (caps & DSP_CAP_REALTIME) + { ; // fprintf(stderr, AUDIO " supports REALTIME, good!\n"); + } + if (caps & DSP_CAP_DUPLEX) - can_duplex = 1; // good soundcard! + { + mCanDuplex = 1; // good soundcard! + } + if (!(caps & DSP_CAP_TRIGGER)) - fprintf(stderr, "no CAP_TRIGGER support!\n"); + { + cerr << "no CAP_TRIGGER support!" << endl; + } else + { installed = 1; + } + close(dev); } else + { perror(AUDIO_DEVICE); + } + dev = -1; // closed audio_enabled = audio_enabled && installed; - } tAudioPlayer::~tAudioPlayer() { - delete listener; + delete mpListener; delete AudioBuffer; if (dev >= 0) close(dev); @@ -153,12 +187,16 @@ void tAudioPlayer::StartAudio() { if (!audio_enabled) + { return; + } long ticks_per_minute = Song->TicksPerQuarter * Song->Speed(); samples.ResetBuffers(AudioBuffer, start_clock, ticks_per_minute); if (PlaybackMode()) + { samples.FillBuffers(OutClock); + } audio_bytes = 0; midi_clock = 0; @@ -191,9 +229,11 @@ int tmp; if (!audio_enabled) + { return; + } - can_duplex = gpConfig->GetValue(C_DuplexAudio); + mCanDuplex = gpConfig->GetValue(C_DuplexAudio); // linux driver seems to need some real free memory, which sometimes // is not available when operating with big samples. So allocate @@ -207,61 +247,91 @@ } int mode = 0; - if (can_duplex) + if (mCanDuplex) + { mode = O_RDWR; + } else if (RecordMode()) + { mode = O_RDONLY; + } else + { mode = O_WRONLY; + } dev = open(AUDIO_DEVICE, mode, 0); - if (dev < 0) { + if (dev < 0) + { perror(AUDIO_DEVICE); audio_enabled = 0; return; } - if (can_duplex) + if (mCanDuplex) + { ioctl(dev, SNDCTL_DSP_SETDUPLEX, 0); + } tmp = 0xffff0000 | FRAGBITS; - if (ioctl(dev, SNDCTL_DSP_SETFRAGMENT, &tmp)==-1) + if (ioctl(dev, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) + { perror("ioctl DSP_SETFRAGMENT"); + } tmp = samples.BitsPerSample(); ioctl(dev, SNDCTL_DSP_SAMPLESIZE, &tmp); if (tmp != samples.BitsPerSample()) - fprintf(stderr, "Unable to set the sample size\n"); + { + cerr << "Unable to set the sample size" << endl; + } tmp = (samples.GetChannels() == 1) ? 0 : 1; - if (ioctl (dev, SNDCTL_DSP_STEREO, &tmp)==-1) - fprintf (stderr, "Unable to set mono/stereo\n"); + if (ioctl (dev, SNDCTL_DSP_STEREO, &tmp) == -1) + { + cerr << "Unable to set mono/stereo" << endl; + } tmp = samples.GetSpeed(); if (ioctl (dev, SNDCTL_DSP_SPEED, &tmp) == -1) + { perror("ioctl DSP_SPEED"); + } - // check if fragsize was ok - ioctl (dev, SNDCTL_DSP_GETBLKSIZE, &tmp); + // Check to see if the fragment size was OK. + ioctl(dev, SNDCTL_DSP_GETBLKSIZE, &tmp); if (tmp < 1) - perror ("GETBLKSIZE"); + { + perror("GETBLKSIZE"); + } else if (tmp != FRAGBYTES) - fprintf(stderr, "Unable to verify FRAGMENT %d, fbytes = %d, fshorts = %d\n", tmp, FRAGBYTES, FRAGSHORTS); + { + cerr + << "Unable to verify FRAGMENT " << tmp + << ", fbytes = " << FRAGBYTES + << ", fshorts = " << FRAGSHORTS + << endl; + } } -void tAudioPlayer::CloseDsp(int reset) +void tAudioPlayer::CloseDsp(bool Reset) { if (dev >= 0) { - if (reset) + if (Reset) { if (ioctl(dev, SNDCTL_DSP_RESET, 0) == -1) + { perror("SNDCTL_DSP_RESET"); + } } - else { + else + { if (ioctl (dev, SNDCTL_DSP_SYNC, NULL) < 0) + { perror("SNDCTL_DSP_SYNC"); + } } close(dev); dev = -1; @@ -271,18 +341,26 @@ void tAudioPlayer::Notify() { - if (audio_enabled) { - if (PlaybackMode()) { + if (audio_enabled) + { + if (PlaybackMode()) + { WriteSamples(); + // here it may hang when swapping in pages samples.FillBuffers(OutClock); + WriteSamples(); } if (RecordMode()) + { ReadSamples(); + } if (samples.softsync) + { MidiSync(); + } } tSeq2Player::Notify(); } @@ -291,25 +369,34 @@ int tAudioPlayer::WriteSamples() { if (!audio_enabled) + { return 0; + } int blocks_written = 0; // number of blocks to be written audio_buf_info info; if (ioctl(dev, SNDCTL_DSP_GETOSPACE, &info) == -1) + { perror("SNDCTL_DSP_GETOSPACE"); + } // todo: this is a bug in the audiodriver in newer kernels (2.1.28) // and the oss/linux for 2.0.29 it should be - // for (int i = 0; i < info.fragments; i++) { + // for (int i = 0; i < info.fragments; i++) - for (int i = 0; i < info.fragments - 1; i++) { + for (int i = 0; i < info.fragments - 1; i++) + { tAudioBuffer *buf = samples.full_buffers.Get(); if (buf == 0) + { break; + } if (write(dev, buf->Data(), BUFBYTES) != BUFBYTES) + { perror("write"); + } blocks_written ++; samples.free_buffers.Put(buf); } @@ -322,21 +409,29 @@ { audio_buf_info info; if (ioctl(dev, SNDCTL_DSP_GETISPACE, &info) == -1) + { perror("SNDCTL_DSP_GETISPACE"); + } // a oss bug: if read is not called, there will be // no recording. probably recording does NOT start // exactly in sync with midi - but who knows. if (force_read && !info.fragments) + { info.fragments = 1; + } force_read = 0; - for (int i = 0; i < info.fragments; i++) { + for (int i = 0; i < info.fragments; i++) + { short *b = recbuffers.RequestBuffer()->data; - if (read(dev, b, BUFBYTES) != BUFBYTES) { + if (read(dev, b, BUFBYTES) != BUFBYTES) + { // oss bug? It send EINTR?? on first read.. if (errno != EINTR && errno != EAGAIN) + { perror("read"); + } recbuffers.UndoRequest(); break; } @@ -347,21 +442,27 @@ void tAudioPlayer::MidiSync() { - // OSS is buggy! In Win32 SDK you read the docs, hack away and - // everything works. In OSS, there are no docs and if it works + // OSS is buggy! In Win32 SDK you read the docs, hack away and + // everything works. In OSS, there are no docs and if it works // with kernel x it wont with kernel y. if (!audio_enabled) + { return; + } int command = SNDCTL_DSP_GETOPTR; if (!PlaybackMode()) + { command = SNDCTL_DSP_GETIPTR; + } // get realtime info for audio/midi sync count_info cinfo; if (ioctl(dev, command, &cinfo) == -1) + { perror("SNDCTL_DSP_GETOPTR"); + } // search for SNDCTL_DSP_GETOPTR in linux/drivers/sound/dmabuf // before trying to understand the next line @@ -370,12 +471,16 @@ { // driver has processed some bytes or whole fragment if (ioctl(seqfd, SNDCTL_SEQ_GETTIME, &midi_clock) < 0) - perror("ioctl SNDCTL_SEQ_GETTIME failed - please get a newer kernel (2.1.28 or up)"); + { + perror( + "ioctl SNDCTL_SEQ_GETTIME failed - " + "please get a newer kernel (2.1.28 or up)"); + } audio_bytes = new_bytes; // OSS bug?: mpu401 does not like speed changes too often - long audio_clock = (long)samples.Samples2Ticks(audio_bytes/2); - int delta_clock = audio_clock - midi_clock; + long audio_clock = (long)samples.Samples2Ticks(audio_bytes / 2); + int delta_clock = audio_clock - midi_clock; int new_speed = midi_speed + delta_clock; // limit speed changes to some reasonable values @@ -392,20 +497,21 @@ if (new_speed != curr_speed) { if (ioctl(seqfd, SNDCTL_TMR_TEMPO, &new_speed) < 0) - // this sometimes happens with mpu-401 timer + { + // Sometimes this happens with mpu-401 timer. ; // perror("SNDCTL_TMR_TEMPO"); + } else + { curr_speed = new_speed; - // xview has reentrancy problems!! - // gpTrackWindow->DrawSpeed(curr_speed); + } } - } } void tAudioPlayer::StartPlay(long Clock, long LoopClock, int Continue) { - delete listener; + delete mpListener; samples.StartPlay(Clock); tSeq2Player::StartPlay(Clock, LoopClock, Continue); } @@ -415,21 +521,26 @@ samples.StopPlay(); tSeq2Player::StopPlay(); if (!audio_enabled) + { return; - CloseDsp(TRUE); + } + + CloseDsp(true); if (RecordMode()) { long frc = rec_info->mFromClock; if (frc < start_clock) + { frc = start_clock; + } long toc = rec_info->mToClock; if (toc > recd_clock) + { toc = recd_clock; + } samples.SaveRecordingDlg(frc, toc, recbuffers); } recbuffers.Clear(); - // xview has reentrancy problems!! - // gpTrackWindow->DrawSpeed(midi_speed); } @@ -437,42 +548,58 @@ void tAudioPlayer::ListenAudio(int key, int start_stop_mode) { if (!audio_enabled) + { return; + } // when already listening then stop listening - if (listener) + if (mpListener) { - delete listener; - listener = 0; + delete mpListener; + mpListener = 0; if (start_stop_mode) + { return; + } } if (key < 0) + { return; + } if (dev >= 0) // device busy (playing) + { return; - listener = new tAudioListener(this, key); + } + + mpListener = new tAudioListener(this, key); } void tAudioPlayer::ListenAudio(tSample &spl, long fr_smpl, long to_smpl) { if (!audio_enabled) + { return; + } // when already listening then stop listening - if (listener) - delete listener; + if (mpListener) + { + delete mpListener; + } + if (dev >= 0) // device busy (playing) + { return; - listener = new tAudioListener(this, spl, fr_smpl, to_smpl); + } + mpListener = new tAudioListener(this, spl, fr_smpl, to_smpl); } -long tAudioPlayer::GetListenerPlayPosition() { - if (!listener) +long tAudioPlayer::GetListenerPlayPosition() +{ + if (!mpListener) + { return -1L; - return listener->GetPlayPosition(); + } + return mpListener->GetPlayPosition(); } - - - Modified: trunk/jazz/src/AudioDriver.h =================================================================== --- trunk/jazz/src/AudioDriver.h 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/AudioDriver.h 2008-04-05 23:43:43 UTC (rev 399) @@ -27,7 +27,7 @@ // in oss/free (from kernel 2.0.29) the following is not implemented // but this works for oss/linux for 2.0.29 // #ifndef SNDCTL_SEQ_GETTIME -// #define SNDCTL_SEQ_GETTIME _IOR ('Q',19, int) +// #define SNDCTL_SEQ_GETTIME _IOR ('Q',19, int) // #endif #include <sys/time.h> @@ -43,52 +43,83 @@ class tAudioPlayer : public tSeq2Player { friend class tAudioListener; + public: + tAudioPlayer(JZSong *song); + virtual ~tAudioPlayer(); + int LoadSamples(const char *filename); + virtual void Notify(); + virtual void StartPlay(long Clock, long LoopClock = 0, int Continue = 0); + virtual void StopPlay(); + virtual void StartAudio(); - virtual int Installed() { return installed && tSeq2Player::Installed(); } - virtual int GetAudioEnabled() const { return audio_enabled; } - virtual void SetAudioEnabled(int x) { audio_enabled = x; } + + virtual int Installed() + { + return installed && tSeq2Player::Installed(); + } + + virtual int GetAudioEnabled() const + { + return audio_enabled; + } + + virtual void SetAudioEnabled(int x) + { + audio_enabled = x; + } + virtual void ListenAudio(int key, int start_stop_mode = 1); + virtual void ListenAudio(tSample &spl, long fr_smpl, long to_smpl); - virtual bool IsListening() const { - return listener != 0; + + virtual bool IsListening() const + { + return mpListener != 0; } + virtual long GetListenerPlayPosition(); // for recording int RecordMode() const; - int PlaybackMode() const { - return !RecordMode() || can_duplex; + + int PlaybackMode() const + { + return !RecordMode() || mCanDuplex; } private: - int can_duplex; // TRUE = can do full duplex record/play + // If true can do full duplex record/play. + int mCanDuplex; + int WriteSamples(); void ReadSamples(); void MidiSync(); void OpenDsp(); - void CloseDsp(int reset); + void CloseDsp(bool Reset); + int dev; int installed; long midi_clock; long audio_bytes; - int midi_speed; // start speed in bpm - int curr_speed; // actual speed in bpm - int audio_enabled; // 0 means midi only + int midi_speed; // start speed in bpm + int curr_speed; // actual speed in bpm + int audio_enabled; // 0 means midi only - tAudioListener *listener; + tAudioListener* mpListener; tAudioRecordBuffer recbuffers; - int force_read; // needed by buggy audio driver ... + // Needed by buggy audio driver ... + int force_read; }; #endif // !define(JZ_AUDIODRIVER_H) Modified: trunk/jazz/src/Player.cpp =================================================================== --- trunk/jazz/src/Player.cpp 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/Player.cpp 2008-04-05 23:43:43 UTC (rev 399) @@ -191,7 +191,7 @@ JZPlayer::JZPlayer(JZSong *song) - : samples( song->TicksPerQuarter * song->Speed() ) + : mSamples(song->TicksPerQuarter * song->Speed()) { DummyDeviceList.Add("default"); poll_millisec = 200; // default Modified: trunk/jazz/src/Player.h =================================================================== --- trunk/jazz/src/Player.h 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/Player.h 2008-04-05 23:43:43 UTC (rev 399) @@ -36,7 +36,9 @@ #include <sys/types.h> #include <time.h> +class JZRecordingInfo; + // audio-menu #define MEN_AUDIO_LOAD 200 #define MEN_AUDIO_SAVE 201 @@ -65,7 +67,7 @@ long Int2ExtClock(long Clock); void PrepareOutput( - tEventArray *buf, + tEventArray* buf, JZSong* pSong, long ExtFr, long ExtTo, @@ -74,14 +76,18 @@ private: long mStartClock; + long mStopClock; }; -enum tClockSource { CsInt = 0, CsFsk, CsMidi, CsMtc }; +enum tClockSource +{ + CsInt = 0, + CsFsk, + CsMidi, + CsMtc +}; -class JZRecordingInfo; - - class tDeviceList { public: @@ -197,22 +203,29 @@ virtual void ListenAudio(tSample &spl, long fr_smpl, long to_smpl) {} virtual bool IsListening() const { return 0; } - virtual int OnMenuCommand(int id) { + virtual int OnMenuCommand(int id) + { if (Playing) { return 0; } - return samples.OnMenuCommand(id); + return mSamples.OnMenuCommand(id); } - virtual const char *GetSampleName(int i) { - return samples.GetSampleName(i); + + virtual const char *GetSampleName(int i) + { + return mSamples.GetSampleName(i); } - virtual void AdjustAudioLength(JZTrack *t) { + + virtual void AdjustAudioLength(JZTrack *t) + { long ticks_per_minute = Song->TicksPerQuarter * Song->Speed(); - samples.AdjustAudioLength(t, ticks_per_minute); + mSamples.AdjustAudioLength(t, ticks_per_minute); } - void EditSample(int key) { - samples.Edit(key); + + void EditSample(int key) + { + mSamples.Edit(key); } virtual long GetListenerPlayPosition() @@ -222,14 +235,17 @@ void LoadDefaultSettings() { - samples.LoadDefaultSettings(); + mSamples.LoadDefaultSettings(); } protected: - tSampleSet samples; + tSampleSet mSamples; + public: + JZPlayer(JZSong *song); + virtual ~JZPlayer(); void Notify(); Modified: trunk/jazz/src/mswin/WindowsAudioInterface.cpp =================================================================== --- trunk/jazz/src/mswin/WindowsAudioInterface.cpp 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/mswin/WindowsAudioInterface.cpp 2008-04-05 23:43:43 UTC (rev 399) @@ -42,63 +42,83 @@ #define LeaveCriticalSection(a) #define DeleteCriticalSection(a) - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- class tAudioListener : public wxTimer { // play a sample from piano roll public: - tAudioListener(tWinAudioPlayer *p, int key) + tAudioListener(tWinAudioPlayer* pPlayer, int key) + : wxTimer(), + mpPlayer(pPlayer), + mCount(0), + mHardExit(true), + mChannels(0) { - hard_exit = TRUE; - player = p; - player->listener = this; - player->rec_info = 0; // not recording! - channels = player->samples.GetChannels(); + mpPlayer->mpListener = this; - count = player->samples.PrepareListen(key); - player->OpenDsp(); - player->StartAudio(); + // Indicate that we are not recording! + mpPlayer->rec_info = 0; + + mChannels = mpPlayer->mSamples.GetChannels(); + + mCount = mpPlayer->mSamples.PrepareListen(key); + + mpPlayer->OpenDsp(); + + mpPlayer->StartAudio(); + Start(200); } tAudioListener( - tWinAudioPlayer *p, - tSample &spl, + tWinAudioPlayer* pPlayer, + tSample& spl, long fr_smpl, long to_smpl) + : wxTimer(), + mpPlayer(pPlayer), + mCount(0), + mHardExit(true), + mChannels(0) { - hard_exit = TRUE; - player = p; - player->listener = this; - player->rec_info = 0; // not recording! - channels = player->samples.GetChannels(); + mpPlayer->mpListener = this; - count = player->samples.PrepareListen(&spl, fr_smpl, to_smpl); - player->OpenDsp(); - player->StartAudio(); + // Indicate that we are not recording! + mpPlayer->rec_info = 0; + + mChannels = mpPlayer->mSamples.GetChannels(); + + mCount = mpPlayer->mSamples.PrepareListen(&spl, fr_smpl, to_smpl); + + mpPlayer->OpenDsp(); + + mpPlayer->StartAudio(); + Start(200); } ~tAudioListener() { Stop(); - // todo: if !hard_exit flush outstanding buffers to device + + // todo: if !mHardExit flush outstanding buffers to device // before closing - player->CloseDsp(); - player->listener = 0; + mpPlayer->CloseDsp(); + mpPlayer->mpListener = 0; } virtual void Notify() { - EnterCriticalSection(&player->mutex); - count += player->samples.ContinueListen(); - player->WriteBuffers(); - LeaveCriticalSection(&player->mutex); - if (player->blocks_played >= count) + EnterCriticalSection(&mpPlayer->mutex); + mCount += mpPlayer->mSamples.ContinueListen(); + mpPlayer->WriteBuffers(); + LeaveCriticalSection(&mpPlayer->mutex); + if (mpPlayer->blocks_played >= mCount) { - hard_exit = FALSE; + mHardExit = false; delete this; } } @@ -107,21 +127,29 @@ { MMTIME mmtime; mmtime.wType = TIME_SAMPLES; - waveOutGetPosition(player->hout, &mmtime, sizeof(mmtime)); - return mmtime.u.sample * channels; + waveOutGetPosition(mpPlayer->hout, &mmtime, sizeof(mmtime)); + return mmtime.u.sample * mChannels; } private: - tWinAudioPlayer *player; - long count; - int hard_exit; - long channels; -}; + tWinAudioPlayer* mpPlayer; + long mCount; -tWinAudioPlayer::tWinAudioPlayer(JZSong *song) - : tWinIntPlayer(song) + bool mHardExit; + + long mChannels; +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +tWinAudioPlayer::tWinAudioPlayer(JZSong* pSong) + : tWinIntPlayer(pSong), + mErrorCode(NoError), + mCanDuplex(false), + mCanSynchronize(true), + mpListener(0) { state->audio_player = this; @@ -132,15 +160,12 @@ installed = 0; dummy = gpConfig->GetValue(C_EnableAudio); audio_enabled = dummy; - listener = 0; hout_open = 0; hinp_open = 0; // check for device installed = 0; - can_duplex = (gpConfig->GetValue(C_DuplexAudio) != 0); - error = NoError; - can_sync = 1; + mCanDuplex = (gpConfig->GetValue(C_DuplexAudio) != 0); if (OpenDsp() == 0) { @@ -149,99 +174,109 @@ MMRESULT res = waveOutGetDevCaps((UINT)hout, &ocaps, sizeof(ocaps)); if (res != MMSYSERR_NOERROR) { - error = ErrCapGet; + mErrorCode = ErrCapGet; } else if (!(ocaps.dwSupport & WAVECAPS_SAMPLEACCURATE)) { - // not a real error - wxMessageBox("your soundcard does not support audio/midi sync", "Warning", wxOK); - can_sync = 0; + // This is not an error; just a warning. + wxMessageBox( + "Your soundcard does not support audio/midi sync", + "Warning", + wxOK); + mCanSynchronize = false; } - if (!error && CloseDsp() == 0) + if (!mErrorCode && CloseDsp() == 0) + { installed = 1; + } } recbuffers.Clear(); audio_enabled = (audio_enabled && installed); - } - - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- tWinAudioPlayer::~tWinAudioPlayer() { - delete listener; + delete mpListener; delete AudioBuffer; - // close device if open + + // Close the device if it is open. CloseDsp(); - // release semaphor + + // Release the semaphor. DeleteCriticalSection(&mutex); } - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::ShowError() { - const char *msg = 0; - switch (error) + const char* pMessage = 0; + switch (mErrorCode) { case ErrOutOpen: - msg = "Cannot open audio output device"; + pMessage = "Cannot open audio output device"; break; case ErrOutPrepare: - msg = "Cannot prepare audio output headers"; + pMessage = "Cannot prepare audio output headers"; break; case ErrOutUnprepare: - msg = "Cannot unprepare audio output headers"; + pMessage = "Cannot unprepare audio output headers"; break; case ErrInpOpen: - msg = "Cannot open audio input device"; + pMessage = "Cannot open audio input device"; break; case ErrInpPrepare: - msg = "Cannot prepare audio input headers"; + pMessage = "Cannot prepare audio input headers"; break; case ErrInpUnprepare: - msg = "Cannot unprepare audio input headers"; + pMessage = "Cannot unprepare audio input headers"; break; case ErrCapGet: - msg = "Unable to get audio device capbabilities"; + pMessage = "Unable to get audio device capbabilities"; break; case ErrCapSync: - msg = "Your soundcard does not support audio/midi sync"; + pMessage = "Your soundcard does not support audio/midi sync"; break; } - if (msg) - wxMessageBox((char *)msg, "Error", wxOK); + if (pMessage) + { + wxMessageBox(pMessage, "Error", wxOK); + } } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- int tWinAudioPlayer::LoadSamples(const char *filename) { - return samples.Load(filename); + return mSamples.Load(filename); } - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- int tWinAudioPlayer::OpenDsp() { int i; MMRESULT res; - error = NoError; // everything ok for now. + mErrorCode = NoError; // everything ok for now. if (!audio_enabled) { return 0; } - can_duplex = (gpConfig->GetValue(C_DuplexAudio) != 0); + mCanDuplex = (gpConfig->GetValue(C_DuplexAudio) != 0); // specify the data format WAVEFORMATEX fmt; memset(&fmt, 0, sizeof(fmt)); fmt.wFormatTag = WAVE_FORMAT_PCM; - fmt.nChannels = samples.GetChannels(); - fmt.nSamplesPerSec = samples.GetSpeed(); - fmt.nBlockAlign = samples.GetChannels() * sizeof(short); + fmt.nChannels = mSamples.GetChannels(); + fmt.nSamplesPerSec = mSamples.GetSpeed(); + fmt.nBlockAlign = mSamples.GetChannels() * sizeof(short); fmt.nAvgBytesPerSec = fmt.nBlockAlign * fmt.nSamplesPerSec; fmt.wBitsPerSample = 16; fmt.cbSize = 0; @@ -264,14 +299,14 @@ if (res != MMSYSERR_NOERROR) { - error = ErrOutOpen; + mErrorCode = ErrOutOpen; return 1; } // prepare headers for (i = 0; i < BUFCOUNT; i++) { - tAudioBuffer *buf = samples.GetBuffer(i); + tAudioBuffer *buf = mSamples.GetBuffer(i); WAVEHDR *hdr = new WAVEHDR; memset(hdr, 0, sizeof(WAVEHDR)); buf->hdr = hdr; @@ -282,7 +317,7 @@ res = waveOutPrepareHeader(hout, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - error = ErrOutPrepare; + mErrorCode = ErrOutPrepare; return 1; } } @@ -297,7 +332,7 @@ res = waveInOpen(&hinp, WAVE_MAPPER, &fmt, (DWORD)audioInterrupt, (DWORD)this, CALLBACK_FUNCTION); if (res != MMSYSERR_NOERROR) { - error = ErrInpOpen; + mErrorCode = ErrInpOpen; return 1; } @@ -321,7 +356,7 @@ res = waveInAddBuffer(hinp, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - error = ErrInpPrepare; + mErrorCode = ErrInpPrepare; return 1; } } @@ -332,9 +367,8 @@ return 0; } - - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- int tWinAudioPlayer::CloseDsp() { // todo: close the device immediately if open @@ -342,7 +376,6 @@ int i; MMRESULT res; - if (hout_open) { hout_open = 0; @@ -353,13 +386,13 @@ // unprepare headers for (i = 0; i < BUFCOUNT; i++) { - tAudioBuffer *buf = samples.GetBuffer(i); + tAudioBuffer *buf = mSamples.GetBuffer(i); WAVEHDR *hdr = (WAVEHDR *)buf->hdr; res = waveOutUnprepareHeader(hout, hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - error = ErrOutUnprepare; + mErrorCode = ErrOutUnprepare; return 1; } delete hdr; @@ -384,7 +417,7 @@ res = waveInUnprepareHeader(hinp, (WAVEHDR *)buf->hdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { - error = ErrInpUnprepare; + mErrorCode = ErrInpUnprepare; return 1; } delete buf->hdr; @@ -397,16 +430,23 @@ return 0; } - -void FAR PASCAL audioInterrupt(HWAVEOUT hout, UINT wMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void FAR PASCAL audioInterrupt( + HWAVEOUT hout, + UINT wMsg, + DWORD dwUser, + DWORD dw1, + DWORD dw2) { if (wMsg == MM_WOM_DONE || wMsg == MM_WIM_DATA) + { ((tWinAudioPlayer *)dwUser)->AudioCallback(wMsg); + } } - - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::AudioCallback(UINT wMsg) { // async called by driver when the driver has processed a buffer completely @@ -416,8 +456,8 @@ { blocks_played ++; play_buffers_needed ++; - tAudioBuffer *buf = samples.driv_buffers.Get(); - samples.free_buffers.Put(buf); + tAudioBuffer *buf = mSamples.driv_buffers.Get(); + mSamples.free_buffers.Put(buf); } if (hinp_open && wMsg == MM_WIM_DATA) { @@ -426,10 +466,8 @@ LeaveCriticalSection(&mutex); } - - - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::StartAudio() { // async called by driver to start audio in sync with midi @@ -445,30 +483,37 @@ } } - +//----------------------------------------------------------------------------- +// Description: +// Send the sample set to driver. +//----------------------------------------------------------------------------- void tWinAudioPlayer::WriteBuffers() { if (audio_enabled && hout_open) { - tAudioBuffer *buf; - while ((buf = samples.full_buffers.Get()) != 0) + tAudioBuffer* pAudioBuffer; + while ((pAudioBuffer = mSamples.full_buffers.Get()) != 0) { - if (waveOutWrite(hout, buf->hdr, sizeof(WAVEHDR)) == MMSYSERR_NOERROR) + if ( + waveOutWrite( + hout, + pAudioBuffer->hdr, + sizeof(WAVEHDR)) == MMSYSERR_NOERROR) { - samples.driv_buffers.Put(buf); - -- play_buffers_needed; + mSamples.driv_buffers.Put(pAudioBuffer); + --play_buffers_needed; } else { - samples.full_buffers.UnGet(buf); + mSamples.full_buffers.UnGet(pAudioBuffer); break; } } } } - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::Notify() { if (audio_enabled) @@ -477,12 +522,14 @@ if (hout_open) { - samples.FillBuffers(OutClock); + mSamples.FillBuffers(OutClock); if (play_buffers_needed > 0) // dont trigger start play by accident + { WriteBuffers(); + } // midi time correction - if (can_sync && samples.softsync) + if (mCanSynchronize && mSamples.softsync) { MMTIME mmtime; MMRESULT res; @@ -490,11 +537,14 @@ res = waveOutGetPosition(hout, &mmtime, sizeof(mmtime)); if (res == MMSYSERR_NOERROR && mmtime.wType == TIME_SAMPLES) { - long time_now = (long)timeGetTime(); - long audio_now = (long)((double)start_time + (double)mmtime.u.sample * 1000.0 / (double)samples.speed); + long time_now = (long)timeGetTime(); + long audio_now = + (long)((double)start_time + 1000.0 * mmtime.u.sample / mSamples.speed); + // low pass filter for time-correction (not really necessary) const long low = 50; - state->time_correction = (low * state->time_correction + (100 - low) * (audio_now - time_now) ) / 100L; + state->time_correction = + (low * state->time_correction + (100 - low) * (audio_now - time_now) ) / 100L; } } } @@ -512,9 +562,9 @@ tAudioBuffer *buf = recbuffers.RequestBuffer(); buf->hdr = hdr; - hdr->lpData = (LPSTR)buf->data; - hdr->dwBufferLength = BUFBYTES; // length, in bytes, of the buffer - hdr->dwFlags = 0; // see below + hdr->lpData = (LPSTR)buf->data; + hdr->dwBufferLength = BUFBYTES; // length, in bytes, of the buffer + hdr->dwFlags = 0; if (waveInPrepareHeader(hinp, hdr, sizeof(WAVEHDR)) == MMSYSERR_NOERROR) { @@ -522,10 +572,12 @@ record_buffers_needed --; } else + { break; + } } - if (can_sync && samples.softsync && !hout_open) + if (mCanSynchronize && mSamples.softsync && !hout_open) { // midi time correction MMTIME mmtime; @@ -534,8 +586,9 @@ res = waveInGetPosition(hinp, &mmtime, sizeof(mmtime)); if (res == MMSYSERR_NOERROR && mmtime.wType == TIME_SAMPLES) { - long time_now = (long)timeGetTime(); - long audio_now = (long)((double)state->start_time + (double)mmtime.u.sample * 1000.0 / (double)samples.speed); + long time_now = (long)timeGetTime(); + long audio_now = + (long)((double)state->start_time + 1000.0 * mmtime.u.sample / mSamples.speed); // low pass filter for time-correction (not really necessary) const long low = 50; state->time_correction = (low * state->time_correction + (100 - low) * (audio_now - time_now) ) / 100L; @@ -549,34 +602,34 @@ tWinIntPlayer::Notify(); } - - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::StartPlay(long Clock, long LoopClock, int Continue) { - samples.StartPlay(Clock); + mSamples.StartPlay(Clock); tWinIntPlayer::StartPlay(Clock, LoopClock, Continue); if (!audio_enabled) return; - delete listener; + delete mpListener; start_clock = Clock; start_time = state->start_time; - samples.ResetBuffers(AudioBuffer, start_clock, state->ticks_per_minute); - samples.FillBuffers(OutClock); + mSamples.ResetBuffers(AudioBuffer, start_clock, state->ticks_per_minute); + mSamples.FillBuffers(OutClock); OpenDsp(); } - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::StopPlay() { tWinIntPlayer::StopPlay(); CloseDsp(); - samples.StopPlay(); + mSamples.StopPlay(); if (RecordMode()) { long frc = rec_info->mFromClock; @@ -586,33 +639,44 @@ long play_clock = Time2Clock(state->play_time); if (toc > play_clock) toc = play_clock; - samples.SaveRecordingDlg(frc, toc, recbuffers); + mSamples.SaveRecordingDlg(frc, toc, recbuffers); } recbuffers.Clear(); } - - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::ListenAudio(int key, int start_stop_mode) { if (!audio_enabled) + { return; + } - // play audio file from piano roll + // Play the audio file from the piano roll. if (Playing) + { return; - // when already listening then stop listening - if (listener) + } + + // If already listening then stop listening. + if (mpListener) { - delete listener; + delete mpListener; if (start_stop_mode) + { return; + } } if (key < 0) + { return; - listener = new tAudioListener(this, key); + } + mpListener = new tAudioListener(this, key); } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void tWinAudioPlayer::ListenAudio(tSample &spl, long fr_smpl, long to_smpl) { if (!audio_enabled) @@ -621,21 +685,27 @@ if (Playing) return; // when already listening then stop listening - if (listener) - delete listener; - listener = new tAudioListener(this, spl, fr_smpl, to_smpl); + if (mpListener) + { + delete mpListener; + } + mpListener = new tAudioListener(this, spl, fr_smpl, to_smpl); } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- long tWinAudioPlayer::GetListenerPlayPosition() { - if (!listener) + if (!mpListener) + { return -1L; - return listener->GetPlayPosition(); + } + return mpListener->GetPlayPosition(); } - +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- int tWinAudioPlayer::RecordMode() const { return rec_info != 0 && rec_info->mpTrack->GetAudioMode(); } - Modified: trunk/jazz/src/mswin/WindowsAudioInterface.h =================================================================== --- trunk/jazz/src/mswin/WindowsAudioInterface.h 2008-04-05 20:12:11 UTC (rev 398) +++ trunk/jazz/src/mswin/WindowsAudioInterface.h 2008-04-05 23:43:43 UTC (rev 399) @@ -35,77 +35,125 @@ class tWinAudioPlayer : public tWinIntPlayer { friend class tAudioListener; + public: - tWinAudioPlayer(JZSong *song); + + enum TEErrorCode + { + NoError, + ErrOutOpen, + ErrOutPrepare, + ErrOutUnprepare, + ErrInpOpen, + ErrInpPrepare, + ErrInpUnprepare, + ErrCapGet, + ErrCapSync + }; + + tWinAudioPlayer(JZSong* pSong); + virtual ~tWinAudioPlayer(); + int LoadSamples(const char *filename); + virtual void Notify(); + virtual void StartPlay(long Clock, long LoopClock = 0, int Continue = 0); + virtual void StopPlay(); + virtual void StartAudio(); // called async by driver - virtual int Installed() { return installed && tWinIntPlayer::Installed(); } - virtual int GetAudioEnabled() const { return audio_enabled; } - virtual void SetAudioEnabled(int x) { audio_enabled = x; } + + virtual int Installed() + { + return installed && tWinIntPlayer::Installed(); + } + + virtual int GetAudioEnabled() const + { + return audio_enabled; + } + + virtual void SetAudioEnabled(int x) + { + audio_enabled = x; + } + virtual void ListenAudio(int key, int start_stop_mode = 1); + virtual void ListenAudio(tSample &spl, long fr_smpl, long to_smpl); + virtual long GetListenerPlayPosition(); - virtual bool IsListening() const { - return listener != 0; + virtual bool IsListening() const + { + return mpListener != 0; } // for recording int RecordMode() const; - int PlaybackMode() const { - return !RecordMode() || can_duplex; + + int PlaybackMode() const + { + return !RecordMode() || mCanDuplex; } - enum ErrorCode { - NoError, - ErrOutOpen, ErrOutPrepare, ErrOutUnprepare, - ErrInpOpen, ErrInpPrepare, ErrInpUnprepare, - ErrCapGet, ErrCapSync - }; - ErrorCode GetError() { - return error; + TEErrorCode GetError() + { + return mErrorCode; } + virtual void ShowError(); private: - ErrorCode error; - int can_duplex; // TRUE = can do full duplex record/play - int can_sync; // TRUE = can determine exact output play position + // ms specific + friend void FAR PASCAL audioInterrupt( + HWAVEOUT, + UINT, + DWORD, + DWORD, + DWORD); - int OpenDsp(); // 0 = ok - int CloseDsp(); // 0 = ok + // Description: + // Send the sample set to driver. + void WriteBuffers(); - int installed; - int audio_enabled; // 0 means midi only + void AudioCallback(UINT msg); + + TEErrorCode mErrorCode; + + // Indicates if full duplex record/play is possible. + bool mCanDuplex; + + // Indicates if the exact output play position can be determined. + bool mCanSynchronize; + + int OpenDsp(); // 0 = ok + int CloseDsp(); // 0 = ok + + int installed; + int audio_enabled; // 0 means midi only long blocks_played; // # of blocks written to device - int play_buffers_needed; // driver requests more output buffers + int play_buffers_needed; // driver requests more output buffers long start_clock; // when did play start long start_time; // play start time (not altered by SetTempo) - tAudioListener *listener; + tAudioListener* mpListener; - // ms specific - friend void FAR PASCAL audioInterrupt(HWAVEOUT, UINT, DWORD, DWORD, DWORD); HWAVEOUT hout; HWAVEIN hinp; - void WriteBuffers(); // send samples.full_buffers to driver - void AudioCallback(UINT msg); - int hout_open; // true = playback device opended successful - int hinp_open; // true = recording device opended successful + int hout_open; // true = playback device opended successful + int hinp_open; // true = recording device opended successful tAudioRecordBuffer recbuffers; - int record_buffers_needed; // driver needs more buffers + int record_buffers_needed; // driver needs more buffers // a semaphor for thread synchronization. Since Notify() and // the audio callback are not time critical, its safe to // let them wait for each other. CRITICAL_SECTION ... [truncated message content] |