DWORD FmodSoundEngine::PlayMusic(int sound_id, CHANNEL Ichannel, bool loop, float volume) { if(Ichannel<0||Ichannel>=maxChannel) { Ichannel = GetNewChannel(); if(Ichannel<0) return NULL; } FMOD::Sound *sound = (FMOD::Sound*)playMusic[sound_id]; FMOD::Channel **channel = (FMOD::Channel**)this->channel; nowChannel = max(nowChannel,Ichannel+1); if(loop) { result = sound->setMode(FMOD_LOOP_NORMAL); //ERRCHECK(result); } if(Ichannel==0){ float freq; sound->getDefaults(&freq,NULL); music_sampleRate = freq; } result = system->playSound(sound, NULL, true, &channel[Ichannel]); //ERRCHECK(result); volumeDes[Ichannel] = volume*defaultVolume; result = channel[Ichannel]->setVolume(volumeDes[Ichannel]); //ERRCHECK(result); SetPosition(Ichannel, sound_id, 0); //ERRCHECK(result); result = channel[Ichannel]->setPaused(false); //ERRCHECK(result); if(Ichannel==0) Update(0); return (DWORD)sound; }
SPtr<Resource> FMODImporter::import(const Path& filePath, SPtr<const ImportOptions> importOptions) { WString extension = filePath.getWExtension(); StringUtil::toLowerCase(extension); AudioFileInfo info; FMOD::Sound* sound; String pathStr = filePath.toString(); if(gFMODAudio()._getFMOD()->createSound(pathStr.c_str(), FMOD_CREATESAMPLE, nullptr, &sound) != FMOD_OK) { LOGERR("Failed importing audio file: " + pathStr); return nullptr; } FMOD_SOUND_FORMAT format; INT32 numChannels = 0; INT32 numBits = 0; sound->getFormat(nullptr, &format, &numChannels, &numBits); if(format != FMOD_SOUND_FORMAT_PCM8 && format != FMOD_SOUND_FORMAT_PCM16 && format != FMOD_SOUND_FORMAT_PCM24 && format != FMOD_SOUND_FORMAT_PCM32 && format != FMOD_SOUND_FORMAT_PCMFLOAT) { LOGERR("Failed importing audio file, invalid imported format: " + pathStr); return nullptr; } float frequency = 0.0f; sound->getDefaults(&frequency, nullptr); UINT32 size; sound->getLength(&size, FMOD_TIMEUNIT_PCMBYTES); info.bitDepth = numBits; info.numChannels = numChannels; info.sampleRate = (UINT32)frequency; info.numSamples = size / (info.bitDepth / 8); UINT32 bytesPerSample = info.bitDepth / 8; UINT32 bufferSize = info.numSamples * bytesPerSample; UINT8* sampleBuffer = (UINT8*)bs_alloc(bufferSize); assert(bufferSize == size); UINT8* startData = nullptr; UINT8* endData = nullptr; UINT32 startSize = 0; UINT32 endSize = 0; sound->lock(0, size, (void**)&startData, (void**)&endData, &startSize, &endSize); if(format == FMOD_SOUND_FORMAT_PCMFLOAT) { assert(info.bitDepth == 32); UINT32* output = (UINT32*)sampleBuffer; for(UINT32 i = 0; i < info.numSamples; i++) { float value = *(((float*)startData) + i); *output = (UINT32)(value * 2147483647.0f); output++; } } else { memcpy(sampleBuffer, startData, bufferSize); } sound->unlock((void**)&startData, (void**)&endData, startSize, endSize); sound->release(); SPtr<const AudioClipImportOptions> clipIO = std::static_pointer_cast<const AudioClipImportOptions>(importOptions); // If 3D, convert to mono if (clipIO->getIs3D() && info.numChannels > 1) { UINT32 numSamplesPerChannel = info.numSamples / info.numChannels; UINT32 monoBufferSize = numSamplesPerChannel * bytesPerSample; UINT8* monoBuffer = (UINT8*)bs_alloc(monoBufferSize); AudioUtility::convertToMono(sampleBuffer, monoBuffer, info.bitDepth, numSamplesPerChannel, info.numChannels); info.numSamples = numSamplesPerChannel; info.numChannels = 1; bs_free(sampleBuffer); sampleBuffer = monoBuffer; bufferSize = monoBufferSize; } // Convert bit depth if needed if (clipIO->getBitDepth() != info.bitDepth) { UINT32 outBufferSize = info.numSamples * (clipIO->getBitDepth() / 8); UINT8* outBuffer = (UINT8*)bs_alloc(outBufferSize); AudioUtility::convertBitDepth(sampleBuffer, info.bitDepth, outBuffer, clipIO->getBitDepth(), info.numSamples); info.bitDepth = clipIO->getBitDepth(); bs_free(sampleBuffer); sampleBuffer = outBuffer; bufferSize = outBufferSize; } // Encode to Ogg Vorbis if needed if (clipIO->getFormat() == AudioFormat::VORBIS) { // TODO - Encode to Ogg Vorbis! } SPtr<MemoryDataStream> sampleStream = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, bufferSize); AUDIO_CLIP_DESC clipDesc; clipDesc.bitDepth = info.bitDepth; clipDesc.format = clipIO->getFormat(); clipDesc.frequency = info.sampleRate; clipDesc.numChannels = info.numChannels; clipDesc.readMode = clipIO->getReadMode(); clipDesc.is3D = clipIO->getIs3D(); SPtr<AudioClip> clip = AudioClip::_createPtr(sampleStream, bufferSize, info.numSamples, clipDesc); WString fileName = filePath.getWFilename(false); clip->setName(fileName); return clip; }
UBOOL USwFMOD::PlayMusic( UMusic* Music, FMOD::Channel* channel, BYTE SongSection, BYTE CdTrack, EMusicTransition Transition ) { guard(USwFMOD::PlayMusic); //SWF_LOG( NAME_DevSound, TEXT("%s >> %s :: [%s]"), SWF_PLOG, *ToStr(Music), *ToStr(SongSection), *ToStr(CdTrack), *ToStr(Transition) ); FMOD_RESULT result; if( !Music ) return 0; /*if( channel ) { // there can be only one music //SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: StopMusic %s"), SWF_PLOG, *PrintChannel(musicchannel) ); SWF_FMOD_RCALL0( musicchannel->setUserData(NULL) ); SWF_FMOD_RCALL0( musicchannel->stop() ); }*/ // Non-modules use one UMusic object for each SongSection if( Music->FileType == SoundType_OGG || Music->FileType == SoundType_MP2 || Music->FileType == SoundType_MP3 ) { Viewport->Actor->SongSection = 0; FString postfix = GetSongSectionPostfix(SongSection); if( postfix ) { FString objname = FString::Printf( TEXT("%s%s.%s%s"), Music->GetName(), *postfix, Music->GetName(), *postfix); UMusic* newmusic = Cast<UMusic>(StaticLoadObject( Music->GetClass(), NULL, *objname, NULL, LOAD_NoWarn | LOAD_Quiet, NULL )); if( newmusic ) { SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: Dynamic Music: %s"), SWF_PLOG, *ToStr(objname) ); Music = newmusic; Viewport->Actor->SongSection = SongSection; } } SongSection = Viewport->Actor->SongSection; } // Register sample FMOD::Sound* sample = RegisterMusicSample(Music); if( !sample ) return 0; // Sample defaults FLOAT deffrequency; FLOAT defvolume; FLOAT defpanning; INT defpriority; FMOD_MODE fmode; SWF_FMOD_RCALL0( sample->getDefaults( &deffrequency, &defvolume, &defpanning, &defpriority ) ); SWF_FMOD_RCALL0( sample->getMode(&fmode) ); // Channel defaults FMOD::ChannelGroup* channelgroup = MusicChannels; FMOD_CHANNELINDEX channelindex = IsChannelValid(channel) ? FMOD_CHANNEL_REUSE : FMOD_CHANNEL_FREE; FLOAT frequency = deffrequency * 1.0f; FLOAT volume = defvolume * 1.0f; FLOAT panning = defpanning * 1.0f; INT priority = PriorityMusic; // Update FMOD to free finished channels guard(UpdateFMOD); SWF_FMOD_RCALL0( System->update() ); unguard; // Play stream SWF_FMOD_RCALL0( System->playSound(channelindex, sample, true, &channel) ); // SWF_FMOD_RCALL0( VerifyNewChannel(channel) ); // Update channel SWF_FMOD_RCALL0( channel->setUserData(NULL) ); SWF_FMOD_RCALL0( channel->setChannelGroup(channelgroup) ); SWF_FMOD_RCALL0( channel->setMode(fmode) ); if( !HasFlag(fmode,FMOD_3D) ) { SWF_FMOD_RCALL0( channel->setPan(panning) ); } SWF_FMOD_RCALL0( channel->setFrequency(frequency) ); SWF_FMOD_RCALL0( channel->setVolume(volume) ); SWF_FMOD_RCALL0( channel->setPriority(priority) ); // restore position result = channel->setPosition(SongSection,FMOD_TIMEUNIT_MODORDER); FSwPosition pos = MusicPositions(SongSection); if( pos.ms != 0 ) { channel->setPosition(pos.ms,FMOD_TIMEUNIT_MS); } else { // TODO:: doesn't work?! result = channel->setPosition(pos.pattern,FMOD_TIMEUNIT_MODPATTERN); result = channel->setPosition(pos.row,FMOD_TIMEUNIT_MODROW); } SWF_FMOD_RCALL0( channel->setPaused(false) ); // Apply channel group's properties ApplyChannelGroup(channelgroup); // Update immediately Viewport->Actor->SongSection = SongSection; // Update FMOD to apply channel updates immediately guard(UpdateFMOD); SWF_FMOD_RCALL0( System->update() ); unguard; //SWF_LOG( NAME_DevSound, TEXT("%s << %s :: [%s]"), SWF_PLOG, *ToStr(Music), *ToStr(SongSection), *ToStr(CdTrack), *ToStr(Transition) ); return 1; unguard; }
UBOOL USwFMOD::PlaySound ( AActor* Actor, INT Id, USound* Sound, FVector Location, FLOAT Volume, FLOAT Radius, FLOAT Pitch ) { guard(USwFMOD::PlaySound); //SWF_LOG( NAME_DevSound, TEXT("%s >> %s :: [%s],[%s],[%s],[%s],[%s],[%s],[%s]"), SWF_PLOG, *ToStr(FSwSoundId(Id)), *ToStr(Actor,true), *ToStr(Sound), *ToStr(Location), *ToStr(Volume), *ToStr(Radius), *ToStr(Pitch) ); FMOD_RESULT result; if( !Viewport || !Sound ) return 0; // Sound slot rules FSwSoundId SoundId = FSwSoundId(Id); if( SoundId.GetSlot() != SLOT_None ) { for( FSwChannelEnumerator it(System); it; ++it ) { FMOD::Channel* channel = *it; if( IsChannelValid(channel) ) { FSwSoundId cid = GetChannelId(channel); // If Actor is the same and Slot is the same: // - prevent this sound from plaing if NoOverride // - stop the old sound otherwise if( cid.GetSlot() == SoundId.GetSlot() && cid.GetActor() == SoundId.GetActor() ) { if( cid.GetNoOverride() ) { //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: NO OVERRIDE <%s> <%s>"), SWF_PLOG, *ToStr(FSwSoundId(Id)), *PrintChannel(channel) ); return 0; } //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: STOP <%s> <%s>"), SWF_PLOG, *ToStr(SoundId), *PrintChannel(channel) ); SWF_FMOD_CALL( channel->setUserData(NULL) ); SWF_FMOD_CALL( channel->stop() ); } } } } // Register sample FMOD::Sound* sample = RegisterSoundSample(Sound); if( !sample ) return 0; // Sample defaults FLOAT deffrequency; FLOAT defvolume; FLOAT defpanning; INT defpriority; FMOD_MODE fmode; SWF_FMOD_RCALL0( sample->getDefaults( &deffrequency, &defvolume, &defpanning, &defpriority ) ); SWF_FMOD_RCALL0( sample->getMode(&fmode) ); // Channel defaults FMOD::ChannelGroup* channelgroup = EffectChannels; FMOD_CHANNELINDEX channelindex = FMOD_CHANNEL_FREE; FLOAT mindist = ToFMODFloat(DistanceMin); FLOAT radius = ToFMODFloat(Radius); TSwSortMinMax( mindist, radius ); FMOD_VECTOR location = ToFMODVector(Location); FMOD_VECTOR velocity = ToFMODNormal(FVector(0,0,0)); FLOAT frequency = deffrequency * Pitch; FLOAT volume = defvolume * Volume; FLOAT panning = defpanning * 1.0f; INT priority = PrioritySound; // 2D or 3D? AActor* ViewActor = Viewport->Actor->ViewTarget ? Viewport->Actor->ViewTarget : Viewport->Actor; UBOOL bIs3D = Actor && (b3DCameraSounds || Actor != ViewActor); if( bIs3D ) { fmode &= ~FMOD_2D; fmode |= FMOD_3D | FMOD_3D_LINEARROLLOFF; // Radius, location & Velocity FMOD_VECTOR location = ToFMODVector(Actor->Location); FMOD_VECTOR velocity = ToFMODVector(Actor->Velocity); SWF_VERIFY_FLOAT( mindist ); SWF_VERIFY_FLOAT( radius ); SWF_VERIFY_FMODVECTOR( location ); SWF_VERIFY_FMODVECTOR( velocity ); } else { fmode &= ~FMOD_3D; fmode |= FMOD_2D; } // Sound effects other than WAV go into compressed group (conversations most likely) if( Sound->FileType != SoundType_WAV ) { priority = PrioritySpeech; channelgroup = CompressedChannels; //fmode |= FMOD_CREATESTREAM; } // Ambient sounds if( SoundId.GetSlot() == SLOT_Ambient ) { priority = PriorityAmbient; channelgroup = AmbientChannels; fmode &= ~FMOD_LOOP_OFF; fmode |= FMOD_LOOP_NORMAL; } // Update FMOD to free finished channels guard(UpdateFMOD); SWF_FMOD_RCALL0( System->update() ); unguard; // Play sound FMOD::Channel* channel; SWF_FMOD_RCALL0( System->playSound(channelindex, sample, true, &channel) ); // SWF_FMOD_RCALL0( VerifyNewChannel(channel) ); // Update channel SWF_FMOD_RCALL0( channel->setUserData( SoundId.ToUserData() ) ); SWF_FMOD_RCALL0( channel->setChannelGroup(channelgroup) ); SWF_FMOD_RCALL0( channel->setMode(fmode) ); if( HasFlag(fmode,FMOD_3D) ) { SWF_FMOD_RCALL0( channel->set3DMinMaxDistance(mindist, radius) ); SWF_FMOD_RCALL0( channel->set3DAttributes(&location,&velocity) ); } else { SWF_FMOD_RCALL0( channel->setPan(panning) ); } SWF_FMOD_RCALL0( channel->setFrequency(frequency) ); SWF_FMOD_RCALL0( channel->setVolume(volume) ); SWF_FMOD_RCALL0( channel->setPriority(priority) ); SWF_FMOD_RCALL0( channel->setPaused(false) ); // Apply channel group's properties ApplyChannelGroup(channelgroup); // Update FMOD to apply channel updates immediately guard(UpdateFMOD); SWF_FMOD_RCALL0( System->update() ); unguard; //SWF_LOG( NAME_DevSound, TEXT("%s << %s :: [%s],[%s],[%s],[%s],[%s],[%s],[%s]"), SWF_PLOG, *ToStr(Actor,true), *ToStr(Id), *ToStr(Sound), *ToStr(Location), *ToStr(Volume), *ToStr(Radius), *ToStr(Pitch) ); return 1; unguard; }
int FMOD_Main() { FMOD::System *system; FMOD::Sound *sound[3]; FMOD::Channel *channel = 0; FMOD::ChannelGroup *channelgroup = 0; FMOD_RESULT result; unsigned int version, dsp_block_len, count; int outputrate = 0; void *extradriverdata = 0; Common_Init(&extradriverdata); /* Create a System object and initialize. */ result = FMOD::System_Create(&system); ERRCHECK(result); result = system->getVersion(&version); ERRCHECK(result); if (version < FMOD_VERSION) { Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version, FMOD_VERSION); } result = system->init(100, FMOD_INIT_NORMAL, extradriverdata); ERRCHECK(result); /* Get information needed later for scheduling. The mixer block size, and the output rate of the mixer. */ result = system->getDSPBufferSize(&dsp_block_len, 0); ERRCHECK(result); result = system->getSoftwareFormat(&outputrate, 0, 0); ERRCHECK(result); /* Load 3 sounds - these are just sine wave tones at different frequencies. C, D and E on the musical scale. */ result = system->createSound(Common_MediaPath("c.ogg"), FMOD_DEFAULT, 0, &sound[NOTE_C]); ERRCHECK(result); result = system->createSound(Common_MediaPath("d.ogg"), FMOD_DEFAULT, 0, &sound[NOTE_D]); ERRCHECK(result); result = system->createSound(Common_MediaPath("e.ogg"), FMOD_DEFAULT, 0, &sound[NOTE_E]); ERRCHECK(result); /* Create a channelgroup that the channels will play on. We can use this channelgroup as our clock reference. It also means we can pause and pitch bend the channelgroup, without affecting the offsets of the delays, because the channelgroup clock which the channels feed off, will be pausing and speeding up/slowing down and still keeping the children in sync. */ result = system->createChannelGroup("Parent", &channelgroup); ERRCHECK(result); unsigned int numsounds = sizeof(note) / sizeof(note[0]); /* Play all the sounds at once! Space them apart with set delay though so that they sound like they play in order. */ for (count = 0; count < numsounds; count++) { static unsigned long long clock_start = 0; unsigned int slen; FMOD::Sound *s = sound[note[count]]; /* Pick a note from our tune. */ result = system->playSound(s, channelgroup, true, &channel); /* Play the sound on the channelgroup we want to use as the parent clock reference (for setDelay further down) */ ERRCHECK(result); if (!clock_start) { result = channel->getDSPClock(0, &clock_start); ERRCHECK(result); clock_start += (dsp_block_len * 2); /* Start the sound into the future, by 2 mixer blocks worth. */ /* Should be enough to avoid the mixer catching up and hitting the clock value before we've finished setting up everything. */ /* Alternatively the channelgroup we're basing the clock on could be paused to stop it ticking. */ } else { float freq; result = s->getLength(&slen, FMOD_TIMEUNIT_PCM); /* Get the length of the sound in samples. */ ERRCHECK(result); result = s->getDefaults(&freq, 0); /* Get the default frequency that the sound was recorded at. */ ERRCHECK(result); slen = (unsigned int)((float)slen / freq * outputrate); /* Convert the length of the sound to 'output samples' for the output timeline. */ clock_start += slen; /* Place the sound clock start time to this value after the last one. */ } result = channel->setDelay(clock_start, 0, false); /* Schedule the channel to start in the future at the newly calculated channelgroup clock value. */ ERRCHECK(result); result = channel->setPaused(false); /* Unpause the sound. Note that you won't hear the sounds, they are scheduled into the future. */ ERRCHECK(result); } /* Main loop. */ do { Common_Update(); if (Common_BtnPress(BTN_ACTION1)) /* Pausing the channelgroup as the clock parent, will pause any scheduled sounds from continuing */ { /* If you paused the channel, this would not stop the clock it is delayed against from ticking, */ bool paused; /* and you'd have to recalculate the delay for the channel into the future again before it was unpaused. */ result = channelgroup->getPaused(&paused); ERRCHECK(result); result = channelgroup->setPaused(!paused); ERRCHECK(result); } if (Common_BtnPress(BTN_ACTION2)) { for (count = 0; count < 50; count++) { float pitch; result = channelgroup->getPitch(&pitch); ERRCHECK(result); pitch += 0.01f; result = channelgroup->setPitch(pitch); ERRCHECK(result); result = system->update(); ERRCHECK(result); Common_Sleep(10); } } if (Common_BtnPress(BTN_ACTION3)) { for (count = 0; count < 50; count++) { float pitch; result = channelgroup->getPitch(&pitch); ERRCHECK(result); if (pitch > 0.1f) { pitch -= 0.01f; } result = channelgroup->setPitch(pitch); ERRCHECK(result); result = system->update(); ERRCHECK(result); Common_Sleep(10); } } result = system->update(); ERRCHECK(result); /* Print some information */ { bool playing = false; bool paused = false; int chansplaying; if (channelgroup) { result = channelgroup->isPlaying(&playing); if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE)) { ERRCHECK(result); } result = channelgroup->getPaused(&paused); if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE)) { ERRCHECK(result); } } result = system->getChannelsPlaying(&chansplaying); ERRCHECK(result); Common_Draw("=================================================="); Common_Draw("Gapless Playback example."); Common_Draw("Copyright (c) Firelight Technologies 2004-2014."); Common_Draw("=================================================="); Common_Draw(""); Common_Draw("Press %s to toggle pause", Common_BtnStr(BTN_ACTION1)); Common_Draw("Press %s to increase pitch", Common_BtnStr(BTN_ACTION2)); Common_Draw("Press %s to decrease pitch", Common_BtnStr(BTN_ACTION3)); Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT)); Common_Draw(""); Common_Draw("Channels Playing %d : %s", chansplaying, paused ? "Paused " : playing ? "Playing" : "Stopped"); } Common_Sleep(50); } while (!Common_BtnPress(BTN_QUIT)); /* Shut down */ result = sound[NOTE_C]->release(); ERRCHECK(result); result = sound[NOTE_D]->release(); ERRCHECK(result); result = sound[NOTE_E]->release(); ERRCHECK(result); result = system->close(); ERRCHECK(result); result = system->release(); ERRCHECK(result); Common_Close(); return 0; }
void USwFMOD::Update( FPointRegion Region, FCoords& Coords ) { guard(USwFMOD::Update); FMOD_RESULT result; //SWF_LOG( NAME_DevSound, TEXT("%s >> %s :: [%s],[%s]"), SWF_PLOG, *ToStr(Region), *ToStr(Coords) ); if( !Viewport || !Viewport->IsValid() || !Viewport->Actor || !Viewport->Actor->IsValid() ) return; // Load geometry if( bOcclusion ) { static ULevel* level = NULL; if( Viewport->Actor->GetLevel() != level ) { level = Viewport->Actor->GetLevel(); LoadGeometry(); } } // Time passes... DOUBLE DeltaTime = appSeconds() - LastTime; LastTime += DeltaTime; DeltaTime = Clamp( DeltaTime, 0.0, 1.0 ); // Get viewactor AActor* ViewActor = Viewport->Actor->ViewTarget ? Viewport->Actor->ViewTarget : Viewport->Actor; // Is viewport realtime ? UBOOL Realtime = Viewport->IsRealtime() && Viewport->Actor->Level->Pauser == TEXT(""); // Default viewport coords FVector location = FVector(0,0,0); FVector velocity = FVector(0,0,0); FVector forward = FVector(1,0,0); FVector up = FVector(0,0,1); // // Update listener // guard(USwFMODAudio::Update::UpdateListener); // Use ViewActor coords FCoords coords = GMath.UnitCoords / ViewActor->Rotation;; coords.Origin = ViewActor->Location; // Set viewport coords location = coords.Origin; velocity = ViewActor->Velocity; forward = coords.XAxis; up = coords.ZAxis; // verify SWF_VERIFY_FVECTOR(location); SWF_VERIFY_FVECTOR(velocity); SWF_VERIFY_FVECTOR_NORMAL(forward); SWF_VERIFY_FVECTOR_NORMAL(up); // Default listener coords FMOD_VECTOR fm_pos = {0,0,0}; FMOD_VECTOR fm_vel = {0,0,0}; FMOD_VECTOR fm_fwd = {0,0,1}; FMOD_VECTOR fm_up = {0,1,0}; // Set listener coords fm_pos = ToFMODVector(location); fm_vel = ToFMODVector(velocity); fm_fwd = ToFMODNormal(forward); fm_up = ToFMODNormal(up); // verify SWF_VERIFY_FMODVECTOR(fm_pos); SWF_VERIFY_FMODVECTOR(fm_vel); SWF_VERIFY_FMODVECTOR_NORMAL(fm_fwd); SWF_VERIFY_FMODVECTOR_NORMAL(fm_up); // Update SWF_FMOD_CALL( System->set3DListenerAttributes( 0, &fm_pos, &fm_vel, &fm_fwd, &fm_up ) ); unguard; // // Zone effects // guard(USwFMODAudio::Update::UpdateZone); /*// Default zone properties UBOOL bWaterZone = 0; UBOOL bReverbZone = 0; UBOOL bRaytraceReverb = 0; BYTE MasterGain = 100; INT CutoffHz = 6000; BYTE Delay[6] = {20,34,0,0,0,0}; BYTE Gain[6] = {150,70,0,0,0,0}; // Get zone properties if( Region.Zone && Region.Zone->IsValid() ) { bWaterZone = Region.Zone->bWaterZone; bReverbZone = Region.Zone->bReverbZone; bRaytraceReverb = Region.Zone->bRaytraceReverb; MasterGain = Region.Zone->MasterGain; CutoffHz = Region.Zone->CutoffHz; appMemcpy(Delay, Region.Zone->Delay, 6*sizeof(BYTE)); appMemcpy(Gain, Region.Zone->Gain, 6*sizeof(BYTE)); }*/ unguard; // // Update sounds. // guard(USwFMODAudio::Update::UpdateSounds); // Iterate through all channels for( FSwChannelEnumerator it(System); it; ++it ) { FMOD::Channel* channel = *it; if( !IsChannelValid(channel) ) continue; // Channel data FMOD::Sound* sample = GetChannelSample(channel); if( !sample ) continue; UObject* object = GetSampleObject(sample); if( !object ) continue; USound* sound = Cast<USound>(object); FSwSoundId id = GetChannelId(channel); AActor* actor = id.GetActor(); FMOD_MODE fmode; SWF_FMOD_CALL( channel->getMode(&fmode) ); UBOOL bIs3D = HasFlag(fmode,FMOD_3D); // Sample defaults FLOAT deffrequency; FLOAT defvolume; FLOAT defpanning; INT defpriority; SWF_FMOD_CALL( sample->getDefaults( &deffrequency, &defvolume, &defpanning, &defpriority ) ); if( sound ) { if( actor && actor->IsValid() ) { // Ambient sounds if( id.GetSlot() == SLOT_Ambient ) { if( actor->AmbientSound != sound || FDist(location, actor->Location) > actor->WorldSoundRadius() + AmbientHysteresis || !Realtime ) { // Stop ambient sound //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient OUT [%d]"), SWF_PLOG, *ToStr(id) ); SWF_FMOD_CALL( channel->setUserData(NULL) ); SWF_FMOD_CALL( channel->stop() ); continue; } else { // Update ambient sound properties. FLOAT volume = actor->SoundVolume / 255.0f; FLOAT frequency = (actor->SoundPitch / 64.0f) * deffrequency; SWF_VERIFY_FLOAT(volume); SWF_VERIFY_FLOAT(frequency); SWF_FMOD_CALL( channel->setVolume( volume ) ); SWF_FMOD_CALL( channel->setFrequency( frequency ) ); if( bIs3D ) { // Update 3D sound properties FLOAT mindist = ToFMODFloat(DistanceMin); FLOAT radius = ToFMODFloat( actor->WorldSoundRadius() ); TSwSortMinMax( mindist, radius ); SWF_VERIFY_FLOAT(radius); SWF_VERIFY_FLOAT(mindist); SWF_FMOD_CALL( channel->set3DMinMaxDistance( mindist, radius ) ); } } } if( bIs3D ) { // Update 3D sound properties FMOD_VECTOR snd_pos = ToFMODVector(actor->Location); FMOD_VECTOR snd_vel = ToFMODVector(actor->Velocity); SWF_VERIFY_FMODVECTOR(snd_pos); SWF_VERIFY_FMODVECTOR(snd_vel); SWF_FMOD_CALL( channel->set3DAttributes(&snd_pos, &snd_vel) ); } } } } unguard; // // Play ambient sounds // if( Realtime ) { guard(USwFMODAudio::Update::PlayAmbient); for( INT i=0; i<Viewport->Actor->GetLevel()->Actors.Num(); ++i ) { AActor* Actor = Viewport->Actor->GetLevel()->Actors(i); if( Actor && Actor->AmbientSound && FDist(location, Actor->Location) <= Actor->WorldSoundRadius() ) { FSwSoundId ambientid = FSwSoundId(Actor,SLOT_Ambient,0); //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient TEST IN [%s]"), SWF_PLOG, *ToStr(ambientid) ); // Find this sound in currently playing ones FMOD::Channel* ambientchannel = NULL; for( FSwChannelEnumerator it(System,AmbientChannels); it; ++it ) { FMOD::Channel* channel = *it; if( IsChannelValid(channel) && GetChannelId(channel) == ambientid ) { //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient FOUND IN [%s]"), SWF_PLOG, *ToStr(GetChannelId(channel)) ); ambientchannel = channel; break; } } // If not found play ambient if( !ambientchannel ) { //SWF_LOG( NAME_DevSound, TEXT("%s -- %s :: Ambient PLAY IN [%s][%s]"), SWF_PLOG, *ToStr(ambientid), *ToStr(Actor->AmbientSound) ); PlaySound( Actor, ambientid.GetId(), Actor->AmbientSound, Actor->Location, Actor->SoundVolume/255.0f, Actor->WorldSoundRadius(), Actor->SoundPitch/64.0f ); } } } unguard; } // // Music // guard(UpdateMusic) /* REQUIREMENTS SongSection is updated at realtime by audio sys MTRAN_Fade* only fade out, not in music changes caused by transition only ttransition reset on change MTRAN_None = don't change MTRAN_Instant = instant change MTRAN_Segue = seamless? MTRAN_Fade = 1s fade MTRAN_FastFade = 1/3s fade MTRAN_SlowFade = 5s fade */ // find music channel FMOD::Channel* musicchannel = NULL; for( FSwChannelEnumerator it(System,MusicChannels); it; ++it ) { FMOD::Channel* channel = *it; if( !IsChannelValid(channel) ) continue; if( !musicchannel ) { musicchannel = channel; } else { // there can be only one music SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: StopMusic %s"), SWF_PLOG, *PrintChannel(channel) ); SWF_FMOD_CALL( channel->setUserData(NULL) ); SWF_FMOD_CALL( channel->stop() ); } } if( Viewport->Actor->Transition != MTRAN_None ) { // init fading if( MusicFade < 0 ) { SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: Music transition %s S:%s T:%s "), SWF_PLOG , *ToStr(Viewport->Actor->Song) , *ToStr(Viewport->Actor->SongSection) , *ToStr(Viewport->Actor->Transition)); switch( Viewport->Actor->Transition ) { case MTRAN_Instant: MusicFadeTime = -1.0f; break; // Instant case MTRAN_Segue: MusicFadeTime = -1.0f; // Instant precached if( Viewport->Actor->Song && !Viewport->Actor->Song->Handle ) RegisterMusic(Viewport->Actor->Song); break; case MTRAN_Fade: MusicFadeTime = 1.0f; break; // 1s fadeout case MTRAN_FastFade: MusicFadeTime = 0.33f; break; // 1/3s fadeout case MTRAN_SlowFade: MusicFadeTime = 5.0f; break; // 5s fadeout default: MusicFadeTime = -1.0f; break; // Unknown,instant } MusicFade = MusicFadeTime; } // deduct delta MusicFade -= DeltaTime; //SWF_LOG( NAME_DevSound, TEXT("%s << %s :: MusicFade %s %s"), SWF_PLOG, *ToStr(MusicFade), *ToStr(MusicFadeTime) ); if( MusicFade > 0 ) { // fade volume if( musicchannel && MusicFadeTime > 0 ) { SWF_FMOD_CALL( musicchannel->setVolume( MusicFade / MusicFadeTime) ); } } else { // play new MusicFade = -1; Viewport->Actor->Transition = MTRAN_None; PlayMusic( Viewport->Actor->Song, musicchannel, Viewport->Actor->SongSection, Viewport->Actor->CdTrack, static_cast<EMusicTransition>(Viewport->Actor->Transition) ); } } else { // Update section if( musicchannel ) { // update section // FIXME:: getPosition doesn't work with volume 0 (virtual?) UINT sec = 0; result = musicchannel->getPosition(&sec,FMOD_TIMEUNIT_MODORDER); if( result == FMOD_OK ) { Viewport->Actor->SongSection = sec; } // Update position if( IsChannelValid(musicchannel) ) { UINT row = 0; result = musicchannel->getPosition(&row,FMOD_TIMEUNIT_MODROW); if( result == FMOD_OK ) { // IT/MOD/XM UINT pattern = 0; result = musicchannel->getPosition(&pattern,FMOD_TIMEUNIT_MODPATTERN); if( result == FMOD_OK ) { MusicPositions(Viewport->Actor->SongSection).row = row; MusicPositions(Viewport->Actor->SongSection).pattern = pattern; } } else { // MPEG/OGG UINT ms = 0; result = musicchannel->getPosition(&ms,FMOD_TIMEUNIT_MS); if( result == FMOD_OK ) { MusicPositions(Viewport->Actor->SongSection).ms = ms; } } } } else if( Viewport->Actor->Song && VolumeMusic > 0 ) { // Restart missing/dropped song (bad channel priorities?) SWF_LOG( NAME_DevSound, TEXT("%s :: %s :: Restarting missing song %s S:%s T:%s "), SWF_PLOG , *ToStr(Viewport->Actor->Song) , *ToStr(Viewport->Actor->SongSection) , *ToStr(Viewport->Actor->Transition)); Viewport->Actor->Transition = MTRAN_Instant; } } unguard; // Update FMOD guard(UpdateFMOD); SWF_FMOD_CALL( System->update() ); unguard; //SWF_LOG( NAME_DevSound, TEXT("%s << %s :: [%s],[%s]"), SWF_PLOG, *ToStr(Region), *ToStr(Coords) ); unguard; }