/fmplayer.cpp
C++ | 655 lines | 499 code | 121 blank | 35 comment | 107 complexity | 4b7c19ed03ca7c63b457bbce117d43f0 MD5 | raw file
- /**************************************************************************
- 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);
- }