Logo Search packages:      
Sourcecode: qliss3d version File versions  Download package

fmplayer.cpp

/**************************************************************************
                    fmplayer.cpp  -  all the FMPlayer-API
                            -------------------
    begin                : September 20th 2002
    copyright            : (C) 2002-2003 by Daniel Gruen
    email                : daniel_gruen@web.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

// this is a slim and special fms version for qliss3d
// please use the original version from http://sourceforge.net/projects/fmsynth
// if you want to do anything on it

#include "include/fmplayer.h"
#include <cmath>

#ifdef FMS_WORKS 

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>

#include "include/fmval.h"
#include "include/version.h"

using namespace std;

int dspfd = 0;

void writeSoundByte(unsigned char * byte, PlayMode mode) {
       ssize_t r;

       //cout << int(byte) << endl;
       if(mode == DSP)
         r = write(dspfd, byte, 1);
       if(mode != DSP)
               return;
       while ((r = write(dspfd, byte, 1)) < 1) {
               if (r == -1)
                       return;
       }

}

/*----------------------------------------------------------------*/


FMPlayer::FMPlayer() {
      if(debug_level>1)
            cout << "FMPlayer::FMPlayer called" << endl;
      first   = new FMChannel(this);
      channel = first;
      syncPointer();
      rate    = D_SAMPRATE;
      mode    = DSP;
}

FMPlayer::~FMPlayer() {
      if(debug_level>1)
            cout << "FMPlayer::~FMPlayer called" << endl;
      delete first;
      if(debug_level>1)
            cout << "FMPlayer::~FMPlayer finished" << endl;
}

void FMPlayer::nextSound() {
      if(debug_level>1)
            cout << "FMPlayer::nextSound called" << endl;
      channel->nextSound();
      syncPointer();
}

void FMPlayer::setRate(int drate) {
      if(debug_level>1)
            cout << "FMPlayer::setRate called" << endl;
      rate = drate;
}

int  FMPlayer::getRate() const {
      return rate;
}

void FMPlayer::openFiles() {
      if(debug_level>1)
            cout << "FMPlayer::openFiles called" << endl;
 try{
      first->openFiles();
 }
 catch(...){
      cout <<  "caught error in FMPlayer::openFiles" << endl;
  throw;
 }
}

void FMPlayer::compute() {
      if(debug_level>1)
            cout << "FMPlayer::compute called" << endl;
      first->compute();
}

void FMPlayer::syncPointer() {
      if(debug_level>1)
            cout << "FMPlayer::syncPointer called" << endl;
      package = channel->package;
      sound   = channel->sound;
}

void FMPlayer::play() {
 try{
      if(debug_level>1)
            cout << "FMPlayer::play called" << endl;
      openFiles();
      compute();
  playInit();
  while(first->ptr)
    playVal();
  playCleanup();
 }
 catch(int x){
      if(x>0) // wenn's eine Fehlermeldung ist
        throw;
 }
}

void FMPlayer::playInit() {
      if(debug_level>1)
            cout << "FMPlayer::playInit called" << endl;

      int format = AFMT_U8;
      int chan = 0;

      first->pointerReset();

 try{

      if(mode == DSP && !dspfd){

            if(debug_level>1)
                  cout << "going to open and initialize /dev/dsp" << endl;

            if((dspfd = open("/dev/dsp", O_WRONLY)) == -1) {
                  mode = NONE;
                  dspfd = 0;
                  if(debug_level)
                        cout << "error opening /dev/dsp: reset PlayMode and dsp-fd" << endl;
                  throw DSP_OPEN_ERR;
                  return;
            }

            if(ioctl(dspfd, SNDCTL_DSP_STEREO, &chan) == -1) {
                  mode = NONE;
                  throw DSP_CHAN_ERR;
                  return;
            }

            if(ioctl(dspfd, SNDCTL_DSP_SETFMT, &format) == -1) {
                  mode = NONE;
                  throw DSP_SFMT_ERR;
                  return;
            }

            if(ioctl(dspfd, SNDCTL_DSP_SPEED, &rate) == -1) {
                  mode = NONE;
                  throw DSP_RATE_ERR;
                  return;
            }
            
            if(debug_level)
                  cout << "opened /dev/dsp successfully!" << endl;

      }

      else if(mode == NONE){
                  return;
      }
      
      else{
            if(debug_level)
                  cout << "PlayMode " << mode << " not implemented!" << endl;
            throw PLY_MODE_ERR;
            return;
      }
 }

  catch(...){
      throw;
  }
      
      if(debug_level>1)
            cout << "FMPlayer::playInit finished" << endl;
}

