//--------------------------------------------------------------------------- /* MaSzyna EU07 locomotive simulator Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others */ #include "system.hpp" #include "classes.hpp" #pragma hdrstop #include "math.h" #include "RealSound.h" #include "Globals.h" #include "Timer.h" #include "Logs.h" #include "McZapkie\mctools.hpp" __fastcall TRealSound::TRealSound() { pSound=NULL; dSoundAtt=-1; AM=0.0; AA=0.0; FM=0.0; FA=0.0; vSoundPosition.x=0; vSoundPosition.y=0; vSoundPosition.z=0; fDistance=fPreviousDistance=0.0; fFrequency=22050.0; //częstotliwość samplowania pliku iDoppler=0; //normlanie jest załączony; !=0 - modyfikacje bLoopPlay=false; //dźwięk wyłączony } __fastcall TRealSound::~TRealSound() { //if (this) if (pSound) pSound->Stop(); } void __fastcall TRealSound::Free() { } void __fastcall TRealSound::Init(char *SoundName, double DistanceAttenuation, double X, double Y, double Z,bool Dynamic,bool freqmod,double rmin) { //Nazwa=SoundName; //to tak raczej nie zadziała, (SoundName) jest tymczasowe pSound=TSoundsManager::GetFromName(SoundName,Dynamic,&fFrequency); if (pSound) { if (freqmod) if (fFrequency!=22050.0) {//dla modulowanych nie może być zmiany mnożnika, bo częstotliwość w nagłówku byłą ignorowana, a mogła być inna niż 22050 fFrequency=22050.0; ErrorLog("Bad sound: "+AnsiString(SoundName)+", as modulated, should have 22.05kHz in header"); } AM=1.0; pSound->SetVolume(DSBVOLUME_MIN); } else {//nie ma dźwięku, to jest wysyp AM=0; ErrorLog("Missed sound: "+AnsiString(SoundName)); } if (DistanceAttenuation>0.0) { dSoundAtt=DistanceAttenuation*DistanceAttenuation; vSoundPosition.x=X; vSoundPosition.y=Y; vSoundPosition.z=Z; if (rmin<0) iDoppler=1; //wyłączenie efektu Dopplera, np. dla dźwięku ptaków } else dSoundAtt=-1; }; double __fastcall TRealSound::ListenerDistance(vector3 ListenerPosition) { if (dSoundAtt==-1) { return 0.0; } else { return SquareMagnitude(ListenerPosition-vSoundPosition); } } void __fastcall TRealSound::Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition) { if (!pSound) return; long int vol; double dS; // double Distance; DWORD stat; if ((Global::bSoundEnabled)&&(AM!=0)) { if (Volume>1.0) Volume=1.0; fPreviousDistance=fDistance; fDistance=0.0; //?? if (dSoundAtt>0.0) { vSoundPosition=NewPosition; dS=dSoundAtt; //*dSoundAtt; //bo odleglosc podawana w kwadracie fDistance=ListenerDistance(Global::pCameraPosition); if (ListenerInside) //osłabianie dźwięków z odległością Volume=Volume*dS/(dS+fDistance); else Volume=Volume*dS/(dS+2*fDistance); //podwójne dla ListenerInside=false } if (iDoppler) // {//Ra 2014-07: efekt Dopplera nie zawsze jest wskazany //if (FreeFlyModeFlag) //gdy swobodne latanie - nie sprawdza się to fPreviousDistance=fDistance; //to efektu Dopplera nie będzie } if (Looping) //dźwięk zapętlony można wyłączyć i zostanie włączony w miarę potrzeby bLoopPlay=true; //dźwięk wyłączony //McZapkie-010302 - babranie tylko z niezbyt odleglymi dźwiękami if ((dSoundAtt==-1)||(fDistance<20.0*dS)) { // vol=2*Volume+1; // if (vol<1) vol=1; // vol=10000*(log(vol)-1); // vol=10000*(vol-1); //int glos=1; //Volume=Volume*glos; //Ra: whatta hella is this if (Volume<0.0) Volume=0.0; vol=-5000.0+5000.0*Volume; if (vol>=0) vol=-1; if (Timer::GetSoundTimer()||!Looping) //Ra: po co to jest? pSound->SetVolume(vol); //Attenuation, in hundredths of a decibel (dB). pSound->GetStatus(&stat); if (!(stat&DSBSTATUS_PLAYING)) pSound->Play(0,0,Looping); } else //wylacz dzwiek bo daleko {//Ra 2014-09: oddalanie się nie może być powodem do wyłączenie dźwięku /* // Ra: stara wersja, ale podobno lepsza pSound->GetStatus(&stat); if (bLoopPlay) //jeśli zapętlony, to zostanie ponownie włączony, o ile znajdzie się bliżej if (stat&DSBSTATUS_PLAYING) pSound->Stop(); // Ra: wyłączyłem, bo podobno jest gorzej niż wcześniej //ZiomalCl: dźwięk po wyłączeniu sam się nie włączy, gdy wrócimy w rejon odtwarzania pSound->SetVolume(DSBVOLUME_MIN); //dlatego lepiej go wyciszyć na czas oddalenia się pSound->GetStatus(&stat); if (!(stat&DSBSTATUS_PLAYING)) pSound->Play(0,0,Looping); //ZiomalCl: włączenie odtwarzania rownież i tu, gdyż jesli uruchamiamy dźwięk poza promieniem, nie uruchomi się on w ogóle */ } } }; void __fastcall TRealSound::Start() {//włączenie dźwięku }; void __fastcall TRealSound::Stop() { DWORD stat; if (pSound) if ((Global::bSoundEnabled)&&(AM!=0)) { bLoopPlay=false; //dźwięk wyłączony pSound->GetStatus(&stat); if (stat&DSBSTATUS_PLAYING) pSound->Stop(); } }; void __fastcall TRealSound::AdjFreq(double Freq, double dt) //McZapkie TODO: dorobic tu efekt Dopplera //Freq moze byc liczba dodatnia mniejsza od 1 lub wieksza od 1 { float df, Vlist, Vsrc; if ((Global::bSoundEnabled) && (AM!=0)) { if (dt>0) //efekt Dopplera { Vlist=(sqrt(fPreviousDistance)-sqrt(fDistance))/dt; df= Freq*(1+Vlist/299.8); } else df=Freq; if (Timer::GetSoundTimer()) { df=fFrequency*df; //TODO - brac czestotliwosc probkowania z wav pSound->SetFrequency(( dfDSBFREQUENCY_MAX ? DSBFREQUENCY_MAX : df) ) ); } } } double TRealSound::GetWaveTime() //McZapkie: na razie tylko dla 22KHz/8bps {//używana do pomiaru czasu dla dźwięków z początkiem i końcem if (!pSound) return 0.0; double WaveTime; DSBCAPS caps; caps.dwSize=sizeof(caps); pSound->GetCaps(&caps); WaveTime=caps.dwBufferBytes; return WaveTime/fFrequency; //(pSound->); // wielkosc w bajtach przez czestotliwosc probkowania } void __fastcall TRealSound::SetPan(int Pan) { pSound->SetPan(Pan); } int TRealSound::GetStatus() { DWORD stat; if ((Global::bSoundEnabled) && (AM!=0)) { pSound->GetStatus(&stat); return stat; } else return 0; } void __fastcall TRealSound::ResetPosition() { if (pSound) //Ra: znowu jakiś badziew! pSound->SetCurrentPosition(0); } void __fastcall TTextSound::Init(char *SoundName,double SoundAttenuation,double X,double Y,double Z,bool Dynamic,bool freqmod,double rmin) {//dodatkowo doczytuje plik tekstowy TRealSound::Init(SoundName,SoundAttenuation,X,Y,Z,Dynamic,freqmod,rmin); fTime=GetWaveTime(); AnsiString txt=AnsiString(SoundName); txt.Delete(txt.Length()-3,4); //obcięcie rozszerzenia for (int i=txt.Length();i>0;--i) if (txt[i]=='/') txt[i]='\\'; //bo nie rozumi txt+="-"+Global::asLang+".txt"; //już może być w różnych językach if (!FileExists(txt)) txt="sounds\\"+txt; //ścieżka może nie być podana if (FileExists(txt)) {//wczytanie TFileStream *ts=new TFileStream(txt,fmOpenRead); asText=AnsiString::StringOfChar(' ',ts->Size); ts->Read(asText.c_str(),ts->Size); delete ts; } }; void __fastcall TTextSound::Play(double Volume,int Looping,bool ListenerInside,vector3 NewPosition) { if (!asText.IsEmpty()) {//jeśli ma powiązany tekst DWORD stat; pSound->GetStatus(&stat); if (!(stat&DSBSTATUS_PLAYING)) //jeśli nie jest aktualnie odgrywany { int i; AnsiString t=asText; do {//na razie zrobione jakkolwiek, docelowo przenieść teksty do tablicy nazw i=t.Pos("\r"); //znak nowej linii if (!i) Global::tranTexts.Add(t.c_str(),fTime,true); else { Global::tranTexts.Add(t.SubString(1,i-1).c_str(),fTime,true); t.Delete(1,i); while (t.IsEmpty()?false:(unsigned char)(t[1])<33) t.Delete(1,1); } } while (i>0); } } TRealSound::Play(Volume,Looping,ListenerInside,NewPosition); }; //--------------------------------------------------------------------------- #pragma package(smart_init)