--------------Boundary-00=_RC2QVUOBMEA14N0LWUWB Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit [found the list and remembered my wish list item] Hi all (since I have no idea who is responsible for the code) I have made "some" modifications to oggvorbis_artsplugin to make it handle non 44100 Hz files. 44100 Hz files is a lot easier since you decode to the same frequency as arts uses internally... The possibility to use other sampling frequencies and mono was added in ogg rc3. wav(f Hz, c Channels) => encode => ogg rc3 => decode => wav(f Hz, c Channels) This gives some problems when trying to handle the standard arts frequency. You basically need to resample - I have included a simple resampler. Audio quality has not been my priority up to this point - now it gives right audio for the correct time. (it works but gives bad audio quality - overtones, a filter with the band width of the original sound will help...) My feeling is that there are probably working resamplers included somewere in the arts libraries... Help please? BUT: I think I detected quite a number of races while working with the code. As an example: when the file is read to end then this code was executed... ! //signal completion ! foo.val = 0; ! // no more data available ! semctl(buflen_sem, 0, SETVAL, foo); ! // and no room either (ie, none coming) ! semctl(buflen_sem, 1, SETVAL, foo); Two problems: * writing zero to sem 0 will not let the audio file play to the end. all samples that were buffered got removed in one stroke. * writing zero to sem 1 might race with main process updating sem 1 and the expected condition will never happen... /RogerL -- Roger Larsson Skellefteċ Sweden --------------Boundary-00=_RC2QVUOBMEA14N0LWUWB Content-Type: text/x-diff; charset="iso-8859-1"; name="kde_oggvorbis_artsplugin.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="kde_oggvorbis_artsplugin.patch" ? oggarts.mcoptype ? oggarts.h ? oggarts.cc ? oggarts.mcopclass Index: oggPlayObject_impl.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/kde/kdemultimedia/oggvorbis_artsplugin/oggPlayObject_impl= =2Ecpp,v retrieving revision 1.3 diff -c -r1.3 oggPlayObject_impl.cpp *** oggPlayObject_impl.cpp=092001/12/14 20:54:43=091.3 --- oggPlayObject_impl.cpp=092002/01/29 22:02:00 *************** *** 32,41 **** --- 32,43 ---- =20 =20 #include "oggPlayObject_impl.h" + #define SAMPLESIZE sizeof(short) =20 using namespace Arts; =20 oggPlayObject_impl::oggPlayObject_impl() + =09: fract_bufpos(0), reserved(0) { =09struct shmid_ds bleh; =09shm_id =3D shmget(IPC_PRIVATE, sizeof(*shm_buf), 0600); *************** *** 95,114 **** =20 =09FILE *ogg_fp; =09ogg_fp =3D fopen(filename.c_str(), "r"); =09int current_section=3D0; =20 =09ov_open(ogg_fp, &vf, NULL, 0); =09if (!(child_pid =3D fork())) { =09=09arts_debug("oggvorbis: child process"); =09=09do { ! =09=09=09// get more data =20 =09=09=09int seekTo =3D semctl(buflen_sem, 2, GETVAL, foo); =09=09=09if (seekTo) { =09=09=09=09arts_debug("oggvorbis: seeking to %d", seekTo); =09=09=09=09// we have a seek command =09=09=09=09int ret =3D ov_time_seek(&vf, (double)seekTo-1); ! =09=09=09=09arts_debug("oggvorbis: ov_time_seek returned: %d\n", ret); =09=09=09=09foo.val=3D0; =09=09=09=09semctl(buflen_sem, 2, SETVAL, foo); // we've done it =09=09=09} --- 97,135 ---- =20 =09FILE *ogg_fp; =09ogg_fp =3D fopen(filename.c_str(), "r"); + =09if (ogg_fp =3D=3D NULL) { + =09 perror(filename.c_str()); + =09 return false; + =09} +=20 =09int current_section=3D0; =20 =09ov_open(ogg_fp, &vf, NULL, 0); + =09arts_debug("oggvorbis: Encoded by: %s",ov_comment(&vf,-1)->vendor); + =20 + =09// Check user comments and info + =09char **ptr=3Dov_comment(&vf,-1)->user_comments; + =09while(*ptr){ + =09 arts_debug("oggvorbis: %s",*ptr); + =09 ++ptr; + =09} +=20 + =09vorbis_info *vi=3Dov_info(&vf,-1); + =09arts_debug("\noggvorbis: Bitstream is %d channel, %ldHz (hw %d Hz)"= ,vi->channels,vi->rate, samplingRate); + =09shm_buf->rate =3D vi->rate; + =20 + =20 =09if (!(child_pid =3D fork())) { =09=09arts_debug("oggvorbis: child process"); =09=09do { ! =09=09=09// seek and indicate position =20 =09=09=09int seekTo =3D semctl(buflen_sem, 2, GETVAL, foo); =09=09=09if (seekTo) { =09=09=09=09arts_debug("oggvorbis: seeking to %d", seekTo); =09=09=09=09// we have a seek command =09=09=09=09int ret =3D ov_time_seek(&vf, (double)seekTo-1); ! =09=09=09=09arts_debug("oggvorbis: ov_time_seek returned: %d", ret); =09=09=09=09foo.val=3D0; =09=09=09=09semctl(buflen_sem, 2, SETVAL, foo); // we've done it =09=09=09} *************** *** 116,135 **** =09=09=09if (foo.val =3D=3D -1) foo.val=3D0; =09=09=09semctl(buflen_sem, 3, SETVAL, foo); =20 ! =09=09=09int thisPass =3D ov_read(&vf, (char *)decode_buf, BACKBUFSIZ*s= izeof(short), 0, 2, 1, ¤t_section); ! =09=09=09if (thisPass =3D=3D 0) { =09=09=09=09// we're done, or we errored (in which case we're done) =09=09=09=09break; =09=09=09} ! =09=09=09thisPass =3D (thisPass / 4); =20 =20 =09=09=09semoper.sem_num =3D 1; =09=09=09semoper.sem_op =3D -thisPass; =09=09=09semop(buflen_sem, &semoper, 1); =20 ! =09=09=09// block until there's enough space to stick in this frame =09=09=09int roomFor =3D semctl(buflen_sem, 1, GETVAL, foo); =09=09=09if (roomFor > BACKBUFSIZ) { =09=09=09=09arts_debug("oggvorbis: exit requested, bye!"); =09=09=09=09// this can never go above BACKBUFSIZ in normal operation, --- 137,162 ---- =09=09=09if (foo.val =3D=3D -1) foo.val=3D0; =09=09=09semctl(buflen_sem, 3, SETVAL, foo); =20 ! =09=09=09// get more data !=20 ! =09=09=09// ALWAYS read 16 bit little endian, that specific format will= be converted to float later... ! =09=09=09int thisPass =3D ov_read(&vf, (char *)decode_buf, sizeof(decod= e_buf), 0, SAMPLESIZE, 1, ¤t_section); ! =09=09=09if (thisPass <=3D 0) { =09=09=09=09// we're done, or we errored (in which case we're done) + =09=09=09=09arts_debug("oggvorbis: ov_read returned: thisPass=3D%d", th= isPass); =09=09=09=09break; =09=09=09} ! =09=09=09thisPass =3D (thisPass / (SAMPLESIZE * vi->channels)); =20 =20 + =09=09=09// block until there's enough space to stick in this frame =09=09=09semoper.sem_num =3D 1; =09=09=09semoper.sem_op =3D -thisPass; =09=09=09semop(buflen_sem, &semoper, 1); =20 ! =09=09=09// check if exit is requested - non blocking =09=09=09int roomFor =3D semctl(buflen_sem, 1, GETVAL, foo); +=20 =09=09=09if (roomFor > BACKBUFSIZ) { =09=09=09=09arts_debug("oggvorbis: exit requested, bye!"); =09=09=09=09// this can never go above BACKBUFSIZ in normal operation, *************** *** 138,145 **** =09=09=09} =20 =09=09=09for (int i=3D0 ; i left[buf_pos] =3D conv_16le_float(decode_buf[2*i])= ; ! =09=09=09=09shm_buf->right[buf_pos] =3D conv_16le_float(decode_buf[2*i+= 1]); =09=09=09} =20 =09=09=09//arts_debug("oggvorbis: enqueued them"); --- 165,174 ---- =09=09=09} =20 =09=09=09for (int i=3D0 ; i left[buf_pos] =3D conv_16le_float(decode_buf[vi->c= hannels*i]); ! =09=09=09=09shm_buf->right[buf_pos] =3D conv_16le_float(decode_buf[vi->= channels*i+(vi->channels-1)]); =09=09=09} =20 =09=09=09//arts_debug("oggvorbis: enqueued them"); *************** *** 150,161 **** =09=09=09//arts_debug("oggvorbis: calculated %d more samples",shm_buf->= back$ =09=09} while(1); =20 ! =09=09//signal completion ! =09=09foo.val =3D 0; ! =09=09// no more data available ! =09=09semctl(buflen_sem, 0, SETVAL, foo); ! =09=09// and no room either (ie, none coming) ! =09=09semctl(buflen_sem, 1, SETVAL, foo); =20 =09=09arts_debug("oggvorbis: decoder process exiting"); =09=09exit(0); --- 179,189 ---- =09=09=09//arts_debug("oggvorbis: calculated %d more samples",shm_buf->= back$ =09=09} while(1); =20 ! =09=09// block until all produced data has been consumed ! =09=09arts_debug("oggvorbis: decoder process waiting"); ! =09=09semoper.sem_num =3D 0; ! =09=09semoper.sem_op =3D 0; ! =09=09semop(buflen_sem, &semoper, 1); =20 =09=09arts_debug("oggvorbis: decoder process exiting"); =09=09exit(0); *************** *** 177,183 **** =09if (time.seconds =3D=3D -1) =09=09time.seconds =3D 0; // Eek infinite loop time. =09time.ms=3D0; ! =09//arts_debug("oggvorbis: time is now %d\n", time.seconds); =09return time; } =20 --- 205,211 ---- =09if (time.seconds =3D=3D -1) =09=09time.seconds =3D 0; // Eek infinite loop time. =09time.ms=3D0; ! =09//arts_debug("oggvorbis: time is now %d", time.seconds); =09return time; } =20 *************** *** 210,215 **** --- 238,244 ---- =09mState =3D posIdle; =09union semun foo; =20 + =09arts_debug("oggvorbis: halt"); =09if (child_pid) { =09=09arts_debug("oggvorbis: killing decoder process"); =09=09foo.val =3D 2*BACKBUFSIZ; *************** *** 222,227 **** --- 251,265 ---- =09// mainly this is to ensure that the decoder wakes up to notice } =20 + void oggPlayObject_impl::halt_on_decoderTerminated() { + =09if (child_pid &&=20 + =09 waitpid(child_pid, NULL, WNOHANG)) { // child has already termin= ated! + =09=09child_pid =3D 0; + =09=09halt(); + =09} + } +=20 +=20 void oggPlayObject_impl::seek(const class poTime &t) { =09union semun foo; *************** *** 249,255 **** =20 void oggPlayObject_impl::calculateBlock(unsigned long samples) { ! =09int samplesAvailable =3D 0; =20 =09//arts_debug("oggvorbis: calculateBlock"); =20 --- 287,293 ---- =20 void oggPlayObject_impl::calculateBlock(unsigned long samples) { ! =09unsigned long samplesWritten =3D 0; =20 =09//arts_debug("oggvorbis: calculateBlock"); =20 *************** *** 257,306 **** =09=09//arts_debug("oggvorbis: calculateBlock, %d(%d) of %d samples in = buffer", =09=09//shm_buf->buflen - bufpos, shm_buf->backbuflen,samples); =20 ! =09=09struct sembuf bleh; =20 ! =09=09bleh.sem_num =3D 0; ! =09=09bleh.sem_flg =3D IPC_NOWAIT; ! =09=09//arts_debug("oggvorbis: %d samples wanted", samplesAvailable); ! =09=09bleh.sem_op =3D -samples; // does the buffer have sufficient samp= les? ! =09=09if (semop(buflen_sem, &bleh, 1) =3D=3D -1) { ! =09=09=09if (errno =3D=3D EAGAIN) { ! =09=09=09=09union semun foo; =09=09=09=09arts_debug("oggvorbis: buffer underrun"); ! =09=09=09=09samplesAvailable =3D semctl(buflen_sem, 0, GETVAL, foo); ! =09=09=09=09// no samples AND no room is the decoder's way of signallin= g completion ! =09=09=09=09if (semctl(buflen_sem, 1, GETVAL, foo) =3D=3D 0) { ! =09=09=09=09=09halt(); ! =09=09=09=09=09samplesAvailable =3D 0; =09=09=09=09} =09=09=09} else { ! =09=09=09=09// something awful has happened =09=09=09=09halt(); ! =09=09=09=09samplesAvailable =3D 0; =09=09=09} - =09=09} else { - =09=09=09samplesAvailable =3D samples; // number of samples we pushed f= rom buffers - =09=09=09// used to calculate the number we should zero out for an unde= rrun =09=09} - =09=09bleh.sem_flg =3D 0; // back to normal now -=20 - =09=09//arts_debug("oggvorbis: %d samples available",samplesAvailable); - =09=09for (int i =3D 0; i < samplesAvailable; - =09=09=09++i, buf_pos =3D ((buf_pos + 1) % BACKBUFSIZ)) { =20 ! =09=09=09left[i] =3D shm_buf->left[buf_pos]; ! =09=09=09right[i] =3D shm_buf->right[buf_pos]; =09=09} =20 ! =09=09bleh.sem_num =3D 1; ! =09=09bleh.sem_op =3D samplesAvailable; ! =09=09semop(buflen_sem, &bleh, 1); // mark the now-free space =09} =09// zero out any samples we didn't have enough to complete ! =09while(static_cast(samplesAvailable) < samples) { ! =09=09left[samplesAvailable] =3D 0.0; ! =09=09right[samplesAvailable] =3D 0.0; ! =09=09samplesAvailable++; =09} } =20 --- 295,378 ---- =09=09//arts_debug("oggvorbis: calculateBlock, %d(%d) of %d samples in = buffer", =09=09//shm_buf->buflen - bufpos, shm_buf->backbuflen,samples); =20 ! =09=09int additional_reserve; ! =09=09if (shm_buf->rate =3D=3D samplingRate) { ! =09=09=09additional_reserve =3D samples; ! =09=09} else { ! =09=09=09additional_reserve =3D samples*shm_buf->rate/samplingRate + 1 = - reserved; ! =09=09} =20 ! =09=09while (additional_reserve > 0) { !=20 ! =09=09=09struct sembuf bleh; !=20 ! =09=09=09bleh.sem_num =3D 0; ! =09=09=09bleh.sem_flg =3D IPC_NOWAIT; ! =09=09=09bleh.sem_op =3D -additional_reserve; ! =09=09=09if (semop(buflen_sem, &bleh, 1) =3D=3D 0) { // likely ! =09=09=09=09// Success! ! =09=09=09=09reserved +=3D additional_reserve; ! =09=09=09=09additional_reserve =3D 0; ! =09=09=09} else if (errno =3D=3D EAGAIN) { =09=09=09=09arts_debug("oggvorbis: buffer underrun"); !=20 ! =09=09=09=09// Check the number of samples available, this does not res= erve them! ! =09=09=09=09union semun foo; ! =09=09=09=09int samplesAvailable =3D semctl(buflen_sem, 0, GETVAL, foo)= ; !=20 ! =09=09=09=09// No samples! Why? Has decoder terminated? ! =09=09=09=09if (samplesAvailable =3D=3D 0) { ! =09=09=09=09=09halt_on_decoderTerminated(); =09=09=09=09} +=20 + =09=09=09=09additional_reserve =3D samplesAvailable; =09=09=09} else { ! =09=09=09=09// something awful/unexpected has happened =09=09=09=09halt(); ! =09=09=09=09additional_reserve =3D 0; =09=09=09} =09=09} =20 ! =09=09//////////////////////// ! =09=09// use from reserved ! =09=09// ! =09=09int used =3D 0; ! =09=09while (samplesWritten < samples && used < reserved) { !=20 ! =09=09 left[samplesWritten] =3D shm_buf->left[buf_pos]; ! =09=09 right[samplesWritten] =3D shm_buf->right[buf_pos]; ! =09=09 samplesWritten++; !=20 ! =09=09 fract_bufpos +=3D shm_buf->rate; !=20 ! =09=09 if (fract_bufpos >=3D samplingRate) { ! =09=09=09fract_bufpos -=3D samplingRate; ! =09=09=09buf_pos =3D ((buf_pos + 1) % BACKBUFSIZ); ! =09=09=09used++; ! =09=09 } =09=09} =20 ! =09=09/////////////////////////////////////////////////////// ! =09=09// finalize, avoid semop with sem_op=3D=3D0 =3D> will sleep ! =09=09// ! =09=09reserved -=3D used; ! =09=09artsdebug("reserved=3D%d, used=3D%d\n", reserved, used); !=20 ! =09=09if (used > 0) { ! =09=09=09struct sembuf freesem; ! =09=09=09freesem.sem_num =3D 1; ! =09=09=09freesem.sem_op =3D +used; ! =09=09=09semop(buflen_sem, &freesem, 1); // mark the now-free space ! =09=09} =09} +=20 + =09//////////////////////////////////////////////////////////// =09// zero out any samples we didn't have enough to complete ! =09// ! =09while(samplesWritten < samples) { ! =09=09left[samplesWritten] =3D 0.0; ! =09=09right[samplesWritten] =3D 0.0; ! =09=09samplesWritten++; =09} } =20 *************** *** 310,312 **** --- 382,390 ---- } =20 REGISTER_IMPLEMENTATION(oggPlayObject_impl); +=20 +=20 +=20 +=20 +=20 +=20 Index: oggPlayObject_impl.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/kde/kdemultimedia/oggvorbis_artsplugin/oggPlayObject_impl= =2Eh,v retrieving revision 1.2 diff -c -r1.2 oggPlayObject_impl.h *** oggPlayObject_impl.h=092001/12/14 20:54:43=091.2 --- oggPlayObject_impl.h=092002/01/29 22:02:00 *************** *** 50,60 **** --- 50,75 ---- =09struct buf_t{ =09=09float left[BACKBUFSIZ]; =09=09float right[BACKBUFSIZ]; + =09 int rate; =09} *shm_buf; =09int shm_id, child_pid; =09int buflen_sem; +=20 + private: + =09int reserved; // reserved, but unused input (shm_buf) + =09int fract_bufpos; // per samplingRate, initialized to 0 +=20 + =09void halt_on_decoderTerminated(); }; =20 }; =20 #endif +=20 +=20 +=20 +=20 +=20 +=20 +=20 +=20 --------------Boundary-00=_RC2QVUOBMEA14N0LWUWB-- _______________________________________________ kde-multimedia mailing list kde-multimedia@mail.kde.org http://mail.kde.org/mailman/listinfo/kde-multimedia