void FMPlayer::playVal(){

      unsigned char buff[1];

      buff[0] = int(*first->ptr);
      writeSoundByte(buff, mode);
      first->ptrInc();

}

void FMPlayer::playCleanup() {
      if(debug_level>1)
            cout << "FMPlayer::playCleanup called" << endl;

      if(mode == DSP){
    if(ioctl(dspfd, SNDCTL_DSP_SYNC) == -1) {
                  throw DSP_SYNC_ERR;
            }
            close(dspfd); dspfd = 0;
  }
}


/*----------------------------------------------------------------*/


FMChannel::FMChannel(FMPlayer *parentPlayer) {
      if(debug_level>1)
            cout << "FMChannel::FMChannel called" << endl;
      player  = parentPlayer;
      first   = new FMPackage(this);
      package = first;
      syncPointer();
      ptr     = 0;
      dr      = 0;
}

FMChannel::~FMChannel(){
      if(debug_level>1)
            cout << "FMChannel::~FMChannel called" << endl;
      delete first;
      if(debug_level>1)
            cout << "FMChannel::~FMChannel finished" << endl;
}

void  FMChannel::nextSound() {
      if(debug_level>1)
            cout << "FMChannel::nextSound called" << endl;
      package->nextSound();
      syncPointer();
}

void  FMChannel::openFiles() {
      if(debug_level>1)
            cout << "FMChannel::openFiles called" << endl;
 try{
      first->openFiles();
 }
 catch(...){
      cout <<  "catch error in FMChannel::openFiles" << endl;
      throw;
 }
}

void  FMChannel::compute() {
      if(debug_level>1)
            cout << "FMChannel::compute called" << endl;
      package = first;
      while(package){
            package->compute();
            package = 0;
      }
      ptr = first->values;
      package = first;
      dr = 0;
}

void  FMChannel::syncPointer() {
      if(debug_level>1)
            cout << "FMChannel::syncPointer called" << endl;
 if(package)
      sound = package->sound;
      if(debug_level>1)
            cout << "FMChannel::syncPointer finished" << endl;
}

void  FMChannel::ptrInc() {
  if(ptr){
      ptr++;
      i++;
      if(ptr >= package->values + package->getRval()){
            ptr = package->values;
      }
      if(i   >= package->getTime() * player->getRate() * package->getRepeat()){
            // channel repeat problematisch!
            ptr = 0;
      }
      }
}

void  FMChannel::pointerReset() {
      if(debug_level>1)
            cout << "FMChannel::pointerReset called" << endl;
      package = first;
      ptr = package->values;
      i = 0;
      if(debug_level>1)
            cout << "FMChannel::pointerReset finished" << endl;
}


/*----------------------------------------------------------------*/


FMPackage::FMPackage(FMChannel *parentChannel){
      if(debug_level>1)
            cout << "FMPackage::FMPackage called" << endl;
      channel = parentChannel;


      tvol   = 0.0; // have to do this before FMSoundfile::FMSoundfile(this)
      sound  = new FMSoundfile(this);
      first  = sound;
      time   = 1.0;
      vol    = 1.0;
      repeat = 1.0;
      rval   = 0;
      values = 0;
      comp_lock=0;
}

