mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
sound works
sound works 2 sound works 3 sound works sound works sound works sound works sound works sound fixes fix
This commit is contained in:
181
AdvSound.cpp
181
AdvSound.cpp
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "AdvSound.h"
|
||||
#include "Timer.h"
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
TAdvancedSound::~TAdvancedSound()
|
||||
{ // Ra: stopowanie się sypie
|
||||
// SoundStart.Stop();
|
||||
// SoundCommencing.Stop();
|
||||
// SoundShut.Stop();
|
||||
}
|
||||
|
||||
void TAdvancedSound::Free()
|
||||
{
|
||||
}
|
||||
|
||||
void TAdvancedSound::Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation,
|
||||
vector3 const &pPosition)
|
||||
{
|
||||
SoundStart.Init(NameOn, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true);
|
||||
SoundCommencing.Init(Name, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true);
|
||||
SoundShut.Init(NameOff, DistanceAttenuation, pPosition.x, pPosition.y, pPosition.z, true);
|
||||
fStartLength = SoundStart.GetWaveTime();
|
||||
fShutLength = SoundShut.GetWaveTime();
|
||||
SoundStart.AM = 1.0;
|
||||
SoundStart.AA = 0.0;
|
||||
SoundStart.FM = 1.0;
|
||||
SoundStart.FA = 0.0;
|
||||
SoundCommencing.AM = 1.0;
|
||||
SoundCommencing.AA = 0.0;
|
||||
SoundCommencing.FM = 1.0;
|
||||
SoundCommencing.FA = 0.0;
|
||||
defAM = 1.0;
|
||||
defFM = 1.0;
|
||||
SoundShut.AM = 1.0;
|
||||
SoundShut.AA = 0.0;
|
||||
SoundShut.FM = 1.0;
|
||||
SoundShut.FA = 0.0;
|
||||
}
|
||||
|
||||
void TAdvancedSound::Load(cParser &Parser, vector3 const &pPosition)
|
||||
{
|
||||
std::string nameon, name, nameoff;
|
||||
double attenuation;
|
||||
Parser.getTokens( 3, true, "\n\t ;," ); // samples separated with commas
|
||||
Parser
|
||||
>> nameon
|
||||
>> name
|
||||
>> nameoff;
|
||||
Parser.getTokens( 1, false );
|
||||
Parser
|
||||
>> attenuation;
|
||||
Init( nameon, name, nameoff, attenuation, pPosition );
|
||||
}
|
||||
|
||||
void TAdvancedSound::TurnOn(bool ListenerInside, vector3 NewPosition)
|
||||
{
|
||||
// hunter-311211: nie trzeba czekac na ponowne odtworzenie dzwieku, az sie wylaczy
|
||||
if ((State == ss_Off || State == ss_ShuttingDown) && (SoundStart.AM > 0))
|
||||
{
|
||||
SoundStart.ResetPosition();
|
||||
SoundCommencing.ResetPosition();
|
||||
SoundStart.Play(1, 0, ListenerInside, NewPosition);
|
||||
// SoundStart->SetVolume(-10000);
|
||||
State = ss_Starting;
|
||||
fTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TAdvancedSound::TurnOff(bool ListenerInside, vector3 NewPosition)
|
||||
{
|
||||
if ((State == ss_Commencing || State == ss_Starting) && (SoundShut.AM > 0))
|
||||
{
|
||||
SoundStart.Stop();
|
||||
SoundCommencing.Stop();
|
||||
SoundShut.ResetPosition();
|
||||
SoundShut.Play(1, 0, ListenerInside, NewPosition);
|
||||
State = ss_ShuttingDown;
|
||||
fTime = fShutLength;
|
||||
// SoundShut->SetVolume(0);
|
||||
}
|
||||
}
|
||||
|
||||
void TAdvancedSound::Update(bool ListenerInside, vector3 NewPosition)
|
||||
{
|
||||
if ((State == ss_Commencing) && (SoundCommencing.AM > 0))
|
||||
{
|
||||
// SoundCommencing->SetFrequency();
|
||||
SoundShut.Stop(); // hunter-311211
|
||||
SoundCommencing.Play(1, DSBPLAY_LOOPING, ListenerInside, NewPosition);
|
||||
}
|
||||
else if (State == ss_Starting)
|
||||
{
|
||||
fTime += Timer::GetDeltaTime();
|
||||
// SoundStart->SetVolume(-1000*(4-fTime)/4);
|
||||
if (fTime >= fStartLength)
|
||||
{
|
||||
State = ss_Commencing;
|
||||
SoundCommencing.ResetPosition();
|
||||
SoundCommencing.Play(1, DSBPLAY_LOOPING, ListenerInside, NewPosition);
|
||||
SoundStart.Stop();
|
||||
}
|
||||
else
|
||||
SoundStart.Play(1, 0, ListenerInside, NewPosition);
|
||||
}
|
||||
else if (State == ss_ShuttingDown)
|
||||
{
|
||||
fTime -= Timer::GetDeltaTime();
|
||||
// SoundShut->SetVolume(-1000*(4-fTime)/4);
|
||||
if (fTime <= 0)
|
||||
{
|
||||
State = ss_Off;
|
||||
SoundShut.Stop();
|
||||
}
|
||||
else
|
||||
SoundShut.Play(1, 0, ListenerInside, NewPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void TAdvancedSound::UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition)
|
||||
{ // update, ale z amplituda i czestotliwoscia
|
||||
if( State == ss_Off ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((State == ss_Commencing) && (SoundCommencing.AM > 0))
|
||||
{
|
||||
SoundShut.Stop(); // hunter-311211
|
||||
SoundCommencing.Play(A, DSBPLAY_LOOPING, ListenerInside, NewPosition);
|
||||
}
|
||||
else if (State == ss_Starting)
|
||||
{
|
||||
fTime += Timer::GetDeltaTime();
|
||||
// SoundStart->SetVolume(-1000*(4-fTime)/4);
|
||||
if (fTime >= fStartLength)
|
||||
{
|
||||
State = ss_Commencing;
|
||||
SoundCommencing.ResetPosition();
|
||||
SoundCommencing.Play(A, DSBPLAY_LOOPING, ListenerInside, NewPosition);
|
||||
SoundStart.Stop();
|
||||
}
|
||||
else
|
||||
SoundStart.Play(A, 0, ListenerInside, NewPosition);
|
||||
}
|
||||
else if (State == ss_ShuttingDown)
|
||||
{
|
||||
fTime -= Timer::GetDeltaTime();
|
||||
// SoundShut->SetVolume(-1000*(4-fTime)/4);
|
||||
if (fTime <= 0)
|
||||
{
|
||||
State = ss_Off;
|
||||
SoundShut.Stop();
|
||||
}
|
||||
else
|
||||
SoundShut.Play(A, 0, ListenerInside, NewPosition);
|
||||
}
|
||||
SoundCommencing.AdjFreq(F, Timer::GetDeltaTime());
|
||||
}
|
||||
|
||||
void TAdvancedSound::CopyIfEmpty(TAdvancedSound &s)
|
||||
{ // skopiowanie, gdyby był potrzebny, a nie został wczytany
|
||||
if ((fStartLength > 0.0) || (fShutLength > 0.0))
|
||||
return; // coś jest
|
||||
SoundStart = s.SoundStart;
|
||||
SoundCommencing = s.SoundCommencing;
|
||||
SoundShut = s.SoundShut;
|
||||
State = s.State;
|
||||
fStartLength = s.fStartLength;
|
||||
fShutLength = s.fShutLength;
|
||||
defAM = s.defAM;
|
||||
defFM = s.defFM;
|
||||
};
|
||||
50
AdvSound.h
50
AdvSound.h
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef AdvSoundH
|
||||
#define AdvSoundH
|
||||
|
||||
#include "RealSound.h"
|
||||
#include "parser.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ss_Off,
|
||||
ss_Starting,
|
||||
ss_Commencing,
|
||||
ss_ShuttingDown
|
||||
} TSoundState;
|
||||
|
||||
class TAdvancedSound
|
||||
{ // klasa dźwięków mających początek, dowolnie długi środek oraz zakończenie (np. Rp1)
|
||||
TRealSound SoundStart;
|
||||
TRealSound SoundCommencing;
|
||||
TRealSound SoundShut;
|
||||
TSoundState State = ss_Off;
|
||||
double fTime = 0.0;
|
||||
double fStartLength = 0.0;
|
||||
double fShutLength = 0.0;
|
||||
double defAM = 0.0;
|
||||
double defFM = 0.0;
|
||||
|
||||
public:
|
||||
TAdvancedSound() = default;
|
||||
~TAdvancedSound();
|
||||
void Init( std::string const &NameOn, std::string const &Name, std::string const &NameOff, double DistanceAttenuation, vector3 const &pPosition);
|
||||
void Load(cParser &Parser, vector3 const &pPosition);
|
||||
void TurnOn(bool ListenerInside, vector3 NewPosition);
|
||||
void TurnOff(bool ListenerInside, vector3 NewPosition);
|
||||
void Free();
|
||||
void Update(bool ListenerInside, vector3 NewPosition);
|
||||
void UpdateAF(double A, double F, bool ListenerInside, vector3 NewPosition);
|
||||
void CopyIfEmpty(TAdvancedSound &s);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
@@ -16,7 +16,6 @@ set(SOURCES
|
||||
"TrkFoll.cpp"
|
||||
"VBO.cpp"
|
||||
"World.cpp"
|
||||
"AdvSound.cpp"
|
||||
"AirCoupler.cpp"
|
||||
"AnimModel.cpp"
|
||||
"Button.cpp"
|
||||
@@ -27,7 +26,6 @@ set(SOURCES
|
||||
"EU07.cpp"
|
||||
"Event.cpp"
|
||||
"EvLaunch.cpp"
|
||||
"FadeSound.cpp"
|
||||
"Float3d.cpp"
|
||||
"Gauge.cpp"
|
||||
"Globals.cpp"
|
||||
@@ -45,7 +43,6 @@ set(SOURCES
|
||||
"parser.cpp"
|
||||
"renderer.cpp"
|
||||
"PyInt.cpp"
|
||||
"RealSound.cpp"
|
||||
"ResourceManager.cpp"
|
||||
"sn_utils.cpp"
|
||||
"Segment.cpp"
|
||||
@@ -54,7 +51,7 @@ set(SOURCES
|
||||
"stars.cpp"
|
||||
"lightarray.cpp"
|
||||
"skydome.cpp"
|
||||
"Sound.cpp"
|
||||
"sound.cpp"
|
||||
"Spring.cpp"
|
||||
"shader.cpp"
|
||||
"frustum.cpp"
|
||||
@@ -116,4 +113,13 @@ target_link_libraries(${PROJECT_NAME} Threads::Threads)
|
||||
find_package(GLM REQUIRED)
|
||||
include_directories(${GLM_INCLUDE_DIRS})
|
||||
|
||||
#set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=undefined -g")
|
||||
find_package(OpenAL REQUIRED)
|
||||
include_directories(${OPENAL_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} ${OPENAL_LIBRARY})
|
||||
|
||||
find_package(libsndfile REQUIRED)
|
||||
include_directories(${LIBSNDFILE_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} ${LIBSNDFILE_LIBRARY})
|
||||
|
||||
#set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -g")
|
||||
|
||||
34
CMake_modules/Findlibsndfile.cmake
Normal file
34
CMake_modules/Findlibsndfile.cmake
Normal file
@@ -0,0 +1,34 @@
|
||||
# - Try to find libsndfile
|
||||
# Once done, this will define
|
||||
#
|
||||
# LIBSNDFILE_FOUND - system has libsndfile
|
||||
# LIBSNDFILE_INCLUDE_DIRS - the libsndfile include directories
|
||||
# LIBSNDFILE_LIBRARIES - link these to use libsndfile
|
||||
|
||||
# Use pkg-config to get hints about paths
|
||||
find_package(PkgConfig QUIET)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(LIBSNDFILE_PKGCONF sndfile)
|
||||
endif(PKG_CONFIG_FOUND)
|
||||
|
||||
# Include dir
|
||||
find_path(LIBSNDFILE_INCLUDE_DIR
|
||||
NAMES sndfile.h
|
||||
PATHS ${LIBSNDFILE_PKGCONF_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
# Library
|
||||
find_library(LIBSNDFILE_LIBRARY
|
||||
NAMES sndfile libsndfile-1
|
||||
PATHS ${LIBSNDFILE_PKGCONF_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
find_package(PackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LibSndFile DEFAULT_MSG LIBSNDFILE_LIBRARY LIBSNDFILE_INCLUDE_DIR)
|
||||
|
||||
if(LIBSNDFILE_FOUND)
|
||||
set(LIBSNDFILE_LIBRARIES ${LIBSNDFILE_LIBRARY})
|
||||
set(LIBSNDFILE_INCLUDE_DIRS ${LIBSNDFILE_INCLUDE_DIR})
|
||||
endif(LIBSNDFILE_FOUND)
|
||||
|
||||
mark_as_advanced(LIBSNDFILE_LIBRARY LIBSNDFILE_LIBRARIES LIBSNDFILE_INCLUDE_DIR LIBSNDFILE_INCLUDE_DIRS)
|
||||
@@ -23,8 +23,8 @@ class TModel3d; //siatka modelu wspólna dla egzemplarzy
|
||||
class TSubModel; // fragment modelu (tu do wyświetlania terenu)
|
||||
class TMemCell; // komórka pamięci
|
||||
class cParser;
|
||||
class TRealSound; // dźwięk ze współrzędnymi XYZ
|
||||
class TTextSound; // dźwięk ze stenogramem
|
||||
class sound;
|
||||
class text_sound;
|
||||
class TEventLauncher;
|
||||
class TTraction; // drut
|
||||
class TTractionPowerSource; // zasilanie drutów
|
||||
|
||||
25
Driver.cpp
25
Driver.cpp
@@ -25,6 +25,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "World.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
#include "McZapkie/MOVER.h"
|
||||
#include "sound.h"
|
||||
|
||||
#define LOGVELOCITY 0
|
||||
#define LOGORDERS 1
|
||||
@@ -1467,7 +1468,7 @@ void TController::CloseLog()
|
||||
|
||||
TController::~TController()
|
||||
{ // wykopanie mechanika z roboty
|
||||
delete tsGuardSignal;
|
||||
sound_man->destroy_sound(&tsGuardSignal);
|
||||
delete TrainParams;
|
||||
CloseLog();
|
||||
};
|
||||
@@ -2380,7 +2381,7 @@ bool TController::DecBrake()
|
||||
bool TController::IncSpeed()
|
||||
{ // zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać
|
||||
if (tsGuardSignal) // jeśli jest dźwięk kierownika
|
||||
if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy
|
||||
if (tsGuardSignal->is_playing()) // jeśli gada, to nie jedziemy
|
||||
return false;
|
||||
bool OK = true;
|
||||
if( ( iDrivigFlags & moveDoorOpened )
|
||||
@@ -2864,9 +2865,8 @@ bool TController::PutCommand(std::string NewCommand, double NewValue1, double Ne
|
||||
NewCommand = Global::asCurrentSceneryPath + NewCommand + ".wav"; // na razie jeden
|
||||
if (FileExists(NewCommand))
|
||||
{ // wczytanie dźwięku odjazdu podawanego bezpośrenido
|
||||
tsGuardSignal = new TTextSound(NewCommand, 30, pVehicle->GetPosition().x,
|
||||
pVehicle->GetPosition().y, pVehicle->GetPosition().z,
|
||||
false);
|
||||
tsGuardSignal = sound_man->create_text_sound(NewCommand);
|
||||
tsGuardSignal->position(pVehicle->GetPosition());
|
||||
// rsGuardSignal->Stop();
|
||||
iGuardRadio = 0; // nie przez radio
|
||||
}
|
||||
@@ -2875,9 +2875,8 @@ bool TController::PutCommand(std::string NewCommand, double NewValue1, double Ne
|
||||
NewCommand = NewCommand.insert(NewCommand.find_last_of("."),"radio"); // wstawienie przed kropkč
|
||||
if (FileExists(NewCommand))
|
||||
{ // wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
|
||||
tsGuardSignal = new TTextSound(NewCommand, -1, pVehicle->GetPosition().x,
|
||||
pVehicle->GetPosition().y, pVehicle->GetPosition().z,
|
||||
false);
|
||||
tsGuardSignal = sound_man->create_text_sound(NewCommand);
|
||||
tsGuardSignal->position(pVehicle->GetPosition());
|
||||
iGuardRadio = iRadioChannel;
|
||||
}
|
||||
}
|
||||
@@ -4202,7 +4201,7 @@ bool TController::UpdateSituation(double dt)
|
||||
->DoorOpenCtrl ) // jeśli drzwi niesterowane przez maszynistę
|
||||
Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika
|
||||
|
||||
tsGuardSignal->Stop();
|
||||
tsGuardSignal->stop();
|
||||
// w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy
|
||||
// bezpośrednim
|
||||
// albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w
|
||||
@@ -4210,9 +4209,7 @@ bool TController::UpdateSituation(double dt)
|
||||
// na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić
|
||||
// obsługę kanałów radiowych itd.
|
||||
if (!iGuardRadio) // jeśli nie przez radio
|
||||
tsGuardSignal->Play(
|
||||
1.0, 0, !FreeFlyModeFlag,
|
||||
pVehicle->GetPosition()); // dla true jest głośniej
|
||||
tsGuardSignal->position(pVehicle->GetPosition()).play();
|
||||
else
|
||||
// if (iGuardRadio==iRadioChannel) //zgodność kanału
|
||||
// if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu
|
||||
@@ -4221,9 +4218,7 @@ bool TController::UpdateSituation(double dt)
|
||||
if (SquareMagnitude(pVehicle->GetPosition() -
|
||||
Global::pCameraPosition) <
|
||||
2000 * 2000) // w odległości mniejszej niż 2km
|
||||
tsGuardSignal->Play(
|
||||
1.0, 0, true,
|
||||
pVehicle->GetPosition()); // dźwięk niby przez radio
|
||||
tsGuardSignal->position(pVehicle->GetPosition()).play();
|
||||
}
|
||||
}
|
||||
if (mvOccupied->V == 0.0)
|
||||
|
||||
2
Driver.h
2
Driver.h
@@ -232,7 +232,7 @@ class TController
|
||||
// AnsiString OrderCommand; //komenda pobierana z pojazdu
|
||||
// double OrderValue; //argument komendy
|
||||
int iRadioChannel = 1; // numer aktualnego kanału radiowego
|
||||
TTextSound *tsGuardSignal = nullptr; // komunikat od kierownika
|
||||
sound *tsGuardSignal = nullptr; // komunikat od kierownika
|
||||
int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia)
|
||||
public:
|
||||
double AccPreferred = 0.0; // preferowane przyspieszenie (wg psychiki kierującego, zmniejszana przy wykryciu kolizji)
|
||||
|
||||
601
DynObj.cpp
601
DynObj.cpp
@@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Camera.h" //bo likwidujemy trzęsienie
|
||||
#include "Console.h"
|
||||
#include "Traction.h"
|
||||
#include "sound.h"
|
||||
|
||||
// Ra: taki zapis funkcjonuje lepiej, ale może nie jest optymalny
|
||||
#define vWorldFront Math3D::vector3(0, 0, 1)
|
||||
@@ -1631,21 +1632,32 @@ TDynamicObject::~TDynamicObject()
|
||||
// parametrow fizycznych
|
||||
SafeDelete(Mechanik);
|
||||
SafeDelete(MoverParameters);
|
||||
// Ra: wyłączanie dźwięków powinno być dodane w ich destruktorach, ale się
|
||||
// sypie
|
||||
/* to też się sypie
|
||||
for (int i=0;i<MaxAxles;++i)
|
||||
rsStukot[i].Stop(); //dzwieki poszczegolnych osi
|
||||
rsSilnik.Stop();
|
||||
rsWentylator.Stop();
|
||||
rsPisk.Stop();
|
||||
rsDerailment.Stop();
|
||||
sPantUp.Stop();
|
||||
sPantDown.Stop();
|
||||
sBrakeAcc.Stop(); //dzwiek przyspieszacza
|
||||
rsDiesielInc.Stop();
|
||||
rscurve.Stop();
|
||||
*/
|
||||
|
||||
for (size_t i = 0; i < MaxAxles; i++)
|
||||
sound_man->destroy_sound(&rsStukot[i]);
|
||||
sound_man->destroy_sound(&rsSilnik);
|
||||
sound_man->destroy_sound(&rsWentylator);
|
||||
sound_man->destroy_sound(&rsPisk);
|
||||
sound_man->destroy_sound(&rsDerailment);
|
||||
sound_man->destroy_sound(&rsPrzekladnia);
|
||||
sound_man->destroy_sound(&sHorn1);
|
||||
sound_man->destroy_sound(&sHorn2);
|
||||
sound_man->destroy_sound(&sCompressor);
|
||||
sound_man->destroy_sound(&sConverter);
|
||||
sound_man->destroy_sound(&sSmallCompressor);
|
||||
sound_man->destroy_sound(&sDepartureSignal);
|
||||
sound_man->destroy_sound(&sTurbo);
|
||||
sound_man->destroy_sound(&sSand);
|
||||
sound_man->destroy_sound(&sReleaser);
|
||||
sound_man->destroy_sound(&sPantUp);
|
||||
sound_man->destroy_sound(&sPantDown);
|
||||
sound_man->destroy_sound(&rsDoorOpen);
|
||||
sound_man->destroy_sound(&rsDoorClose);
|
||||
sound_man->destroy_sound(&sBrakeAcc);
|
||||
sound_man->destroy_sound(&rsUnbrake);
|
||||
sound_man->destroy_sound(&rsDiesielInc);
|
||||
sound_man->destroy_sound(&rscurve);
|
||||
|
||||
/*
|
||||
delete[] pAnimations; // obiekty obsługujące animację
|
||||
*/
|
||||
@@ -3044,7 +3056,8 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
// McZapkie-270202
|
||||
if (MyTrack->fSoundDistance != -1)
|
||||
{
|
||||
if (ObjectDist < rsStukot[0].dSoundAtt * rsStukot[0].dSoundAtt * 15.0)
|
||||
//m7todo: restore
|
||||
//if (ObjectDist < rsStukot[0].dSoundAtt * rsStukot[0].dSoundAtt * 15.0)
|
||||
{
|
||||
vol = (20.0 + MyTrack->iDamageFlag) / 21;
|
||||
if (MyTrack->eEnvironment == e_tunnel)
|
||||
@@ -3079,16 +3092,15 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
// McZapkie-040302
|
||||
if (i == iAxles - 1)
|
||||
{
|
||||
rsStukot[0].Stop();
|
||||
if (rsStukot[0]) rsStukot[0]->stop();
|
||||
MoverParameters->AccV +=
|
||||
0.5 * GetVelocity() / (1 + MoverParameters->Vmax);
|
||||
}
|
||||
else
|
||||
{
|
||||
rsStukot[i + 1].Stop();
|
||||
if (rsStukot[i + 1]) rsStukot[i + 1]->stop();
|
||||
}
|
||||
rsStukot[i].Play(vol, 0, MechInside,
|
||||
vPosition); // poprawic pozycje o uklad osi
|
||||
if (rsStukot[i]) rsStukot[i]->gain(vol).position(vPosition).play(); // poprawic pozycje o uklad osi
|
||||
if (i == 1)
|
||||
MoverParameters->AccV -=
|
||||
0.5 * GetVelocity() / (1 + MoverParameters->Vmax);
|
||||
@@ -3105,11 +3117,10 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
int flag = MoverParameters->Hamulec->GetSoundFlag();
|
||||
if ((bBrakeAcc) && (TestFlag(flag, sf_Acc)) && (ObjectDist < 2500))
|
||||
{
|
||||
sBrakeAcc->SetVolume(-ObjectDist * 3 - (FreeFlyModeFlag ? 0 : 2000));
|
||||
sBrakeAcc->Play(0, 0, 0);
|
||||
sBrakeAcc->SetPan(10000 * sin(ModCamRot));
|
||||
sBrakeAcc->gain(-ObjectDist * 3 - (FreeFlyModeFlag ? 0 : 2000));
|
||||
sBrakeAcc->play();
|
||||
}
|
||||
if ((rsUnbrake.AM != 0) && (ObjectDist < 5000))
|
||||
if ((rsUnbrake) && (ObjectDist < 5000))
|
||||
{
|
||||
if ((TestFlag(flag, sf_CylU)) &&
|
||||
((MoverParameters->BrakePress * MoverParameters->MaxBrakePress[3]) > 0.05))
|
||||
@@ -3120,11 +3131,10 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
MoverParameters->MaxBrakePress[3]),
|
||||
1);
|
||||
vol = vol + (FreeFlyModeFlag ? 0 : -0.5) - ObjectDist / 5000;
|
||||
rsUnbrake.SetPan(10000 * sin(ModCamRot));
|
||||
rsUnbrake.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition());
|
||||
rsUnbrake->loop().gain(vol).position(GetPosition()).play();
|
||||
}
|
||||
else
|
||||
rsUnbrake.Stop();
|
||||
rsUnbrake->stop();
|
||||
}
|
||||
|
||||
// fragment z EXE Kursa
|
||||
@@ -3237,8 +3247,8 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
&& ( PantDiff < 0.01 ) ) // tolerancja niedolegania
|
||||
{
|
||||
if ((MoverParameters->PantFrontVolt == 0.0) &&
|
||||
(MoverParameters->PantRearVolt == 0.0))
|
||||
sPantUp.Play(vol, 0, MechInside, vPosition);
|
||||
(MoverParameters->PantRearVolt == 0.0) && sPantUp)
|
||||
sPantUp->gain(vol).position(vPosition).play();
|
||||
if (p->hvPowerWire) // TODO: wyliczyć trzeba prąd przypadający na
|
||||
// pantograf i
|
||||
// wstawić do GetVoltage()
|
||||
@@ -3266,8 +3276,8 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
&& ( PantDiff < 0.01 ) )
|
||||
{
|
||||
if ((MoverParameters->PantRearVolt == 0.0) &&
|
||||
(MoverParameters->PantFrontVolt == 0.0))
|
||||
sPantUp.Play(vol, 0, MechInside, vPosition);
|
||||
(MoverParameters->PantFrontVolt == 0.0) && sPantUp)
|
||||
sPantUp->gain(vol).position(vPosition).play();
|
||||
if (p->hvPowerWire) // TODO: wyliczyć trzeba prąd przypadający na
|
||||
// pantograf i
|
||||
// wstawić do GetVoltage()
|
||||
@@ -3354,12 +3364,12 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
} // koniec pętli po pantografach
|
||||
if ((MoverParameters->PantFrontSP == false) && (MoverParameters->PantFrontUp == false))
|
||||
{
|
||||
sPantDown.Play(vol, 0, MechInside, vPosition);
|
||||
sPantDown->gain(vol).position(vPosition).play();
|
||||
MoverParameters->PantFrontSP = true;
|
||||
}
|
||||
if ((MoverParameters->PantRearSP == false) && (MoverParameters->PantRearUp == false))
|
||||
{
|
||||
sPantDown.Play(vol, 0, MechInside, vPosition);
|
||||
sPantDown->gain(vol).position(vPosition).play();
|
||||
MoverParameters->PantRearSP = true;
|
||||
}
|
||||
/*
|
||||
@@ -3462,24 +3472,24 @@ bool TDynamicObject::Update(double dt, double dt1)
|
||||
// NBMX Obsluga drzwi, MC: zuniwersalnione
|
||||
if ((dDoorMoveL < MoverParameters->DoorMaxShiftL) && (MoverParameters->DoorLeftOpened))
|
||||
{
|
||||
rsDoorOpen.Play(1, 0, MechInside, vPosition);
|
||||
rsDoorOpen->position(vPosition).play();
|
||||
dDoorMoveL += dt1 * 0.5 * MoverParameters->DoorOpenSpeed;
|
||||
}
|
||||
if ((dDoorMoveL > 0) && (!MoverParameters->DoorLeftOpened))
|
||||
{
|
||||
rsDoorClose.Play(1, 0, MechInside, vPosition);
|
||||
rsDoorClose->position(vPosition).play();
|
||||
dDoorMoveL -= dt1 * MoverParameters->DoorCloseSpeed;
|
||||
if (dDoorMoveL < 0)
|
||||
dDoorMoveL = 0;
|
||||
}
|
||||
if ((dDoorMoveR < MoverParameters->DoorMaxShiftR) && (MoverParameters->DoorRightOpened))
|
||||
{
|
||||
rsDoorOpen.Play(1, 0, MechInside, vPosition);
|
||||
rsDoorOpen->position(vPosition).play();
|
||||
dDoorMoveR += dt1 * 0.5 * MoverParameters->DoorOpenSpeed;
|
||||
}
|
||||
if ((dDoorMoveR > 0) && (!MoverParameters->DoorRightOpened))
|
||||
{
|
||||
rsDoorClose.Play(1, 0, MechInside, vPosition);
|
||||
rsDoorClose->position(vPosition).play();
|
||||
dDoorMoveR -= dt1 * MoverParameters->DoorCloseSpeed;
|
||||
if (dDoorMoveR < 0)
|
||||
dDoorMoveR = 0;
|
||||
@@ -3658,7 +3668,7 @@ void TDynamicObject::RenderSounds()
|
||||
|
||||
if (MoverParameters->Power > 0)
|
||||
{
|
||||
if ((rsSilnik.AM != 0)
|
||||
if ((rsSilnik)
|
||||
&& ((MoverParameters->Mains)
|
||||
// McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach
|
||||
|| (MoverParameters->EngineType == DieselEngine)))
|
||||
@@ -3666,39 +3676,33 @@ void TDynamicObject::RenderSounds()
|
||||
if ((fabs(MoverParameters->enrot) > 0.01) ||
|
||||
(MoverParameters->EngineType == Dumb)) //&& (MoverParameters->EnginePower>0.1))
|
||||
{
|
||||
freq = rsSilnik.FM * fabs(MoverParameters->enrot) + rsSilnik.FA;
|
||||
freq = fabs(MoverParameters->enrot);
|
||||
if (MoverParameters->EngineType == Dumb)
|
||||
freq = freq -
|
||||
0.2 * MoverParameters->EnginePower / (1 + MoverParameters->Power * 1000);
|
||||
rsSilnik.AdjFreq(freq, dt);
|
||||
rsSilnik->pitch(freq);
|
||||
if (MoverParameters->EngineType == DieselEngine)
|
||||
{
|
||||
if (MoverParameters->enrot > 0)
|
||||
{
|
||||
if (MoverParameters->EnginePower > 0)
|
||||
vol = rsSilnik.AM * MoverParameters->dizel_fill + rsSilnik.AA;
|
||||
vol = MoverParameters->dizel_fill;
|
||||
else
|
||||
vol =
|
||||
rsSilnik.AM * fabs(MoverParameters->enrot / MoverParameters->dizel_nmax) +
|
||||
rsSilnik.AA * 0.9;
|
||||
fabs(MoverParameters->enrot / MoverParameters->dizel_nmax);
|
||||
}
|
||||
else
|
||||
vol = 0;
|
||||
}
|
||||
else if (MoverParameters->EngineType == DieselElectric)
|
||||
vol = rsSilnik.AM *
|
||||
(MoverParameters->EnginePower / 1000 / MoverParameters->Power) +
|
||||
vol = (MoverParameters->EnginePower / 1000 / MoverParameters->Power) +
|
||||
0.2 * (MoverParameters->enrot * 60) /
|
||||
(MoverParameters->DElist[MoverParameters->MainCtrlPosNo].RPM) +
|
||||
rsSilnik.AA;
|
||||
(MoverParameters->DElist[MoverParameters->MainCtrlPosNo].RPM);
|
||||
else if (MoverParameters->EngineType == ElectricInductionMotor)
|
||||
vol = rsSilnik.AM *
|
||||
(MoverParameters->EnginePower + fabs(MoverParameters->enrot * 2)) +
|
||||
rsSilnik.AA;
|
||||
vol = (MoverParameters->EnginePower + fabs(MoverParameters->enrot * 2));
|
||||
else
|
||||
vol = rsSilnik.AM * (MoverParameters->EnginePower / 1000 +
|
||||
fabs(MoverParameters->enrot) * 60.0) +
|
||||
rsSilnik.AA;
|
||||
vol = (MoverParameters->EnginePower / 1000 +
|
||||
fabs(MoverParameters->enrot) * 60.0);
|
||||
// McZapkie-250302 - natezenie zalezne od obrotow i mocy
|
||||
if ((vol < 1) && (MoverParameters->EngineType == ElectricSeriesMotor) &&
|
||||
(MoverParameters->EnginePower < 100))
|
||||
@@ -3731,11 +3735,11 @@ void TDynamicObject::RenderSounds()
|
||||
if (enginevolume > 0.0001)
|
||||
if (MoverParameters->EngineType != DieselElectric)
|
||||
{
|
||||
rsSilnik.Play(enginevolume, DSBPLAY_LOOPING, MechInside, GetPosition());
|
||||
rsSilnik->loop().gain(enginevolume).position(GetPosition()).play();
|
||||
}
|
||||
else
|
||||
{
|
||||
sConverter.UpdateAF(vol, freq, MechInside, GetPosition());
|
||||
sConverter->gain(vol).pitch(freq).position(GetPosition());
|
||||
|
||||
float fincvol;
|
||||
fincvol = 0;
|
||||
@@ -3746,100 +3750,114 @@ void TDynamicObject::RenderSounds()
|
||||
(MoverParameters->enrot * 60));
|
||||
fincvol /= (0.05 * MoverParameters->DElist[0].RPM);
|
||||
};
|
||||
if (fincvol > 0.02)
|
||||
rsDiesielInc.Play(fincvol, DSBPLAY_LOOPING, MechInside, GetPosition());
|
||||
else
|
||||
rsDiesielInc.Stop();
|
||||
if (rsDiesielInc)
|
||||
{
|
||||
if (fincvol > 0.02)
|
||||
rsDiesielInc->loop().position(GetPosition()).gain(fincvol).play();
|
||||
else
|
||||
rsDiesielInc->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
rsSilnik.Stop();
|
||||
rsSilnik->stop();
|
||||
}
|
||||
enginevolume = (enginevolume + vol) * 0.5;
|
||||
if( enginevolume < 0.01 ) {
|
||||
rsSilnik.Stop();
|
||||
rsSilnik->stop();
|
||||
}
|
||||
if ( ( MoverParameters->EngineType == ElectricSeriesMotor )
|
||||
|| ( MoverParameters->EngineType == ElectricInductionMotor )
|
||||
&& ( rsWentylator.AM != 0 ) )
|
||||
if ( (( MoverParameters->EngineType == ElectricSeriesMotor )
|
||||
|| ( MoverParameters->EngineType == ElectricInductionMotor ))
|
||||
&& ( rsWentylator ) )
|
||||
{
|
||||
if (MoverParameters->RventRot > 0.1) {
|
||||
// play ventilator sound if the ventilators are rotating fast enough...
|
||||
freq = rsWentylator.FM * MoverParameters->RventRot + rsWentylator.FA;
|
||||
rsWentylator.AdjFreq(freq, dt);
|
||||
freq = MoverParameters->RventRot;
|
||||
rsWentylator->pitch(freq);
|
||||
if( MoverParameters->EngineType == ElectricInductionMotor ) {
|
||||
|
||||
vol = rsWentylator.AM * std::sqrt( std::fabs( MoverParameters->dizel_fill ) ) + rsWentylator.AA;
|
||||
vol = std::sqrt( std::fabs( MoverParameters->dizel_fill ) );
|
||||
}
|
||||
else {
|
||||
|
||||
vol = rsWentylator.AM * MoverParameters->RventRot + rsWentylator.AA;
|
||||
vol = MoverParameters->RventRot;
|
||||
}
|
||||
rsWentylator.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition());
|
||||
rsWentylator->gain(vol).loop().position(GetPosition()).play();
|
||||
}
|
||||
else {
|
||||
// ...otherwise shut down the sound
|
||||
rsWentylator.Stop();
|
||||
rsWentylator->stop();
|
||||
}
|
||||
}
|
||||
if (MoverParameters->TrainType == dt_ET40)
|
||||
if (MoverParameters->TrainType == dt_ET40 && rsPrzekladnia)
|
||||
{
|
||||
if (MoverParameters->Vel > 0.1)
|
||||
{
|
||||
freq = rsPrzekladnia.FM * (MoverParameters->Vel) + rsPrzekladnia.FA;
|
||||
rsPrzekladnia.AdjFreq(freq, dt);
|
||||
vol = rsPrzekladnia.AM * (MoverParameters->Vel) + rsPrzekladnia.AA;
|
||||
rsPrzekladnia.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition());
|
||||
freq = MoverParameters->Vel;
|
||||
rsPrzekladnia->pitch(freq);
|
||||
vol = MoverParameters->Vel;
|
||||
rsPrzekladnia->loop().position(GetPosition()).gain(vol).play();
|
||||
}
|
||||
else
|
||||
rsPrzekladnia.Stop();
|
||||
rsPrzekladnia->stop();
|
||||
}
|
||||
}
|
||||
|
||||
// youBy: dzwiek ostrych lukow i ciasnych zwrotek
|
||||
|
||||
if ((ts.R * ts.R > 1) && (MoverParameters->Vel > 0))
|
||||
vol = MoverParameters->AccN * MoverParameters->AccN;
|
||||
else
|
||||
vol = 0;
|
||||
// vol+=(50000/ts.R*ts.R);
|
||||
|
||||
if (vol > 0.001)
|
||||
if (rscurve)
|
||||
{
|
||||
rscurve.Play(2 * vol, DSBPLAY_LOOPING, MechInside, GetPosition());
|
||||
if ((ts.R * ts.R > 1) && (MoverParameters->Vel > 0))
|
||||
vol = MoverParameters->AccN * MoverParameters->AccN;
|
||||
else
|
||||
vol = 0;
|
||||
// vol+=(50000/ts.R*ts.R);
|
||||
|
||||
if (vol > 0.001)
|
||||
{
|
||||
rscurve->gain(2 * vol).loop().position(GetPosition()).play();
|
||||
}
|
||||
else
|
||||
rscurve->stop();
|
||||
}
|
||||
else
|
||||
rscurve.Stop();
|
||||
|
||||
// McZapkie-280302 - pisk mocno zacisnietych hamulcow - trzeba jeszcze
|
||||
// zabezpieczyc przed
|
||||
// brakiem deklaracji w mmedia.dta
|
||||
if (rsPisk.AM != 0)
|
||||
|
||||
if (rsPisk)
|
||||
{
|
||||
if ((MoverParameters->Vel > (rsPisk.GetStatus() != 0 ? 0.01 : 0.5)) &&
|
||||
(!MoverParameters->SlippingWheels) && (MoverParameters->UnitBrakeForce > rsPisk.AM))
|
||||
if ((MoverParameters->Vel > (rsPisk->is_playing() != 0 ? 0.01 : 0.5)) &&
|
||||
(!MoverParameters->SlippingWheels) && (MoverParameters->UnitBrakeForce > rsPisk->gain_mul))
|
||||
{
|
||||
vol = MoverParameters->UnitBrakeForce / (rsPisk.AM + 1) + rsPisk.AA;
|
||||
rsPisk.Play(vol, DSBPLAY_LOOPING, MechInside, GetPosition());
|
||||
vol = (MoverParameters->UnitBrakeForce / (rsPisk->gain_mul + 1)) / rsPisk->gain_mul;
|
||||
rsPisk->gain(vol).loop().position(GetPosition()).play();
|
||||
}
|
||||
else
|
||||
rsPisk.Stop();
|
||||
rsPisk->stop();
|
||||
}
|
||||
|
||||
if (MoverParameters->SandDose) // Dzwiek piasecznicy
|
||||
sSand.TurnOn(MechInside, GetPosition());
|
||||
else
|
||||
sSand.TurnOff(MechInside, GetPosition());
|
||||
sSand.Update(MechInside, GetPosition());
|
||||
if (MoverParameters->Hamulec->GetStatus() & b_rls) // Dzwiek odluzniacza
|
||||
sReleaser.TurnOn(MechInside, GetPosition());
|
||||
else
|
||||
sReleaser.TurnOff(MechInside, GetPosition());
|
||||
//sReleaser.Update(MechInside, GetPosition());
|
||||
double releaser_vol = 1;
|
||||
if (MoverParameters->BrakePress < 0.1)
|
||||
releaser_vol = MoverParameters->BrakePress * 10;
|
||||
sReleaser.UpdateAF(releaser_vol, 1, MechInside, GetPosition());
|
||||
if (sSand)
|
||||
{
|
||||
if (MoverParameters->SandDose) // Dzwiek piasecznicy
|
||||
sSand->position(GetPosition()).play();
|
||||
else
|
||||
sSand->stop();
|
||||
}
|
||||
|
||||
if (sReleaser)
|
||||
{
|
||||
if (MoverParameters->Hamulec->GetStatus() & b_rls) // Dzwiek odluzniacza
|
||||
sReleaser->position(GetPosition()).play();
|
||||
else
|
||||
sReleaser->stop();
|
||||
//sReleaser.Update(MechInside, GetPosition());
|
||||
double releaser_vol = 1;
|
||||
if (MoverParameters->BrakePress < 0.1)
|
||||
releaser_vol = MoverParameters->BrakePress * 10;
|
||||
|
||||
sReleaser->gain(releaser_vol);
|
||||
}
|
||||
// if ((MoverParameters->ConverterFlag==false) &&
|
||||
// (MoverParameters->TrainType!=dt_ET22))
|
||||
// if
|
||||
@@ -3851,51 +3869,59 @@ void TDynamicObject::RenderSounds()
|
||||
// MoverParameters->CompressorAllow=MoverParameters->ConverterFlag;
|
||||
|
||||
// McZapkie! - dzwiek compressor.wav tylko gdy dziala sprezarka
|
||||
if (MoverParameters->VeselVolume != 0)
|
||||
{
|
||||
if (MoverParameters->CompressorFlag)
|
||||
sCompressor.TurnOn(MechInside, GetPosition());
|
||||
else
|
||||
sCompressor.TurnOff(MechInside, GetPosition());
|
||||
sCompressor.Update(MechInside, GetPosition());
|
||||
}
|
||||
if (MoverParameters->PantCompFlag) // Winger 160404 - dzwiek malej sprezarki
|
||||
sSmallCompressor.TurnOn(MechInside, GetPosition());
|
||||
else
|
||||
sSmallCompressor.TurnOff(MechInside, GetPosition());
|
||||
sSmallCompressor.Update(MechInside, GetPosition());
|
||||
|
||||
// youBy - przenioslem, bo diesel tez moze miec turbo
|
||||
if( (MoverParameters->TurboTest > 0)
|
||||
&& (MoverParameters->MainCtrlPos >= MoverParameters->TurboTest))
|
||||
if (sCompressor)
|
||||
{
|
||||
// udawanie turbo: (6.66*(eng_vol-0.85))
|
||||
if (eng_turbo > 6.66 * (enginevolume - 0.8) + 0.2 * dt)
|
||||
eng_turbo = eng_turbo - 0.2 * dt; // 0.125
|
||||
else if (eng_turbo < 6.66 * (enginevolume - 0.8) - 0.4 * dt)
|
||||
eng_turbo = eng_turbo + 0.4 * dt; // 0.333
|
||||
else
|
||||
eng_turbo = 6.66 * (enginevolume - 0.8);
|
||||
|
||||
sTurbo.TurnOn(MechInside, GetPosition());
|
||||
// sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition());
|
||||
sTurbo.UpdateAF(3 * eng_turbo - 1, 0.4 + eng_turbo * 0.4, MechInside, GetPosition());
|
||||
// eng_vol_act=enginevolume;
|
||||
// eng_frq_act=eng_frq;
|
||||
if (MoverParameters->VeselVolume != 0)
|
||||
{
|
||||
if (MoverParameters->CompressorFlag)
|
||||
sCompressor->position(GetPosition()).play();
|
||||
else
|
||||
sCompressor->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (sSmallCompressor)
|
||||
{
|
||||
if (MoverParameters->PantCompFlag) // Winger 160404 - dzwiek malej sprezarki
|
||||
sSmallCompressor->position(GetPosition()).play();
|
||||
else
|
||||
sSmallCompressor->stop();
|
||||
}
|
||||
|
||||
if (sTurbo)
|
||||
{
|
||||
// youBy - przenioslem, bo diesel tez moze miec turbo
|
||||
if( (MoverParameters->TurboTest > 0)
|
||||
&& (MoverParameters->MainCtrlPos >= MoverParameters->TurboTest))
|
||||
{
|
||||
// udawanie turbo: (6.66*(eng_vol-0.85))
|
||||
if (eng_turbo > 6.66 * (enginevolume - 0.8) + 0.2 * dt)
|
||||
eng_turbo = eng_turbo - 0.2 * dt; // 0.125
|
||||
else if (eng_turbo < 6.66 * (enginevolume - 0.8) - 0.4 * dt)
|
||||
eng_turbo = eng_turbo + 0.4 * dt; // 0.333
|
||||
else
|
||||
eng_turbo = 6.66 * (enginevolume - 0.8);
|
||||
|
||||
sTurbo->gain(3 * eng_turbo - 1).pitch(0.4 + eng_turbo * 0.4).position(GetPosition()).play();
|
||||
}
|
||||
else
|
||||
sTurbo->stop();
|
||||
}
|
||||
else
|
||||
sTurbo.TurnOff(MechInside, GetPosition());
|
||||
|
||||
if (MoverParameters->TrainType == dt_PseudoDiesel)
|
||||
{
|
||||
// ABu: udawanie woodwarda dla lok. spalinowych
|
||||
// jesli silnik jest podpiety pod dzwiek przetwornicy
|
||||
if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy
|
||||
if (sConverter)
|
||||
{
|
||||
sConverter.TurnOn(MechInside, GetPosition());
|
||||
if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy
|
||||
{
|
||||
sConverter->position(GetPosition()).play();
|
||||
}
|
||||
else
|
||||
sConverter->stop();
|
||||
}
|
||||
else
|
||||
sConverter.TurnOff(MechInside, GetPosition());
|
||||
|
||||
// glosnosc zalezy od stosunku mocy silnika el. do mocy max
|
||||
double eng_vol;
|
||||
@@ -3942,7 +3968,7 @@ void TDynamicObject::RenderSounds()
|
||||
if (eng_frq_act < defrot + 0.1 * dt)
|
||||
eng_frq_act = defrot;
|
||||
}
|
||||
sConverter.UpdateAF(eng_vol_act, eng_frq_act + eng_dfrq, MechInside, GetPosition());
|
||||
sConverter->gain(eng_vol_act).pitch(eng_frq_act + eng_dfrq).position(GetPosition());
|
||||
// udawanie turbo: (6.66*(eng_vol-0.85))
|
||||
if (eng_turbo > 6.66 * (eng_vol - 0.8) + 0.2 * dt)
|
||||
eng_turbo = eng_turbo - 0.2 * dt; // 0.125
|
||||
@@ -3951,62 +3977,67 @@ void TDynamicObject::RenderSounds()
|
||||
else
|
||||
eng_turbo = 6.66 * (eng_vol - 0.8);
|
||||
|
||||
sTurbo.TurnOn(MechInside, GetPosition());
|
||||
if (sTurbo) sTurbo->gain(3 * eng_turbo - 1).pitch(0.4 + eng_turbo * 0.4).position(GetPosition()).play();
|
||||
// sTurbo.UpdateAF(eng_turbo,0.7+(eng_turbo*0.6),MechInside,GetPosition());
|
||||
sTurbo.UpdateAF(3 * eng_turbo - 1, 0.4 + eng_turbo * 0.4, MechInside, GetPosition());
|
||||
eng_vol_act = eng_vol;
|
||||
// eng_frq_act=eng_frq;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy
|
||||
sConverter.TurnOn(MechInside, GetPosition());
|
||||
else
|
||||
sConverter.TurnOff(MechInside, GetPosition());
|
||||
sConverter.Update(MechInside, GetPosition());
|
||||
if (sConverter)
|
||||
{
|
||||
if (MoverParameters->ConverterFlag) // NBMX dzwiek przetwornicy
|
||||
{
|
||||
sConverter->position(GetPosition()).play();
|
||||
}
|
||||
else
|
||||
sConverter->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if( TestFlag( MoverParameters->WarningSignal, 1 ) ) {
|
||||
sHorn1.TurnOn( MechInside, GetPosition() );
|
||||
}
|
||||
else {
|
||||
sHorn1.TurnOff( MechInside, GetPosition() );
|
||||
}
|
||||
if( TestFlag( MoverParameters->WarningSignal, 2 ) ) {
|
||||
sHorn2.TurnOn( MechInside, GetPosition() );
|
||||
}
|
||||
else {
|
||||
sHorn2.TurnOff( MechInside, GetPosition() );
|
||||
if (sHorn1)
|
||||
{
|
||||
if( TestFlag( MoverParameters->WarningSignal, 1 ) ) {
|
||||
sHorn1->position(GetPosition()).play();
|
||||
}
|
||||
else {
|
||||
sHorn1->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (MoverParameters->DoorClosureWarning)
|
||||
if (sHorn2)
|
||||
{
|
||||
if (MoverParameters->DepartureSignal) // NBMX sygnal odjazdu, MC: pod warunkiem ze jest
|
||||
// zdefiniowane w chk
|
||||
sDepartureSignal.TurnOn(MechInside, GetPosition());
|
||||
else
|
||||
sDepartureSignal.TurnOff(MechInside, GetPosition());
|
||||
sDepartureSignal.Update(MechInside, GetPosition());
|
||||
if( TestFlag( MoverParameters->WarningSignal, 2 ) ) {
|
||||
sHorn2->position(GetPosition()).play();
|
||||
}
|
||||
else {
|
||||
sHorn2->stop();
|
||||
}
|
||||
}
|
||||
sHorn1.Update(MechInside, GetPosition());
|
||||
sHorn2.Update(MechInside, GetPosition());
|
||||
// McZapkie: w razie wykolejenia
|
||||
if (MoverParameters->EventFlag)
|
||||
|
||||
if (sDepartureSignal)
|
||||
{
|
||||
if (TestFlag(MoverParameters->DamageFlag, dtrain_out) && GetVelocity() > 0)
|
||||
rsDerailment.Play(1, 0, true, GetPosition());
|
||||
if (GetVelocity() == 0)
|
||||
rsDerailment.Stop();
|
||||
if (MoverParameters->DoorClosureWarning)
|
||||
{
|
||||
if (MoverParameters->DepartureSignal) // NBMX sygnal odjazdu, MC: pod warunkiem ze jest
|
||||
// zdefiniowane w chk
|
||||
sDepartureSignal->position(GetPosition()).play();
|
||||
else
|
||||
sDepartureSignal->stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (rsDerailment)
|
||||
{
|
||||
// McZapkie: w razie wykolejenia
|
||||
if (MoverParameters->EventFlag)
|
||||
{
|
||||
if (TestFlag(MoverParameters->DamageFlag, dtrain_out) && GetVelocity() > 0)
|
||||
rsDerailment->position(GetPosition()).play();
|
||||
if (GetVelocity() == 0)
|
||||
rsDerailment->stop();
|
||||
}
|
||||
}
|
||||
/* //Ra: dwa razy?
|
||||
if (MoverParameters->EventFlag)
|
||||
{
|
||||
if (TestFlag(MoverParameters->DamageFlag,dtrain_out) && GetVelocity()>0)
|
||||
rsDerailment.Play(1,0,true,GetPosition());
|
||||
if (GetVelocity()==0)
|
||||
rsDerailment.Stop();
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
// McZapkie-250202
|
||||
@@ -4711,9 +4742,9 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
if( token != "end" ) {
|
||||
rsStukot[ i ].Init( token, dSDist, GetPosition().x,
|
||||
GetPosition().y + dWheelsPosition[ i ], GetPosition().z,
|
||||
true );
|
||||
rsStukot[i] = sound_man->create_sound(token);
|
||||
if (rsStukot[i]) rsStukot[i]->position(glm::vec3(GetPosition().x,
|
||||
GetPosition().y + dWheelsPosition[ i ], GetPosition().z)).dist(dSDist);
|
||||
}
|
||||
}
|
||||
if( token != "end" ) {
|
||||
@@ -4730,32 +4761,31 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rsSilnik.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true, true );
|
||||
if( rsSilnik.GetWaveTime() == 0 ) {
|
||||
ErrorLog( "Missed sound: \"" + token + "\" for " + asFileName );
|
||||
}
|
||||
parser.getTokens( 1, false );
|
||||
parser >> rsSilnik.AM;
|
||||
if( MoverParameters->EngineType == DieselEngine ) {
|
||||
rsSilnik = sound_man->create_sound(token);
|
||||
if (rsSilnik)
|
||||
{
|
||||
rsSilnik->dist(attenuation);
|
||||
parser.getTokens( 4, false );
|
||||
|
||||
rsSilnik.AM /= ( MoverParameters->Power + MoverParameters->nmax * 60 );
|
||||
}
|
||||
else if( MoverParameters->EngineType == DieselElectric ) {
|
||||
parser >> rsSilnik->gain_mul;
|
||||
if( MoverParameters->EngineType == DieselEngine ) {
|
||||
|
||||
rsSilnik.AM /= ( MoverParameters->Power * 3 );
|
||||
}
|
||||
else {
|
||||
rsSilnik->gain_mul /= ( MoverParameters->Power + MoverParameters->nmax * 60 );
|
||||
}
|
||||
else if( MoverParameters->EngineType == DieselElectric ) {
|
||||
|
||||
rsSilnik.AM /= ( MoverParameters->Power + MoverParameters->nmax * 60 + MoverParameters->Power + MoverParameters->Power );
|
||||
}
|
||||
parser.getTokens( 3, false );
|
||||
parser
|
||||
>> rsSilnik.AA
|
||||
>> rsSilnik.FM // MoverParameters->nmax;
|
||||
>> rsSilnik.FA;
|
||||
rsSilnik->gain_mul /= ( MoverParameters->Power * 3 );
|
||||
}
|
||||
else {
|
||||
|
||||
rsSilnik->gain_mul /= ( MoverParameters->Power + MoverParameters->nmax * 60 + MoverParameters->Power + MoverParameters->Power );
|
||||
}
|
||||
|
||||
parser
|
||||
>> rsSilnik->gain_off
|
||||
>> rsSilnik->pitch_mul // MoverParameters->nmax;
|
||||
>> rsSilnik->pitch_off;
|
||||
}
|
||||
}
|
||||
|
||||
else if( ( token == "ventilator:" )
|
||||
@@ -4767,18 +4797,19 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rsWentylator.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true, true );
|
||||
parser.getTokens( 4, false );
|
||||
parser
|
||||
>> rsWentylator.AM
|
||||
>> rsWentylator.AA
|
||||
>> rsWentylator.FM
|
||||
>> rsWentylator.FA;
|
||||
rsWentylator.AM /= MoverParameters->RVentnmax;
|
||||
rsWentylator.FM /= MoverParameters->RVentnmax;
|
||||
rsWentylator = sound_man->create_sound(token);
|
||||
if (rsWentylator)
|
||||
{
|
||||
rsWentylator->dist(attenuation);
|
||||
parser.getTokens( 4, false );
|
||||
parser
|
||||
>> rsWentylator->gain_mul
|
||||
>> rsWentylator->gain_off
|
||||
>> rsWentylator->pitch_mul
|
||||
>> rsWentylator->pitch_off;
|
||||
rsWentylator->gain_mul /= MoverParameters->RVentnmax;
|
||||
rsWentylator->pitch_mul /= MoverParameters->RVentnmax;
|
||||
}
|
||||
}
|
||||
|
||||
else if( ( token == "transmission:" )
|
||||
@@ -4789,14 +4820,15 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rsPrzekladnia.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rsPrzekladnia.AM = 0.029;
|
||||
rsPrzekladnia.AA = 0.1;
|
||||
rsPrzekladnia.FM = 0.005;
|
||||
rsPrzekladnia.FA = 1.0;
|
||||
rsPrzekladnia = sound_man->create_sound(token);
|
||||
if (rsPrzekladnia)
|
||||
{
|
||||
rsPrzekladnia->dist(attenuation);
|
||||
rsPrzekladnia->gain_mul = 0.029;
|
||||
rsPrzekladnia->gain_off = 0.1;
|
||||
rsPrzekladnia->pitch_mul = 0.005;
|
||||
rsPrzekladnia->pitch_off = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
else if( token == "brake:" ){
|
||||
@@ -4806,26 +4838,27 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rsPisk.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rsPisk.AM = parser.getToken<double>();
|
||||
rsPisk.AA = parser.getToken<double>() * ( 105 - Random( 10 ) ) / 100;
|
||||
rsPisk.FM = 1.0;
|
||||
rsPisk.FA = 0.0;
|
||||
rsPisk = sound_man->create_sound(token);
|
||||
if (rsPisk)
|
||||
{
|
||||
rsPisk->dist(attenuation);
|
||||
rsPisk->gain_mul = parser.getToken<double>();
|
||||
rsPisk->gain_off = parser.getToken<double>() * ( 105 - Random( 10 ) ) / 100;
|
||||
rsPisk->pitch_mul = 1.0;
|
||||
rsPisk->pitch_off = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
else if( token == "brakeacc:" ) {
|
||||
// plik z przyspieszaczem (upust po zlapaniu hamowania)
|
||||
// sBrakeAcc.Init(str.c_str(),Parser->GetNextSymbol().ToDouble(),GetPosition().x,GetPosition().y,GetPosition().z,true);
|
||||
parser.getTokens( 1, false ); parser >> token;
|
||||
sBrakeAcc = TSoundsManager::GetFromName( token, true );
|
||||
sBrakeAcc = sound_man->create_sound(token);
|
||||
bBrakeAcc = true;
|
||||
// sBrakeAcc.AM=1.0;
|
||||
// sBrakeAcc.AA=0.0;
|
||||
// sBrakeAcc.FM=1.0;
|
||||
// sBrakeAcc.FA=0.0;
|
||||
// sBrakeAcc->gain_mul=1.0;
|
||||
// sBrakeAcc->gain_off=0.0;
|
||||
// sBrakeAcc->pitch_mul=1.0;
|
||||
// sBrakeAcc->pitch_off=0.0;
|
||||
}
|
||||
|
||||
else if( token == "unbrake:" ) {
|
||||
@@ -4835,14 +4868,9 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rsUnbrake.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rsUnbrake.AM = 1.0;
|
||||
rsUnbrake.AA = 0.0;
|
||||
rsUnbrake.FM = 1.0;
|
||||
rsUnbrake.FA = 0.0;
|
||||
rsUnbrake = sound_man->create_sound(token);
|
||||
if (rsUnbrake)
|
||||
rsUnbrake->dist(attenuation);
|
||||
}
|
||||
|
||||
else if( token == "derail:" ) {
|
||||
@@ -4852,14 +4880,9 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rsDerailment.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rsDerailment.AM = 1.0;
|
||||
rsDerailment.AA = 0.0;
|
||||
rsDerailment.FM = 1.0;
|
||||
rsDerailment.FA = 0.0;
|
||||
rsDerailment = sound_man->create_sound(token);
|
||||
if (rsDerailment)
|
||||
rsDerailment->dist(attenuation);
|
||||
}
|
||||
|
||||
else if( token == "dieselinc:" ) {
|
||||
@@ -4869,14 +4892,9 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rsDiesielInc.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rsDiesielInc.AM = 1.0;
|
||||
rsDiesielInc.AA = 0.0;
|
||||
rsDiesielInc.FM = 1.0;
|
||||
rsDiesielInc.FA = 0.0;
|
||||
rsDiesielInc = sound_man->create_sound(token);
|
||||
if (rsDiesielInc)
|
||||
rsDiesielInc->dist(attenuation);
|
||||
}
|
||||
|
||||
else if( token == "curve:" ) {
|
||||
@@ -4886,24 +4904,19 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
parser
|
||||
>> token
|
||||
>> attenuation;
|
||||
rscurve.Init(
|
||||
token, attenuation,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rscurve.AM = 1.0;
|
||||
rscurve.AA = 0.0;
|
||||
rscurve.FM = 1.0;
|
||||
rscurve.FA = 0.0;
|
||||
rscurve = sound_man->create_sound(token);
|
||||
if (rscurve)
|
||||
rscurve->dist(attenuation);
|
||||
}
|
||||
|
||||
else if( token == "horn1:" ) {
|
||||
// pliki z trabieniem
|
||||
sHorn1.Load( parser, GetPosition() );
|
||||
sHorn1 = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
else if( token == "horn2:" ) {
|
||||
// pliki z trabieniem wysokoton.
|
||||
sHorn2.Load( parser, GetPosition() );
|
||||
sHorn2 = sound_man->create_complex_sound(parser);
|
||||
if( iHornWarning ) {
|
||||
iHornWarning = 2; // numer syreny do użycia po otrzymaniu sygnału do jazdy
|
||||
}
|
||||
@@ -4911,74 +4924,62 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName,
|
||||
|
||||
else if( token == "departuresignal:" ) {
|
||||
// pliki z sygnalem odjazdu
|
||||
sDepartureSignal.Load( parser, GetPosition() );
|
||||
sDepartureSignal = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
else if( token == "pantographup:" ) {
|
||||
// pliki dzwiekow pantografow
|
||||
parser.getTokens( 1, false ); parser >> token;
|
||||
sPantUp.Init(
|
||||
token, 50,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
sPantUp = sound_man->create_sound(token);
|
||||
}
|
||||
|
||||
else if( token == "pantographdown:" ) {
|
||||
// pliki dzwiekow pantografow
|
||||
parser.getTokens( 1, false ); parser >> token;
|
||||
sPantDown.Init(
|
||||
token, 50,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
sPantDown = sound_man->create_sound(token);
|
||||
}
|
||||
|
||||
else if( token == "compressor:" ) {
|
||||
// pliki ze sprezarka
|
||||
sCompressor.Load( parser, GetPosition() );
|
||||
sCompressor = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
else if( token == "converter:" ) {
|
||||
// pliki z przetwornica
|
||||
// if (MoverParameters->EngineType==DieselElectric) //będzie modulowany?
|
||||
sConverter.Load( parser, GetPosition() );
|
||||
sConverter = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
else if( token == "turbo:" ) {
|
||||
// pliki z turbogeneratorem
|
||||
sTurbo.Load( parser, GetPosition() );
|
||||
sTurbo = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
else if( token == "small-compressor:" ) {
|
||||
// pliki z przetwornica
|
||||
sSmallCompressor.Load( parser, GetPosition() );
|
||||
sSmallCompressor = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
else if( token == "dooropen:" ) {
|
||||
|
||||
parser.getTokens( 1, false ); parser >> token;
|
||||
rsDoorOpen.Init(
|
||||
token, 50,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rsDoorOpen = sound_man->create_sound(token);
|
||||
}
|
||||
|
||||
else if( token == "doorclose:" ) {
|
||||
|
||||
parser.getTokens( 1, false ); parser >> token;
|
||||
rsDoorClose.Init(
|
||||
token, 50,
|
||||
GetPosition().x, GetPosition().y, GetPosition().z,
|
||||
true );
|
||||
rsDoorClose = sound_man->create_sound(token);
|
||||
}
|
||||
|
||||
else if( token == "sand:" ) {
|
||||
// pliki z piasecznica
|
||||
sSand.Load( parser, GetPosition() );
|
||||
sSand = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
else if( token == "releaser:" ) {
|
||||
// pliki z odluzniaczem
|
||||
sReleaser.Load( parser, GetPosition() );
|
||||
sReleaser = sound_man->create_complex_sound(parser);
|
||||
}
|
||||
|
||||
} while( ( token != "" )
|
||||
|
||||
52
DynObj.h
52
DynObj.h
@@ -14,8 +14,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "TrkFoll.h"
|
||||
// McZapkie:
|
||||
#include "RealSound.h"
|
||||
#include "AdvSound.h"
|
||||
#include "Button.h"
|
||||
#include "AirCoupler.h"
|
||||
#include "Texture.h"
|
||||
@@ -307,28 +305,28 @@ public: // modele składowe pojazdu
|
||||
double dRailLength;
|
||||
double dRailPosition[MaxAxles]; // licznik pozycji osi w/m szyny
|
||||
double dWheelsPosition[MaxAxles]; // pozycja osi w/m srodka pojazdu
|
||||
TRealSound rsStukot[MaxAxles]; // dzwieki poszczegolnych osi //McZapkie-270202
|
||||
TRealSound rsSilnik; // McZapkie-010302 - silnik
|
||||
TRealSound rsWentylator; // McZapkie-030302
|
||||
TRealSound rsPisk; // McZapkie-260302
|
||||
TRealSound rsDerailment; // McZapkie-051202
|
||||
TRealSound rsPrzekladnia;
|
||||
TAdvancedSound sHorn1;
|
||||
TAdvancedSound sHorn2;
|
||||
TAdvancedSound sCompressor; // NBMX wrzesien 2003
|
||||
TAdvancedSound sConverter;
|
||||
TAdvancedSound sSmallCompressor;
|
||||
TAdvancedSound sDepartureSignal;
|
||||
TAdvancedSound sTurbo;
|
||||
TAdvancedSound sSand;
|
||||
TAdvancedSound sReleaser;
|
||||
sound* rsStukot[MaxAxles] = { nullptr }; // dzwieki poszczegolnych osi //McZapkie-270202
|
||||
sound* rsSilnik = nullptr; // McZapkie-010302 - silnik
|
||||
sound* rsWentylator = nullptr; // McZapkie-030302
|
||||
sound* rsPisk = nullptr; // McZapkie-260302
|
||||
sound* rsDerailment = nullptr; // McZapkie-051202
|
||||
sound* rsPrzekladnia = nullptr;
|
||||
sound* sHorn1 = nullptr;
|
||||
sound* sHorn2 = nullptr;
|
||||
sound* sCompressor = nullptr; // NBMX wrzesien 2003
|
||||
sound* sConverter = nullptr;
|
||||
sound* sSmallCompressor = nullptr;
|
||||
sound* sDepartureSignal = nullptr;
|
||||
sound* sTurbo = nullptr;
|
||||
sound* sSand = nullptr;
|
||||
sound* sReleaser = nullptr;
|
||||
|
||||
// Winger 010304
|
||||
// TRealSound rsPanTup; //PSound sPantUp;
|
||||
TRealSound sPantUp;
|
||||
TRealSound sPantDown;
|
||||
TRealSound rsDoorOpen; // Ra: przeniesione z kabiny
|
||||
TRealSound rsDoorClose;
|
||||
// sound* rsPanTup; //PSound sPantUp;
|
||||
sound* sPantUp = nullptr;
|
||||
sound* sPantDown = nullptr;
|
||||
sound* rsDoorOpen = nullptr; // Ra: przeniesione z kabiny
|
||||
sound* rsDoorClose = nullptr;
|
||||
|
||||
double eng_vol_act;
|
||||
double eng_frq_act;
|
||||
@@ -339,10 +337,10 @@ public: // modele składowe pojazdu
|
||||
vector3 modelShake;
|
||||
|
||||
bool renderme; // yB - czy renderowac
|
||||
// TRealSound sBrakeAcc; //dźwięk przyspieszacza
|
||||
PSound sBrakeAcc;
|
||||
// sound* sBrakeAcc; //dźwięk przyspieszacza
|
||||
sound* sBrakeAcc = nullptr;
|
||||
bool bBrakeAcc;
|
||||
TRealSound rsUnbrake; // yB - odglos luzowania
|
||||
sound* rsUnbrake = nullptr; // yB - odglos luzowania
|
||||
float ModCamRot;
|
||||
int iInventory; // flagi bitowe posiadanych submodeli (np. świateł)
|
||||
void TurnOff();
|
||||
@@ -397,8 +395,8 @@ public: // modele składowe pojazdu
|
||||
return this ? asName : std::string("");
|
||||
};
|
||||
|
||||
TRealSound rsDiesielInc; // youBy
|
||||
TRealSound rscurve; // youBy
|
||||
sound* rsDiesielInc = nullptr; // youBy
|
||||
sound* rscurve = nullptr; // youBy
|
||||
// std::ofstream PneuLogFile; //zapis parametrow pneumatycznych
|
||||
// youBy - dym
|
||||
// TSmoke Smog;
|
||||
|
||||
2
Event.h
2
Event.h
@@ -73,7 +73,7 @@ union TParam
|
||||
bool asBool;
|
||||
double asdouble;
|
||||
int asInt;
|
||||
TTextSound *tsTextSound;
|
||||
sound *tsTextSound;
|
||||
char *asText;
|
||||
TCommandType asCommand;
|
||||
TTractionPowerSource *psPower;
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/*
|
||||
MaSzyna EU07 locomotive simulator
|
||||
Copyright (C) 2001-2004 Marcin Wozniak and others
|
||||
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "FadeSound.h"
|
||||
#include "Timer.h"
|
||||
|
||||
TFadeSound::~TFadeSound()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
void TFadeSound::Free()
|
||||
{
|
||||
}
|
||||
|
||||
void TFadeSound::Init(std::string const &Name, float fNewFade)
|
||||
{
|
||||
Sound = TSoundsManager::GetFromName(Name, false);
|
||||
if (Sound)
|
||||
Sound->SetVolume(0);
|
||||
fFade = fNewFade;
|
||||
fTime = 0;
|
||||
}
|
||||
|
||||
void TFadeSound::TurnOn()
|
||||
{
|
||||
State = ss_Starting;
|
||||
Sound->Play(0, 0, DSBPLAY_LOOPING);
|
||||
fTime = fFade;
|
||||
}
|
||||
|
||||
void TFadeSound::TurnOff()
|
||||
{
|
||||
State = ss_ShuttingDown;
|
||||
}
|
||||
|
||||
void TFadeSound::Update()
|
||||
{
|
||||
|
||||
if (State == ss_Starting)
|
||||
{
|
||||
fTime += Timer::GetDeltaTime();
|
||||
// SoundStart->SetVolume(-1000*(4-fTime)/4);
|
||||
if (fTime >= fFade)
|
||||
{
|
||||
fTime = fFade;
|
||||
State = ss_Commencing;
|
||||
Sound->SetVolume(-2000 * (fFade - fTime) / fFade);
|
||||
Sound->SetFrequency(44100 - 500 + 500 * (fTime) / fFade);
|
||||
}
|
||||
else if (Timer::GetSoundTimer())
|
||||
{
|
||||
Sound->SetVolume(-2000 * (fFade - fTime) / fFade);
|
||||
Sound->SetFrequency(44100 - 500 + 500 * (fTime) / fFade);
|
||||
}
|
||||
}
|
||||
else if (State == ss_ShuttingDown)
|
||||
{
|
||||
fTime -= Timer::GetDeltaTime();
|
||||
|
||||
if (fTime <= 0)
|
||||
{
|
||||
State = ss_Off;
|
||||
fTime = 0;
|
||||
Sound->Stop();
|
||||
}
|
||||
if (Timer::GetSoundTimer())
|
||||
{ // DSBVOLUME_MIN
|
||||
Sound->SetVolume(-2000 * (fFade - fTime) / fFade);
|
||||
Sound->SetFrequency(44100 - 500 + 500 * fTime / fFade);
|
||||
}
|
||||
}
|
||||
}
|
||||
void TFadeSound::Volume(long vol)
|
||||
{
|
||||
float glos = 1;
|
||||
Sound->SetVolume(vol * glos);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
40
FadeSound.h
40
FadeSound.h
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef FadeSoundH
|
||||
#define FadeSoundH
|
||||
|
||||
#include "Sound.h"
|
||||
#include "AdvSound.h"
|
||||
|
||||
class TFadeSound
|
||||
{
|
||||
PSound Sound = nullptr;
|
||||
float fFade = 0.0f;
|
||||
float dt = 0.0f,
|
||||
fTime = 0.0f;
|
||||
TSoundState State = ss_Off;
|
||||
|
||||
public:
|
||||
TFadeSound();
|
||||
~TFadeSound();
|
||||
void Init(std::string const &Name, float fNewFade);
|
||||
void TurnOn();
|
||||
void TurnOff();
|
||||
bool Playing()
|
||||
{
|
||||
return (State == ss_Commencing || State == ss_Starting);
|
||||
};
|
||||
void Free();
|
||||
void Update();
|
||||
void Volume(long vol);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
@@ -121,7 +121,7 @@ class TDynamicObject;
|
||||
class TAnimModel; // obiekt terenu
|
||||
class cParser; // nowy (powolny!) parser
|
||||
class TEvent;
|
||||
class TTextSound;
|
||||
class sound;
|
||||
|
||||
class TTranscript
|
||||
{ // klasa obsługująca linijkę napisu do dźwięku
|
||||
@@ -320,7 +320,7 @@ class Global
|
||||
static float4 UITextColor; // base color of UI text
|
||||
static std::string asLang; // domyślny język - http://tools.ietf.org/html/bcp47
|
||||
static int iHiddenEvents; // czy łączyć eventy z torami poprzez nazwę toru
|
||||
static TTextSound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk)
|
||||
static sound *tsRadioBusy[10]; // zajętość kanałów radiowych (wskaźnik na odgrywany dźwięk)
|
||||
static int iPoKeysPWM[7]; // numery wejść dla PWM
|
||||
|
||||
//randomizacja
|
||||
|
||||
28
Ground.cpp
28
Ground.cpp
@@ -26,7 +26,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "TractionPower.h"
|
||||
#include "Traction.h"
|
||||
#include "Track.h"
|
||||
#include "RealSound.h"
|
||||
#include "AnimModel.h"
|
||||
#include "MemCell.h"
|
||||
#include "mtable.h"
|
||||
@@ -38,13 +37,16 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Names.h"
|
||||
#include "World.h"
|
||||
#include "uilayer.h"
|
||||
#include "sound.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C"
|
||||
{
|
||||
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound
|
||||
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window );
|
||||
}
|
||||
#endif
|
||||
|
||||
bool bCondition; // McZapkie: do testowania warunku na event multiple
|
||||
std::string LogComment;
|
||||
@@ -231,13 +233,6 @@ void TGroundNode::RenderHidden()
|
||||
double mgn = SquareMagnitude(pCenter - Global::pCameraPosition);
|
||||
switch (iType)
|
||||
{
|
||||
case TP_SOUND: // McZapkie - dzwiek zapetlony w zaleznosci od odleglosci
|
||||
if ((tsStaticSound->GetStatus() & DSBSTATUS_PLAYING) == DSBPLAY_LOOPING)
|
||||
{
|
||||
tsStaticSound->Play(1, DSBPLAY_LOOPING, true, tsStaticSound->vSoundPosition);
|
||||
tsStaticSound->AdjFreq(1.0, Timer::GetDeltaTime());
|
||||
}
|
||||
return;
|
||||
case TP_EVLAUNCH:
|
||||
if (EvLaunch->Render())
|
||||
if ((EvLaunch->dRadius < 0) || (mgn < EvLaunch->dRadius))
|
||||
@@ -1060,8 +1055,11 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
//str = AnsiString(token.c_str());
|
||||
tmp->tsStaticSound = new TTextSound(str, sqrt(tmp->fSquareRadius), tmp->pCenter.x, tmp->pCenter.y, tmp->pCenter.z, false, false, rmin);
|
||||
|
||||
tmp->tsStaticSound = sound_man->create_text_sound(str);
|
||||
if (tmp->tsStaticSound)
|
||||
tmp->tsStaticSound->position(tmp->pCenter).dist(sqrt(tmp->fSquareRadius));
|
||||
|
||||
if (rmin < 0.0)
|
||||
rmin = 0.0; // przywrócenie poprawnej wartości, jeśli służyła do wyłączenia efektu Dopplera
|
||||
parser->getTokens();
|
||||
@@ -3183,15 +3181,13 @@ bool TGround::CheckQuery()
|
||||
switch (tmpEvent->Params[0].asInt)
|
||||
{ // trzy możliwe przypadki:
|
||||
case 0:
|
||||
tmpEvent->Params[9].tsTextSound->Stop();
|
||||
tmpEvent->Params[9].tsTextSound->stop();
|
||||
break;
|
||||
case 1:
|
||||
tmpEvent->Params[9].tsTextSound->Play(
|
||||
1, 0, true, tmpEvent->Params[9].tsTextSound->vSoundPosition);
|
||||
tmpEvent->Params[9].tsTextSound->play();
|
||||
break;
|
||||
case -1:
|
||||
tmpEvent->Params[9].tsTextSound->Play(
|
||||
1, DSBPLAY_LOOPING, true, tmpEvent->Params[9].tsTextSound->vSoundPosition);
|
||||
tmpEvent->Params[9].tsTextSound->play();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
2
Ground.h
2
Ground.h
@@ -123,7 +123,7 @@ public:
|
||||
TEventLauncher *EvLaunch; // wyzwalacz zdarzeń
|
||||
TTraction *hvTraction; // drut zasilający
|
||||
TTractionPowerSource *psTractionPowerSource; // zasilanie drutu (zaniedbane w sceneriach)
|
||||
TTextSound *tsStaticSound; // dźwięk przestrzenny
|
||||
sound *tsStaticSound; // dźwięk przestrzenny
|
||||
TGroundNode *nNode; // obiekt renderujący grupowo ma tu wskaźnik na listę obiektów
|
||||
};
|
||||
Math3D::vector3 pCenter; // współrzędne środka do przydzielenia sektora
|
||||
|
||||
278
RealSound.cpp
278
RealSound.cpp
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/*
|
||||
MaSzyna EU07 locomotive simulator
|
||||
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
|
||||
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "RealSound.h"
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
//#include "math.h"
|
||||
#include "Timer.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
#include "usefull.h"
|
||||
|
||||
TRealSound::TRealSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic,
|
||||
bool freqmod, double rmin)
|
||||
{
|
||||
Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin);
|
||||
}
|
||||
|
||||
TRealSound::~TRealSound()
|
||||
{
|
||||
// if (this) if (pSound) pSound->Stop();
|
||||
}
|
||||
|
||||
void TRealSound::Free()
|
||||
{
|
||||
}
|
||||
|
||||
void TRealSound::Init(std::string const &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: " + 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: " + 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 TRealSound::ListenerDistance(vector3 ListenerPosition)
|
||||
{
|
||||
if (dSoundAtt == -1)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SquareMagnitude(ListenerPosition - vSoundPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void TRealSound::Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition)
|
||||
{
|
||||
if (!pSound)
|
||||
return;
|
||||
long int vol;
|
||||
double dS = 0.0;
|
||||
// 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 TRealSound::Start(){
|
||||
// włączenie dźwięku
|
||||
|
||||
};
|
||||
|
||||
void 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 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;
|
||||
if ((Global::bSoundEnabled) && (AM != 0) && (pSound != nullptr))
|
||||
{
|
||||
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( clamp( df, static_cast<float>(DSBFREQUENCY_MIN), static_cast<float>(DSBFREQUENCY_MAX) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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 TRealSound::ResetPosition()
|
||||
{
|
||||
if (pSound) // Ra: znowu jakiś badziew!
|
||||
pSound->SetCurrentPosition(0);
|
||||
}
|
||||
|
||||
TTextSound::TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z,
|
||||
bool Dynamic, bool freqmod, double rmin)
|
||||
: TRealSound(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin)
|
||||
{
|
||||
Init(SoundName, SoundAttenuation, X, Y, Z, Dynamic, freqmod, rmin);
|
||||
}
|
||||
|
||||
void TTextSound::Init(std::string const &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();
|
||||
std::string txt(SoundName);
|
||||
txt.erase( txt.rfind( '.' ) ); // obcięcie rozszerzenia
|
||||
for (size_t 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;
|
||||
*/ std::ifstream inputfile( txt );
|
||||
asText.assign( std::istreambuf_iterator<char>( inputfile ), std::istreambuf_iterator<char>() );
|
||||
}
|
||||
};
|
||||
void TTextSound::Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition)
|
||||
{
|
||||
if (false == asText.empty())
|
||||
{ // jeśli ma powiązany tekst
|
||||
DWORD stat;
|
||||
pSound->GetStatus(&stat);
|
||||
if (!(stat & DSBSTATUS_PLAYING)) {
|
||||
// jeśli nie jest aktualnie odgrywany
|
||||
Global::tranTexts.Add( asText, fTime, true );
|
||||
}
|
||||
}
|
||||
TRealSound::Play(Volume, Looping, ListenerInside, NewPosition);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
83
RealSound.h
83
RealSound.h
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef RealSoundH
|
||||
#define RealSoundH
|
||||
|
||||
#include <string>
|
||||
#include "Sound.h"
|
||||
#include "geometry.h"
|
||||
|
||||
class TRealSound
|
||||
{
|
||||
protected:
|
||||
PSound pSound = nullptr;
|
||||
// char *Nazwa; // dla celow odwszawiania NOTE: currently not used anywhere
|
||||
double fDistance = 0.0,
|
||||
fPreviousDistance = 0.0; // dla liczenia Dopplera
|
||||
float fFrequency = 22050.0; // częstotliwość samplowania pliku
|
||||
int iDoppler = 0; // Ra 2014-07: możliwość wyłączenia efektu Dopplera np. dla śpiewu ptaków
|
||||
public:
|
||||
vector3 vSoundPosition; // polozenie zrodla dzwieku
|
||||
double dSoundAtt = -1.0; // odleglosc polowicznego zaniku dzwieku
|
||||
double AM = 0.0; // mnoznik amplitudy
|
||||
double AA = 0.0; // offset amplitudy
|
||||
double FM = 0.0; // mnoznik czestotliwosci
|
||||
double FA = 0.0; // offset czestotliwosci
|
||||
bool bLoopPlay = false; // czy zapętlony dźwięk jest odtwarzany
|
||||
TRealSound() = default;
|
||||
TRealSound( std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic,
|
||||
bool freqmod = false, double rmin = 0.0);
|
||||
~TRealSound();
|
||||
void Free();
|
||||
void Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic,
|
||||
bool freqmod = false, double rmin = 0.0);
|
||||
double ListenerDistance(vector3 ListenerPosition);
|
||||
void Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition);
|
||||
void Start();
|
||||
void Stop();
|
||||
void AdjFreq(double Freq, double dt);
|
||||
void SetPan(int Pan);
|
||||
double GetWaveTime(); // McZapkie TODO: dorobic dla roznych bps
|
||||
int GetStatus();
|
||||
void ResetPosition();
|
||||
// void FreqReset(float f=22050.0) {fFrequency=f;};
|
||||
bool Empty() { return ( pSound == nullptr ); }
|
||||
};
|
||||
|
||||
class TTextSound : public TRealSound
|
||||
{ // dźwięk ze stenogramem
|
||||
std::string asText;
|
||||
float fTime; // czas trwania
|
||||
public:
|
||||
TTextSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z,
|
||||
bool Dynamic, bool freqmod = false, double rmin = 0.0);
|
||||
void Init(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z,
|
||||
bool Dynamic, bool freqmod = false, double rmin = 0.0);
|
||||
void Play(double Volume, int Looping, bool ListenerInside, vector3 NewPosition);
|
||||
};
|
||||
|
||||
class TSynthSound
|
||||
{ // klasa generująca sygnał odjazdu (Rp12, Rp13), potem rozbudować o pracę manewrowego...
|
||||
int iIndex[44]; // indeksy początkowe, gdy mamy kilka wariantów dźwięków składowych
|
||||
// 0..9 - cyfry 0..9
|
||||
// 10..19 - liczby 10..19
|
||||
// 21..29 - dziesiątki (*21==*10?)
|
||||
// 31..39 - setki 100,200,...,800,900
|
||||
// 40 - "tysiąc"
|
||||
// 41 - "tysiące"
|
||||
// 42 - indeksy początkowe dla "odjazd"
|
||||
// 43 - indeksy początkowe dla "gotów"
|
||||
PSound *sSound; // posortowana tablica dźwięków, rozmiar zależny od liczby znalezionych plików
|
||||
// a może zamiast wielu plików/dźwięków zrobić jeden połączony plik i posługiwać się czasem
|
||||
// od..do?
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#endif
|
||||
@@ -1,5 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
#include "WinSound.cpp"
|
||||
#else
|
||||
#include "DummySound.cpp"
|
||||
#endif
|
||||
81
Sound.h
81
Sound.h
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stack>
|
||||
#include <cinttypes>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <dsound.h>
|
||||
#else
|
||||
#define DSBFREQUENCY_MIN 0
|
||||
#define DSBFREQUENCY_MAX 0
|
||||
#define DSBSTATUS_PLAYING 0
|
||||
#define DSBPLAY_LOOPING 0
|
||||
#define DSBVOLUME_MIN 0
|
||||
#define DSBVOLUME_MAX 0
|
||||
struct DSBCAPS
|
||||
{
|
||||
uint16_t dwBufferBytes;
|
||||
uint16_t dwSize;
|
||||
};
|
||||
struct dummysb
|
||||
{
|
||||
void Stop() {}
|
||||
void SetCurrentPosition(int) {}
|
||||
void SetVolume(int) {}
|
||||
void Play(int, int, int) {}
|
||||
void GetStatus(unsigned int *stat) { *stat = 0; }
|
||||
void SetPan(int) {}
|
||||
void SetFrequency(int) {}
|
||||
void GetCaps(DSBCAPS *caps) { caps->dwBufferBytes = 0; }
|
||||
};
|
||||
typedef dummysb* LPDIRECTSOUNDBUFFER;
|
||||
typedef int LPDIRECTSOUNDNOTIFY;
|
||||
typedef int LPDIRECTSOUND;
|
||||
typedef int HWND;
|
||||
#endif
|
||||
|
||||
typedef LPDIRECTSOUNDBUFFER PSound;
|
||||
|
||||
class TSoundContainer
|
||||
{
|
||||
public:
|
||||
int Concurrent;
|
||||
int Oldest;
|
||||
std::string m_name;
|
||||
LPDIRECTSOUNDBUFFER DSBuffer;
|
||||
float fSamplingRate; // częstotliwość odczytana z pliku
|
||||
int iBitsPerSample; // ile bitów na próbkę
|
||||
TSoundContainer *Next;
|
||||
std::stack<LPDIRECTSOUNDBUFFER> DSBuffers;
|
||||
|
||||
TSoundContainer(LPDIRECTSOUND pDS, std::string const &Directory, std::string const &Filename, int NConcurrent);
|
||||
~TSoundContainer();
|
||||
LPDIRECTSOUNDBUFFER GetUnique( LPDIRECTSOUND pDS );
|
||||
};
|
||||
|
||||
class TSoundsManager
|
||||
{
|
||||
private:
|
||||
static LPDIRECTSOUND pDS;
|
||||
static LPDIRECTSOUNDNOTIFY pDSNotify;
|
||||
static TSoundContainer *First;
|
||||
static int Count;
|
||||
|
||||
static TSoundContainer * LoadFromFile( std::string const &Directory, std::string const &FileName, int Concurrent);
|
||||
|
||||
public:
|
||||
~TSoundsManager();
|
||||
static void Init( HWND hWnd );
|
||||
static void Free();
|
||||
static LPDIRECTSOUNDBUFFER GetFromName( std::string const &Name, bool Dynamic, float *fSamplingRate = NULL );
|
||||
static void RestoreAll();
|
||||
};
|
||||
78
Train.h
78
Train.h
@@ -14,8 +14,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Button.h"
|
||||
#include "Gauge.h"
|
||||
#include "Spring.h"
|
||||
#include "AdvSound.h"
|
||||
#include "FadeSound.h"
|
||||
#include "PyInt.h"
|
||||
#include "command.h"
|
||||
|
||||
@@ -99,8 +97,8 @@ class TTrain
|
||||
bool initialize_button(cParser &Parser, std::string const &Label, int const Cabindex);
|
||||
// plays specified sound, or fallback sound if the primary sound isn't presend
|
||||
// NOTE: temporary routine until sound system is sorted out and paired with switches
|
||||
void play_sound( PSound Sound, int const Volume = DSBVOLUME_MAX, DWORD const Flags = 0 );
|
||||
void play_sound( PSound Sound, PSound Fallbacksound, int const Volume, DWORD const Flags );
|
||||
void play_sound( sound* Sound, float gain = 1.0f);
|
||||
void play_sound( sound* Sound, sound* Fallbacksound, float gain = 1.0f );
|
||||
// helper, returns true for EMU with oerlikon brake
|
||||
bool is_eztoer() const;
|
||||
// command handlers
|
||||
@@ -379,48 +377,48 @@ public: // reszta może by?publiczna
|
||||
double fMechRoll;
|
||||
double fMechPitch;
|
||||
|
||||
PSound dsbNastawnikJazdy;
|
||||
PSound dsbNastawnikBocz; // hunter-081211
|
||||
PSound dsbRelay;
|
||||
PSound dsbPneumaticRelay;
|
||||
PSound dsbSwitch;
|
||||
PSound dsbPneumaticSwitch;
|
||||
PSound dsbReverserKey; // hunter-121211
|
||||
sound* dsbNastawnikJazdy = nullptr;
|
||||
sound* dsbNastawnikBocz = nullptr; // hunter-081211
|
||||
sound* dsbRelay = nullptr;
|
||||
sound* dsbPneumaticRelay = nullptr;
|
||||
sound* dsbSwitch = nullptr;
|
||||
sound* dsbPneumaticSwitch = nullptr;
|
||||
sound* dsbReverserKey = nullptr; // hunter-121211
|
||||
|
||||
PSound dsbCouplerAttach; // Ra: w kabinie????
|
||||
PSound dsbCouplerDetach; // Ra: w kabinie???
|
||||
sound* dsbCouplerAttach = nullptr; // Ra: w kabinie????
|
||||
sound* dsbCouplerDetach = nullptr; // Ra: w kabinie???
|
||||
|
||||
PSound dsbDieselIgnition; // Ra: w kabinie???
|
||||
sound* dsbDieselIgnition = nullptr; // Ra: w kabinie???
|
||||
|
||||
PSound dsbDoorClose; // Ra: w kabinie???
|
||||
PSound dsbDoorOpen; // Ra: w kabinie???
|
||||
sound* dsbDoorClose = nullptr; // Ra: w kabinie???
|
||||
sound* dsbDoorOpen = nullptr; // Ra: w kabinie???
|
||||
|
||||
// Winger 010304
|
||||
PSound dsbPantUp;
|
||||
PSound dsbPantDown;
|
||||
sound* dsbPantUp = nullptr;
|
||||
sound* dsbPantDown = nullptr;
|
||||
|
||||
PSound dsbWejscie_na_bezoporow;
|
||||
PSound dsbWejscie_na_drugi_uklad; // hunter-081211: poprawka literowki
|
||||
sound* dsbWejscie_na_bezoporow = nullptr;
|
||||
sound* dsbWejscie_na_drugi_uklad = nullptr; // hunter-081211: poprawka literowki
|
||||
|
||||
// PSound dsbHiss1;
|
||||
// PSound dsbHiss2;
|
||||
// sound* dsbHiss1;
|
||||
// sound* dsbHiss2;
|
||||
|
||||
// McZapkie-280302
|
||||
TRealSound rsBrake;
|
||||
TRealSound rsSlippery;
|
||||
TRealSound rsHiss; // upuszczanie
|
||||
TRealSound rsHissU; // napelnianie
|
||||
TRealSound rsHissE; // nagle
|
||||
TRealSound rsHissX; // fala
|
||||
TRealSound rsHissT; // czasowy
|
||||
TRealSound rsSBHiss;
|
||||
TRealSound rsRunningNoise;
|
||||
TRealSound rsEngageSlippery;
|
||||
TRealSound rsFadeSound;
|
||||
sound* rsBrake = nullptr;
|
||||
sound* rsSlippery = nullptr;
|
||||
sound* rsHiss = nullptr; // upuszczanie
|
||||
sound* rsHissU = nullptr; // napelnianie
|
||||
sound* rsHissE = nullptr; // nagle
|
||||
sound* rsHissX = nullptr; // fala
|
||||
sound* rsHissT = nullptr; // czasowy
|
||||
sound* rsSBHiss = nullptr;
|
||||
sound* rsRunningNoise = nullptr;
|
||||
sound* rsEngageSlippery = nullptr;
|
||||
sound* rsFadeSound = nullptr;
|
||||
|
||||
PSound dsbHasler;
|
||||
PSound dsbBuzzer;
|
||||
PSound dsbSlipAlarm; // Bombardier 011010: alarm przy poslizgu dla 181/182
|
||||
sound* dsbHasler = nullptr;
|
||||
sound* dsbBuzzer = nullptr;
|
||||
sound* dsbSlipAlarm = nullptr; // Bombardier 011010: alarm przy poslizgu dla 181/182
|
||||
// TFadeSound sConverter; //przetwornica
|
||||
// TFadeSound sSmallCompressor; //przetwornica
|
||||
|
||||
@@ -432,10 +430,10 @@ public: // reszta może by?publiczna
|
||||
vector3 MirrorPosition(bool lewe);
|
||||
|
||||
private:
|
||||
// PSound dsbBuzzer;
|
||||
PSound dsbCouplerStretch;
|
||||
PSound dsbEN57_CouplerStretch;
|
||||
PSound dsbBufferClamp;
|
||||
// sound* dsbBuzzer;
|
||||
sound* dsbCouplerStretch = nullptr;
|
||||
sound* dsbEN57_CouplerStretch = nullptr;
|
||||
sound* dsbBufferClamp = nullptr;
|
||||
// TSubModel *smCzuwakShpOn;
|
||||
// TSubModel *smCzuwakOn;
|
||||
// TSubModel *smShpOn;
|
||||
|
||||
26
World.cpp
26
World.cpp
@@ -21,7 +21,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "renderer.h"
|
||||
#include "Timer.h"
|
||||
#include "mtable.h"
|
||||
#include "Sound.h"
|
||||
#include "sound.h"
|
||||
#include "Camera.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "Event.h"
|
||||
@@ -217,7 +217,7 @@ TWorld::~TWorld()
|
||||
Global::bManageNodes = false; // Ra: wyłączenie wyrejestrowania, bo się sypie
|
||||
TrainDelete();
|
||||
// Ground.Free(); //Ra: usunięcie obiektów przed usunięciem dźwięków - sypie się
|
||||
TSoundsManager::Free();
|
||||
delete sound_man;
|
||||
TModelsManager::Free();
|
||||
}
|
||||
|
||||
@@ -304,12 +304,9 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
|
||||
std::shared_ptr<ui_panel> initpanel = std::make_shared<ui_panel>(85, 600);
|
||||
|
||||
#ifdef _WIN32
|
||||
TSoundsManager::Init( glfwGetWin32Window( window ) );
|
||||
#else
|
||||
TSoundsManager::Init( 0 );
|
||||
#endif
|
||||
sound_man = new sound_manager();
|
||||
WriteLog("Sound Init OK");
|
||||
|
||||
TModelsManager::Init();
|
||||
WriteLog("Models init OK");
|
||||
|
||||
@@ -760,8 +757,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
temp->MoverParameters->DecBrakeMult())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->dsbSwitch->SetVolume(DSBVOLUME_MAX);
|
||||
Train->dsbSwitch->Play(0, 0, 0);
|
||||
Train->dsbSwitch->gain(1.0f).play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -790,8 +786,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
tmp->iLights[CouplNr] = (tmp->iLights[CouplNr] & ~mask) | set;
|
||||
if (Train)
|
||||
{ // Ra: ten dźwięk z kabiny to przegięcie, ale na razie zostawiam
|
||||
Train->dsbSwitch->SetVolume(DSBVOLUME_MAX);
|
||||
Train->dsbSwitch->Play(0, 0, 0);
|
||||
Train->dsbSwitch->gain(1.0f).play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -811,8 +806,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if (temp->MoverParameters->IncLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->dsbPneumaticRelay->SetVolume(-80);
|
||||
Train->dsbPneumaticRelay->Play(0, 0, 0);
|
||||
Train->dsbPneumaticRelay->gain(0.5f).play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -831,8 +825,7 @@ void TWorld::OnKeyDown(int cKey)
|
||||
if (temp->MoverParameters->DecLocalBrakeLevelFAST())
|
||||
if (Train)
|
||||
{ // dźwięk oczywiście jest w kabinie
|
||||
Train->dsbPneumaticRelay->SetVolume(-80);
|
||||
Train->dsbPneumaticRelay->Play(0, 0, 0);
|
||||
Train->dsbPneumaticRelay->gain(0.5f).play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1125,6 +1118,9 @@ bool TWorld::Update()
|
||||
|
||||
dt = Timer::GetDeltaRenderTime(); // nie uwzględnia pauzowania ani mnożenia czasu
|
||||
|
||||
sound_man->set_listener(Camera.Pos, Camera.LookAt, Camera.vUp);
|
||||
sound_man->update(dt);
|
||||
|
||||
// fixed step render time routines
|
||||
|
||||
fTime50Hz += dt; // w pauzie też trzeba zliczać czas, bo przy dużym FPS będzie problem z odczytem ramek
|
||||
|
||||
@@ -11,5 +11,9 @@ cmake ../.. -T v140_xp ^
|
||||
-DPNG_PNG_INCLUDE_DIR=%DEPS_DIR%/libpng/include ^
|
||||
-DPNG_LIBRARY=%DEPS_DIR%/libpng/lib/win32/libpng16.lib ^
|
||||
-DZLIB_INCLUDE_DIR=%DEPS_DIR%/zlib-1.2.11 ^
|
||||
-DGLM_ROOT_DIR=%DEPS_DIR%/glm-0.9.8.4
|
||||
-DGLM_ROOT_DIR=%DEPS_DIR%/glm-0.9.8.4 ^
|
||||
-DOPENAL_INCLUDE_DIR=%DEPS_DIR%/openal/include ^
|
||||
-DOPENAL_LIBRARY=%DEPS_DIR%/openal/lib/win32/OpenAL32.lib ^
|
||||
-DLIBSNDFILE_INCLUDE_DIR=%DEPS_DIR%/libsndfile/include ^
|
||||
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win32/libsndfile-1.lib
|
||||
popd
|
||||
@@ -11,5 +11,9 @@ cmake ../.. -A x64 ^
|
||||
-DPNG_PNG_INCLUDE_DIR=%DEPS_DIR%/libpng/include ^
|
||||
-DPNG_LIBRARY=%DEPS_DIR%/libpng/lib/win64/libpng16.lib ^
|
||||
-DZLIB_INCLUDE_DIR=%DEPS_DIR%/zlib-1.2.11 ^
|
||||
-DGLM_ROOT_DIR=%DEPS_DIR%/glm-0.9.8.4
|
||||
-DGLM_ROOT_DIR=%DEPS_DIR%/glm-0.9.8.4 ^
|
||||
-DOPENAL_INCLUDE_DIR=%DEPS_DIR%/openal/include ^
|
||||
-DOPENAL_LIBRARY=%DEPS_DIR%/openal/lib/win64/OpenAL32.lib ^
|
||||
-DLIBSNDFILE_INCLUDE_DIR=%DEPS_DIR%/libsndfile/include ^
|
||||
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win64/libsndfile-1.lib
|
||||
popd
|
||||
@@ -1,2 +1,2 @@
|
||||
powershell "$wc = New-Object System.Net.WebClient; $wc.DownloadFile(\"https://milek7.pl/.stuff/eu07exe/builddep1.zip\", \"%cd%\deps_win.zip\")"
|
||||
powershell "$wc = New-Object System.Net.WebClient; $wc.DownloadFile(\"https://milek7.pl/.stuff/eu07exe/builddep2.zip\", \"%cd%\deps_win.zip\")"
|
||||
powershell "$s = New-Object -ComObject shell.application; $z = $s.Namespace(\"%cd%\deps_win.zip\"); foreach ($i in $z.items()) { $s.Namespace(\"%cd%\").CopyHere($i) }"
|
||||
561
sound.cpp
Normal file
561
sound.cpp
Normal file
@@ -0,0 +1,561 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "McZapkie/mctools.h"
|
||||
#include "Globals.h"
|
||||
#include "sound.h"
|
||||
#include "Logs.h"
|
||||
#include <sndfile.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
|
||||
load_error::load_error(std::string const &f) : std::runtime_error("sound: cannot find " + f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
sound_manager::sound_manager()
|
||||
{
|
||||
dev = alcOpenDevice(0);
|
||||
if (!dev)
|
||||
throw std::runtime_error("sound: cannot open device");
|
||||
|
||||
ALCint attr[3] = { ALC_MONO_SOURCES, 20000, 0 };
|
||||
// we're requesting horrible max amount of sources here
|
||||
// because we create AL source object for each sound object,
|
||||
// even if not active currently. considier creating AL source
|
||||
// object only when source is played and destroying it afterwards
|
||||
|
||||
ctx = alcCreateContext(dev, attr);
|
||||
if (!ctx)
|
||||
throw std::runtime_error("sound: cannot create context");
|
||||
|
||||
if (!alcMakeContextCurrent(ctx))
|
||||
throw std::runtime_error("sound: cannot select context");
|
||||
|
||||
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
|
||||
|
||||
alGetError();
|
||||
}
|
||||
|
||||
sound_manager::~sound_manager()
|
||||
{
|
||||
alcMakeContextCurrent(0);
|
||||
alcDestroyContext(ctx);
|
||||
alcCloseDevice(dev);
|
||||
}
|
||||
|
||||
sound_buffer* sound_manager::find_buffer(std::string name)
|
||||
{
|
||||
name.erase(name.rfind('.'));
|
||||
std::replace(name.begin(), name.end(), '\\', '/');
|
||||
|
||||
auto search = buffers.find(name);
|
||||
if (search != buffers.end())
|
||||
return search->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string sound_manager::find_file(std::string name)
|
||||
{
|
||||
if (FileExists(name))
|
||||
return name;
|
||||
|
||||
name.erase(name.rfind('.'));
|
||||
std::vector<std::string> exts { ".wav", ".flac", ".ogg" };
|
||||
for (auto const &ext : exts)
|
||||
if (FileExists(name + ext))
|
||||
return name + ext;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
sound_buffer* sound_manager::get_buffer(std::string const &name)
|
||||
{
|
||||
sound_buffer* buf = find_buffer(Global::asCurrentDynamicPath + name);
|
||||
if (buf)
|
||||
return buf;
|
||||
|
||||
buf = find_buffer("sounds/" + name);
|
||||
if (buf)
|
||||
return buf;
|
||||
|
||||
std::string file = find_file(Global::asCurrentDynamicPath + name);
|
||||
if (!file.size())
|
||||
file = find_file("sounds/" + name);
|
||||
|
||||
if (!file.size())
|
||||
throw load_error(name);
|
||||
|
||||
std::replace(file.begin(), file.end(), '\\', '/');
|
||||
|
||||
buf = new sound_buffer(file);
|
||||
|
||||
file.erase(file.rfind('.'));
|
||||
buffers.emplace(file, buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
simple_sound* sound_manager::create_sound(std::string const &file)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteLog("creating source with " + file);
|
||||
simple_sound *s = new simple_sound(get_buffer(file));
|
||||
sounds.emplace(s);
|
||||
return s;
|
||||
}
|
||||
catch (load_error& e)
|
||||
{
|
||||
WriteLog(e.what());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
text_sound* sound_manager::create_text_sound(std::string const &file)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteLog("creating source with " + file);
|
||||
text_sound *s = new text_sound(get_buffer(file));
|
||||
sounds.emplace(s);
|
||||
return s;
|
||||
}
|
||||
catch (load_error& e)
|
||||
{
|
||||
WriteLog(e.what());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
complex_sound* sound_manager::create_complex_sound(std::string const &pre, std::string const &main, std::string const &post)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteLog("creating source with " + pre + ", " + main + ", " + post);
|
||||
complex_sound *s = new complex_sound(get_buffer(pre), get_buffer(main), get_buffer(post));
|
||||
sounds.emplace(s);
|
||||
return s;
|
||||
}
|
||||
catch (load_error& e)
|
||||
{
|
||||
WriteLog(e.what());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
complex_sound* sound_manager::create_complex_sound(cParser &parser)
|
||||
{
|
||||
std::string pre, main, post;
|
||||
double attenuation;
|
||||
|
||||
parser.getTokens(3, true, "\n\t ;,"); // samples separated with commas
|
||||
parser >> pre >> main >> post;
|
||||
parser.getTokens(1, false);
|
||||
parser >> attenuation;
|
||||
|
||||
complex_sound* s = create_complex_sound(pre, main, post);
|
||||
if (s)
|
||||
s->dist(attenuation);
|
||||
return s;
|
||||
}
|
||||
|
||||
void sound_manager::destroy_sound(sound **s)
|
||||
{
|
||||
if (*s != nullptr)
|
||||
{
|
||||
sounds.erase(*s);
|
||||
delete *s;
|
||||
*s = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void sound_manager::update(float dt)
|
||||
{
|
||||
ALenum err = alGetError();
|
||||
if (err != AL_NO_ERROR)
|
||||
{
|
||||
std::string errname;
|
||||
if (err == AL_INVALID_NAME)
|
||||
errname = "AL_INVALID_NAME";
|
||||
else if (err == AL_INVALID_ENUM)
|
||||
errname = "AL_INVALID_ENUM";
|
||||
else if (err == AL_INVALID_VALUE)
|
||||
errname = "AL_INVALID_VALUE";
|
||||
else if (err == AL_INVALID_OPERATION)
|
||||
errname = "AL_INVALID_OPERATION";
|
||||
else if (err == AL_OUT_OF_MEMORY)
|
||||
errname = "AL_OUT_OF_MEMORY";
|
||||
else
|
||||
errname = "?";
|
||||
|
||||
throw std::runtime_error("sound: al error: " + errname);
|
||||
}
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto it = buffers.begin();
|
||||
while (it != buffers.end())
|
||||
{
|
||||
if (now - it->second->unused_since() > gc_time)
|
||||
{
|
||||
delete it->second;
|
||||
it = buffers.erase(it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
glm::vec3 velocity = (pos - last_pos) / dt;
|
||||
alListenerfv(AL_VELOCITY, glm::value_ptr(velocity));
|
||||
last_pos = pos;
|
||||
|
||||
for (auto &s : sounds)
|
||||
s->update(dt);
|
||||
}
|
||||
|
||||
void sound_manager::set_listener(glm::vec3 const &p, glm::vec3 const &at, glm::vec3 const &up)
|
||||
{
|
||||
pos = p;
|
||||
alListenerfv(AL_POSITION, glm::value_ptr(p));
|
||||
glm::vec3 ori[] = { at, up };
|
||||
alListenerfv(AL_ORIENTATION, (ALfloat*)ori);
|
||||
}
|
||||
|
||||
void sound_manager::set_listener(Math3D::vector3 const &p, Math3D::vector3 const &at, Math3D::vector3 const &up)
|
||||
{
|
||||
set_listener((glm::vec3)glm::make_vec3(&p.x), (glm::vec3)glm::make_vec3(&at.x), (glm::vec3)glm::make_vec3(&up.x));
|
||||
}
|
||||
|
||||
sound::sound()
|
||||
{
|
||||
id = 0;
|
||||
alGenSources(1, &id);
|
||||
if (!id)
|
||||
throw std::runtime_error("sound: cannot generate source");
|
||||
alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
dist(5.0f * 3.82f);
|
||||
spatial = false;
|
||||
gain_off = 0.0f;
|
||||
gain_mul = 1.0f;
|
||||
pitch_off = 0.0f;
|
||||
pitch_mul = 1.0f;
|
||||
}
|
||||
|
||||
simple_sound::simple_sound(sound_buffer *buf) : sound::sound()
|
||||
{
|
||||
looping = false;
|
||||
playing = false;
|
||||
buffer = buf;
|
||||
alSourcei(id, AL_BUFFER, buffer->get_id());
|
||||
buffer->ref();
|
||||
}
|
||||
|
||||
sound::~sound()
|
||||
{
|
||||
alDeleteSources(1, &id);
|
||||
}
|
||||
|
||||
simple_sound::~simple_sound()
|
||||
{
|
||||
buffer->unref();
|
||||
}
|
||||
|
||||
sound& sound::position(glm::vec3 const &p)
|
||||
{
|
||||
if (!spatial)
|
||||
{
|
||||
alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
spatial = true;
|
||||
last_pos = p;
|
||||
}
|
||||
|
||||
if (p != pos)
|
||||
{
|
||||
pos = p;
|
||||
pos_dirty = true;
|
||||
|
||||
alSourcefv(id, AL_POSITION, glm::value_ptr(p));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
sound& sound::position(Math3D::vector3 const &pos)
|
||||
{
|
||||
position((glm::vec3)glm::make_vec3(&pos.x));
|
||||
return *this;
|
||||
}
|
||||
|
||||
sound& sound::dist(float dist)
|
||||
{
|
||||
max_dist = dist;
|
||||
alSourcef(id, AL_MAX_DISTANCE, dist);
|
||||
alSourcef(id, AL_REFERENCE_DISTANCE, dist / 3.82f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void simple_sound::play()
|
||||
{
|
||||
if (playing || (spatial && glm::distance(pos, sound_man->pos) > max_dist))
|
||||
return;
|
||||
|
||||
alSourcePlay(id);
|
||||
playing = true;
|
||||
}
|
||||
|
||||
void simple_sound::stop()
|
||||
{
|
||||
if (!playing)
|
||||
return;
|
||||
|
||||
alSourceStop(id);
|
||||
playing = false;
|
||||
}
|
||||
|
||||
void sound::update(float dt)
|
||||
{
|
||||
if (spatial && pos_dirty)
|
||||
{
|
||||
glm::vec3 velocity = (pos - last_pos) / dt; // m/s
|
||||
alSourcefv(id, AL_VELOCITY, glm::value_ptr(velocity));
|
||||
last_pos = pos;
|
||||
pos_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void simple_sound::update(float dt)
|
||||
{
|
||||
sound::update(dt);
|
||||
|
||||
if (playing)
|
||||
{
|
||||
ALint v;
|
||||
alGetSourcei(id, AL_SOURCE_STATE, &v);
|
||||
if (v != AL_PLAYING)
|
||||
playing = false;
|
||||
else if (spatial && glm::distance(pos, sound_man->pos) > max_dist)
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
sound& sound::gain(float gain)
|
||||
{
|
||||
gain = std::min(std::max(0.0f, gain * gain_mul + gain_off), 1.0f);
|
||||
alSourcef(id, AL_GAIN, gain);
|
||||
return *this;
|
||||
}
|
||||
|
||||
sound& sound::pitch(float pitch)
|
||||
{
|
||||
pitch = std::min(std::max(0.05f, pitch * pitch_mul + pitch_off), 20.0f);
|
||||
alSourcef(id, AL_PITCH, pitch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
sound& simple_sound::loop(bool loop)
|
||||
{
|
||||
if (loop != looping)
|
||||
{
|
||||
alSourcei(id, AL_LOOPING, (ALint)loop);
|
||||
looping = loop;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool simple_sound::is_playing()
|
||||
{
|
||||
return playing;
|
||||
}
|
||||
|
||||
//m7todo: implement text_sound
|
||||
text_sound::text_sound(sound_buffer *buf) : simple_sound::simple_sound(buf)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void text_sound::play()
|
||||
{
|
||||
simple_sound::play();
|
||||
}
|
||||
|
||||
complex_sound::complex_sound(sound_buffer* pre, sound_buffer* main, sound_buffer* post) : sound::sound()
|
||||
{
|
||||
this->pre = pre;
|
||||
this->buffer = main;
|
||||
this->post = post;
|
||||
|
||||
pre->ref();
|
||||
buffer->ref();
|
||||
post->ref();
|
||||
|
||||
cs = state::post;
|
||||
}
|
||||
|
||||
complex_sound::~complex_sound()
|
||||
{
|
||||
pre->unref();
|
||||
buffer->unref();
|
||||
post->unref();
|
||||
}
|
||||
|
||||
void complex_sound::play()
|
||||
{
|
||||
if (cs != state::post)
|
||||
return;
|
||||
|
||||
if (spatial && glm::distance(pos, sound_man->pos) > max_dist)
|
||||
return;
|
||||
|
||||
alSourceRewind(id);
|
||||
|
||||
alSourcei(id, AL_LOOPING, AL_FALSE);
|
||||
alSourcei(id, AL_BUFFER, 0);
|
||||
ALuint buffers[] = { pre->get_id(), buffer->get_id() };
|
||||
alSourceQueueBuffers(id, 2, buffers);
|
||||
|
||||
alSourcePlay(id);
|
||||
|
||||
cs = state::premain;
|
||||
}
|
||||
|
||||
void complex_sound::stop()
|
||||
{
|
||||
if (cs == state::main)
|
||||
{
|
||||
alSourceRewind(id);
|
||||
|
||||
alSourcei(id, AL_LOOPING, AL_FALSE);
|
||||
alSourcei(id, AL_BUFFER, 0);
|
||||
alSourcei(id, AL_BUFFER, post->get_id());
|
||||
|
||||
alSourcePlay(id);
|
||||
|
||||
cs = state::post;
|
||||
}
|
||||
else if (cs == state::premain)
|
||||
cs = state::prepost;
|
||||
}
|
||||
|
||||
void complex_sound::update(float dt)
|
||||
{
|
||||
sound::update(dt);
|
||||
|
||||
if (cs == state::premain || cs == state::prepost)
|
||||
{
|
||||
ALint processed;
|
||||
alGetSourcei(id, AL_BUFFERS_PROCESSED, &processed);
|
||||
if (processed > 0) // already processed pre
|
||||
{
|
||||
if (cs == state::premain)
|
||||
{
|
||||
cs = state::main;
|
||||
|
||||
ALuint pre_id = pre->get_id();
|
||||
alSourceUnqueueBuffers(id, 1, &pre_id);
|
||||
alSourcei(id, AL_LOOPING, AL_TRUE);
|
||||
if (processed > 1) // underrun occured
|
||||
alSourcePlay(id);
|
||||
|
||||
}
|
||||
else if (cs == state::prepost)
|
||||
{
|
||||
cs = state::main;
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cs == state::main)
|
||||
if (spatial && glm::distance(pos, sound_man->pos) > max_dist)
|
||||
stop();
|
||||
}
|
||||
|
||||
sound& complex_sound::loop(bool loop)
|
||||
{
|
||||
throw std::runtime_error("cannot loop complex_sound");
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool complex_sound::is_playing()
|
||||
{
|
||||
return cs != state::post; // almost accurate
|
||||
}
|
||||
|
||||
sound_buffer::sound_buffer(std::string &file)
|
||||
{
|
||||
WriteLog("creating sound buffer from " + file);
|
||||
|
||||
SF_INFO si;
|
||||
si.format = 0;
|
||||
|
||||
SNDFILE *sf = sf_open(file.c_str(), SFM_READ, &si);
|
||||
if (sf == nullptr)
|
||||
throw std::runtime_error("sound: sf_open failed");
|
||||
|
||||
int16_t *fbuf = new int16_t[si.frames * si.channels];
|
||||
if (sf_readf_short(sf, fbuf, si.frames) != si.frames)
|
||||
throw std::runtime_error("sound: incomplete file");
|
||||
|
||||
sf_close(sf);
|
||||
|
||||
int16_t *buf = nullptr;
|
||||
if (si.channels == 1)
|
||||
buf = fbuf;
|
||||
else
|
||||
{
|
||||
WriteLog("sound: warning: mixing multichannel file to mono");
|
||||
buf = new int16_t[si.frames];
|
||||
for (size_t i = 0; i < si.frames; i++)
|
||||
{
|
||||
int32_t accum = 0;
|
||||
for (size_t j = 0; j < si.channels; j++)
|
||||
accum += fbuf[i * si.channels + j];
|
||||
buf[i] = accum / si.channels;
|
||||
}
|
||||
}
|
||||
|
||||
id = 0;
|
||||
alGenBuffers(1, &id);
|
||||
if (!id)
|
||||
throw std::runtime_error("sound: cannot generate buffer");
|
||||
|
||||
alBufferData(id, AL_FORMAT_MONO16, buf, si.frames * 2, si.samplerate);
|
||||
|
||||
if (si.channels != 1)
|
||||
delete[] buf;
|
||||
delete[] fbuf;
|
||||
}
|
||||
|
||||
sound_buffer::~sound_buffer()
|
||||
{
|
||||
alDeleteBuffers(1, &id);
|
||||
}
|
||||
|
||||
void sound_buffer::ref()
|
||||
{
|
||||
refcount++;
|
||||
}
|
||||
|
||||
void sound_buffer::unref()
|
||||
{
|
||||
refcount--;
|
||||
last_unref = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
ALuint sound_buffer::get_id()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> sound_buffer::unused_since()
|
||||
{
|
||||
if (refcount > 0)
|
||||
return std::chrono::time_point<std::chrono::steady_clock>::max();
|
||||
|
||||
return last_unref;
|
||||
}
|
||||
|
||||
sound_manager* sound_man;
|
||||
160
sound.h
Normal file
160
sound.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <cinttypes>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <glm/glm.hpp>
|
||||
#include "dumb3d.h"
|
||||
#include "parser.h"
|
||||
|
||||
class load_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
load_error(std::string const &f);
|
||||
};
|
||||
|
||||
class sound_buffer
|
||||
{
|
||||
ALuint id;
|
||||
uint32_t refcount;
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_unref;
|
||||
|
||||
public:
|
||||
sound_buffer(std::string &file);
|
||||
~sound_buffer();
|
||||
|
||||
ALuint get_id();
|
||||
void ref();
|
||||
void unref();
|
||||
std::chrono::time_point<std::chrono::steady_clock> unused_since();
|
||||
};
|
||||
|
||||
//m7todo: make constructor/destructor private friend to sound_manager
|
||||
class sound
|
||||
{
|
||||
bool pos_dirty;
|
||||
glm::vec3 last_pos;
|
||||
|
||||
protected:
|
||||
float max_dist;
|
||||
bool spatial;
|
||||
glm::vec3 pos;
|
||||
|
||||
ALuint id;
|
||||
sound();
|
||||
|
||||
public:
|
||||
float gain_off;
|
||||
float gain_mul;
|
||||
float pitch_off;
|
||||
float pitch_mul;
|
||||
|
||||
virtual ~sound();
|
||||
|
||||
virtual bool is_playing() = 0;
|
||||
|
||||
virtual void play() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void update(float dt);
|
||||
|
||||
sound& dist(float);
|
||||
sound& gain(float);
|
||||
sound& pitch(float);
|
||||
virtual sound& loop(bool loop = true) = 0;
|
||||
|
||||
sound& position(glm::vec3 const &);
|
||||
sound& position(Math3D::vector3 const &);
|
||||
};
|
||||
|
||||
class simple_sound : public sound
|
||||
{
|
||||
sound_buffer *buffer;
|
||||
|
||||
bool looping;
|
||||
bool playing;
|
||||
|
||||
public:
|
||||
simple_sound(sound_buffer *buf);
|
||||
~simple_sound();
|
||||
|
||||
void play();
|
||||
void stop();
|
||||
void update(float dt);
|
||||
|
||||
sound& loop(bool loop = true);
|
||||
|
||||
bool is_playing();
|
||||
};
|
||||
|
||||
class complex_sound : public sound
|
||||
{
|
||||
sound_buffer *pre, *buffer, *post;
|
||||
|
||||
enum class state
|
||||
{
|
||||
premain, // playing pre and continue to main
|
||||
prepost, // playing pre and jump to post
|
||||
main, //playing main
|
||||
post // playing post or idling
|
||||
} cs;
|
||||
|
||||
public:
|
||||
complex_sound(sound_buffer* pre, sound_buffer* main, sound_buffer* post);
|
||||
~complex_sound();
|
||||
|
||||
bool is_playing();
|
||||
|
||||
void play();
|
||||
void stop();
|
||||
void update(float dt);
|
||||
|
||||
sound& loop(bool loop = true);
|
||||
};
|
||||
|
||||
class text_sound : public simple_sound
|
||||
{
|
||||
public:
|
||||
text_sound(sound_buffer *buf);
|
||||
|
||||
void play();
|
||||
};
|
||||
|
||||
class sound_manager
|
||||
{
|
||||
ALCdevice *dev;
|
||||
ALCcontext *ctx;
|
||||
|
||||
const std::chrono::duration<float> gc_time = std::chrono::duration<float>(60.0f);
|
||||
std::unordered_map<std::string, sound_buffer*> buffers;
|
||||
std::unordered_set<sound*> sounds;
|
||||
|
||||
std::string find_file(std::string);
|
||||
sound_buffer* find_buffer(std::string);
|
||||
|
||||
sound_buffer* get_buffer(std::string const &);
|
||||
|
||||
public:
|
||||
glm::vec3 pos, last_pos;
|
||||
|
||||
sound_manager();
|
||||
~sound_manager();
|
||||
|
||||
simple_sound* create_sound(std::string const &file);
|
||||
text_sound* create_text_sound(std::string const &file);
|
||||
complex_sound* create_complex_sound(std::string const &pre, std::string const &main, std::string const &post);
|
||||
complex_sound* create_complex_sound(cParser &);
|
||||
void destroy_sound(sound**);
|
||||
|
||||
void update(float dt);
|
||||
void set_listener(glm::vec3 const &pos, glm::vec3 const &at, glm::vec3 const &up);
|
||||
void set_listener(Math3D::vector3 const &pos, Math3D::vector3 const &at, Math3D::vector3 const &up);
|
||||
};
|
||||
|
||||
extern sound_manager* sound_man;
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
ui_layer UILayer;
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C"
|
||||
{
|
||||
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window ); //m7todo: potrzebne do directsound
|
||||
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window );
|
||||
}
|
||||
#endif
|
||||
|
||||
ui_layer::~ui_layer() {
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user