FMPackage::~FMPackage() {
      if(debug_level>1)
            cout << "FMPackage::~FMPackage called" << endl;
      delete first;
      if(values)
            delete []values;
      if(debug_level>1)
            cout << "FMPackage::~FMPackage finished" << endl;
}

void FMPackage::nextSound() {
      if(debug_level>1)
            cout << "FMPackage::nextSound called" << endl;
      if(!sound->next){
            sound->next = new FMSoundfile(this);
            comp_lock=0;
      }
      sound = sound->next;
}

float FMPackage::getTime() const {
      return time;
}

void  FMPackage::setTime(float dtime) {
      if(debug_level>1)
            cout << "FMPackage::setTime called" << endl;
      time = dtime; compLockAll();
}

float FMPackage::getVolume() const {
      if(debug_level>1)
            cout << "FMPackage::getVolume called" << endl;
      return vol;
}

void  FMPackage::setVolume(float dvol) {
      if(debug_level>1)
            cout << "FMPackage::setVolume called" << endl;
      vol = dvol; comp_lock=0;
}

int   FMPackage::getRval() const {
      return rval;
}

float FMPackage::getRepeat() const {
      return repeat;
}

void FMPackage::setTVol(float dtvol) {
      if(debug_level>1)
            cout << "FMPackage::setTVol called" << endl;
      tvol = dtvol;
}

float FMPackage::getTVol() const {
      return tvol;
}

void  FMPackage::setRepeat(float drepeat) {
      if(debug_level>1)
            cout << "FMPackage::setRepeat called" << endl;
      repeat = drepeat;
}

void  FMPackage::volumeChanged(float oldv, float newv){
      if(debug_level>1)
            cout << "FMPackage::volumeChanged called" << endl << "Volume changed: " << tvol << " - ";
      tvol += newv - oldv;
      if(debug_level>1)
            cout << tvol << endl;
      comp_lock=0;
}

void  FMPackage::openFiles() {
      if(debug_level>1)
            cout << "FMPackage::openFiles called" << endl;
      try{
            FMSoundfile * tmpsound = first;
            while(tmpsound){
                  if(!tmpsound->openLock())
                        tmpsound->openFile();
                  tmpsound = tmpsound->next;
                  if(debug_level>1)
                        cout << "opening of one file finished" << endl;
            }
            if(debug_level)
                  cout << "opening of all files in package finished" << endl;
      }
      catch(...){
            cout <<  "caught error in FMPackage::openFiles" << endl;
            throw;
      }
}

void  FMPackage::compute() {
      if(debug_level>1)
            cout << "FMPackage::compute called" << endl;
      if(comp_lock){
            FMSoundfile * tmp = first;
            bool ac = 1;
            while(tmp){
                  ac = ac * tmp->compLock();
                  tmp = tmp->next;
            }
            if(ac){
                  if(debug_level)
                        cout << "already computed" << endl;
                  return;
            }
      }

      if(values){
            if(debug_level)
                  cout << "recomputing package" << endl;
            delete []values;
      }

      // first, how many values do we need?
      rval = 1;
      //int numsounds = 0;
      FMSoundfile *tmpsound = first;
      while(tmpsound){
            //numsounds++;
            tmpsound->compute();
            tmpsound->setAtime(0.0);
            //tmpsound->setVolume(tmpsound->getVolume() / tvol, 0); 
            // don't set total volume, that's the reason for 0
            rval = int(kgv(rval, tmpsound->rval()));
            tmpsound = tmpsound->next;
      }

      if(rval > channel->player->getRate() * time || rval < 0)
            rval = int(channel->player->getRate() * time);

      // ok, so we'll make a new value array
      if(debug_level>1)
            cout << rval << " values will be computed in package" << endl;
      values = new float[rval];
      ptr = values;
      if(debug_level>1)
            cout << "values starting @ " << ptr << endl;

      // and now, we'll actually compute the values


      while(ptr < values+rval){
            *ptr = 0.0;
            tmpsound = first;
            while(tmpsound){
                  *ptr = *ptr + tmpsound->value();
                  //if(tmpsound->ffreq)
                  //    tmpsound->setFreq(tmpsound->ffreq->HFValue());
                  tmpsound = tmpsound->next;
            }
            ptr++;
      }
      comp_lock=1;
      if(debug_level>1)
            cout << "FMPackage::compute finished after computing" << endl;
}

void FMPackage::compLockAll(){
}

/*----------------------------------------------------------------*/


FMFile::FMFile(FMPackage *parentPackage){
      if(debug_level>1)
            cout << "FMFile::FMFile called" << endl;
      package  = parentPackage;
      freq     = 1;
      atime    = 0.0;
      open_lock = 0;
      volume   = 1.0;
}

FMFile::~FMFile(){
}

bool FMFile::openLock(){
      if(debug_level>1)
            cout << "FMFile::openLock called" << endl;
      return open_lock;
}

bool FMFile::compLock(){
      if(debug_level>1)
            cout << "FMFile::compLock called" << endl;
      return 1;
}

void FMFile::compute(){
      if(debug_level>1)
            cout << "FMFile::compute called" << endl;
}

void   FMFile::setFreq(float dfreq) {
      freq = dfreq;
      package->compLockAll();
}

void  FMFile::setVolume(float dvolume, bool setptvol){
      if(debug_level>1)
            cout << "FMFile::setVolume called" << endl;
      if(setptvol){
            if(debug_level>1)
                  cout << "changing total volume (" << volume << ", " << dvolume << ")" << endl;
            package->volumeChanged(volume, dvolume);
      }
      volume=dvolume;
      package->compLockAll();
}

float FMFile::getVolume() const {
      if(debug_level>1)
            cout << "FMFile::getVolume called" << endl;
      return volume;
}

void   FMFile::setAtime(float datime) {
      if(debug_level>1)
            cout << "FMFile::setAtime called" << endl;
      atime = datime; /*should there be a comp_lock=0 here?*/
}

void   FMFile::incAtime() {
        atime = fmod((atime + vtl[getVlen()-1].getTime() * freq / package->channel->player->getRate()),
            vtl[getVlen()-1].getTime());
}

void   FMFile::openFile() {
  if(debug_level)
       cout << "FMFile::openFile called" << endl;
      try{
            init();
      }
      catch(...){
            throw;
            open_lock=0;
      }
}

float  FMFile::value(bool count_on){

      float avalue = fmval(this, atime);

      if(count_on)
            incAtime();

      return avalue;
}

int FMFile::rval(){
 if(debug_level>1)
      cout << "FMFile::rval called" << endl;
 int drval = 1;
 drval = int(kgv(drval,package->channel->player->getRate() / freq));
 if(drval < 0.0 || drval > package->channel->player->getRate() * package->getTime())
 drval = int(package->channel->player->getRate() * package->getTime());
 return drval;
}


/*----------------------------------------------------------------*/


FMSoundfile::FMSoundfile(FMPackage *parentPackage) : FMFile(parentPackage){
      if(debug_level>1)
            cout << "FMSoundfile::FMSoundfile called" << endl;
      next    = 0;
      freq    = 441.0;
      package->volumeChanged(0.0, 1.0);
}

FMSoundfile::~FMSoundfile(){
      if(debug_level>1)
            cout << "FMSoundfile::~FMSoundfile called" << endl;
      if(next)
            delete next;
      if(debug_level>1)
            cout << "FMSoundfile::~FMSoundfile finished" << endl;
}

float FMSoundfile::value(bool count_on){
      return FMFile::value(count_on) * (volume/package->getTVol());
}


/*----------------------------------------------------------------*/

#endif

float   ggt(float a, float b) {

      if(a < 0)
            a = a * -1;

      if(b < 0)
            b = b * -1;

      if(b>a)
            return ggt(b, a);

      if(b!=0)
            return ggt(b, fmod(a, b));

      else
            return a;
}

float   kgv(float a, float b) {

      return a*b/ggt(a, b);

}



Generated by  Doxygen 1.6.0   Back to index