SIZE_T USoundCue::GetResourceSize(EResourceSizeMode::Type Mode)
{
	if( Mode == EResourceSizeMode::Exclusive )
	{
		return( 0 );
	}
	else
	{
		// Sum up the size of referenced waves
		int32 ResourceSize = 0;

		TArray<USoundNodeWavePlayer*> WavePlayers;
		RecursiveFindNode<USoundNodeWavePlayer>( FirstNode, WavePlayers );

		for( int32 WaveIndex = 0; WaveIndex < WavePlayers.Num(); ++WaveIndex )
		{
			USoundWave* SoundWave = WavePlayers[WaveIndex]->GetSoundWave();
			if (SoundWave)
			{
				ResourceSize += SoundWave->GetResourceSize(Mode);
			}
		}

		return( ResourceSize );
	}
}
EReimportResult::Type UMP3SoundFactory::Reimport(UObject* Obj)
{
	if (Obj == nullptr || Cast<USoundWave>(Obj) == nullptr)
	{
		return EReimportResult::Failed;
	}

	USoundWave* SoundWave = Cast<USoundWave>(Obj);

	const FString Filename = SoundWave->AssetImportData->GetFirstFilename();
	const FString FileExtension = FPaths::GetExtension(Filename);

	if (FileExtension.Compare("MP3", ESearchCase::IgnoreCase) != 0)
		return EReimportResult::Failed;

	UE_LOG(MP3ImporterLog, Log, TEXT("Reimport triggered for %s"), *Filename);

	if (UFactory::StaticImportObject(SoundWave->GetClass(), SoundWave->GetOuter(), *SoundWave->GetName(), RF_Public | RF_Standalone, *Filename, nullptr, this))
	{
		UE_LOG(MP3ImporterLog, Log, TEXT("Reimport successfull"));

		SoundWave->AssetImportData->Update(Filename);
		SoundWave->MarkPackageDirty();

		return EReimportResult::Succeeded;
	}
	else
	{
		UE_LOG(MP3ImporterLog, Warning, TEXT("Reimport failed!"));
		return EReimportResult::Failed;
	}
}
Esempio n. 3
0
void USoundWave::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const
{
	Super::GetAssetRegistryTags(OutTags);

	// GetCompressedDataSize could technically modify this->CompressedFormatData therefore it is not const, however this information
	// is very useful in the asset registry so we will allow GetCompressedDataSize to be modified if the formats do not exist
	USoundWave* MutableThis = const_cast<USoundWave*>(this);
	const FString OggSize = FString::Printf(TEXT("%.2f"), MutableThis->GetCompressedDataSize("OGG") / 1024.0f );
	OutTags.Add( FAssetRegistryTag("OggSize", OggSize, UObject::FAssetRegistryTag::TT_Numerical) );
}
Esempio n. 4
0
/**
 * This will return the name of the SoundClass of the Sound that this buffer(SoundWave) belongs to.
 * NOTE: This will find the first cue in the ObjectIterator list.  So if we are using SoundWaves in multiple
 * places we will pick up the first one only.
 **/
FName FSoundBuffer::GetSoundClassName()
{
	// need to look in all cues
	for (TObjectIterator<USoundBase> It; It; ++It)
	{
		USoundCue* Cue = Cast<USoundCue>(*It);
		if (Cue)
		{
			// get all the waves this cue uses
			TArray<USoundNodeWavePlayer*> WavePlayers;
			Cue->RecursiveFindNode<USoundNodeWavePlayer>(Cue->FirstNode, WavePlayers);

			// look through them to see if this cue uses a wave this buffer is bound to, via ResourceID
			for (int32 WaveIndex = 0; WaveIndex < WavePlayers.Num(); ++WaveIndex)
			{
				USoundWave* WaveNode = WavePlayers[WaveIndex]->GetSoundWave();
				if (WaveNode != NULL)
				{
					if (WaveNode->ResourceID == ResourceID)
					{
						if (Cue->GetSoundClass())
						{
							return Cue->GetSoundClass()->GetFName();
						}
						else
						{
							return NAME_None;
						}
					}
				}
			}
		}
		else
		{
			USoundWave* Wave = Cast<USoundWave>(*It);
			if (Wave && Wave->ResourceID == ResourceID)
			{
				if (Wave->GetSoundClass())
				{
					return Wave->GetSoundClass()->GetFName();
				}
				else
				{
					return NAME_None;
				}
			}
		}
	}

	return NAME_None;
}
void USoundNodeWaveParam::ParseNodes( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances )
{
	USoundWave* NewWave = NULL;
	ActiveSound.GetWaveParameter( WaveParameterName, NewWave );
	if( NewWave != NULL )
	{
		NewWave->Parse( AudioDevice, GetNodeWaveInstanceHash(NodeWaveInstanceHash, (UPTRINT)NewWave, 0), ActiveSound, ParseParams, WaveInstances );
	}
	else
	{
		// use the default node linked to us, if any
		Super::ParseNodes( AudioDevice, NodeWaveInstanceHash, ActiveSound, ParseParams, WaveInstances );
	}
}
Esempio n. 6
0
void USoundWave::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const
{
	Super::GetAssetRegistryTags(OutTags);
	
#if WITH_EDITORONLY_DATA
	if (AssetImportData)
	{
		OutTags.Add( FAssetRegistryTag(SourceFileTagName(), AssetImportData->GetSourceData().ToJson(), FAssetRegistryTag::TT_Hidden) );
	}
#endif
	// GetCompressedDataSize could technically modify this->CompressedFormatData therefore it is not const, however this information
	// is very useful in the asset registry so we will allow GetCompressedDataSize to be modified if the formats do not exist
	USoundWave* MutableThis = const_cast<USoundWave*>(this);
	const FString OggSize = FString::Printf(TEXT("%.2f"), MutableThis->GetCompressedDataSize("OGG") / 1024.0f );
	OutTags.Add( FAssetRegistryTag("OggSize", OggSize, UObject::FAssetRegistryTag::TT_Numerical) );
}
int32 USoundCue::GetResourceSizeForFormat(FName Format)
{
	TArray<USoundNodeWavePlayer*> WavePlayers;
	RecursiveFindNode<USoundNodeWavePlayer>(FirstNode, WavePlayers);

	int32 ResourceSize = 0;
	for (int32 WaveIndex = 0; WaveIndex < WavePlayers.Num(); ++WaveIndex)
	{
		USoundWave* SoundWave = WavePlayers[WaveIndex]->GetSoundWave();
		if (SoundWave)
		{
			ResourceSize += SoundWave->GetResourceSizeForFormat(Format);
		}
	}

	return ResourceSize;
}
	bool FMixerSource::ReadMorePCMRTData(const int32 BufferIndex, EBufferReadMode BufferReadMode, bool* OutLooped)
	{
		USoundWave* WaveData = WaveInstance->WaveData;

		if (WaveData && WaveData->bProcedural)
		{
			AUDIO_MIXER_CHECK_AUDIO_PLAT_THREAD(MixerDevice);
			const int32 MaxSamples = (MONO_PCM_BUFFER_SIZE * Buffer->NumChannels) / sizeof(int16);

			if (BufferReadMode == EBufferReadMode::Synchronous || WaveData->bCanProcessAsync == false)
			{
				const int32 BytesWritten = WaveData->GeneratePCMData(SourceVoiceBuffers[BufferIndex]->AudioData.GetData(), MaxSamples);
				SourceVoiceBuffers[BufferIndex]->AudioBytes = BytesWritten;
			}
			else
			{
				check(!AsyncRealtimeAudioTask);
				AsyncRealtimeAudioTask = new FAsyncRealtimeAudioTask(WaveData, SourceVoiceBuffers[BufferIndex]->AudioData.GetData(), MaxSamples);
				AsyncRealtimeAudioTask->StartBackgroundTask();
			}

			// Not looping
			return false;
		}
		else if (BufferReadMode == EBufferReadMode::Synchronous)
		{
			return MixerBuffer->ReadCompressedData(SourceVoiceBuffers[BufferIndex]->AudioData.GetData(), WaveInstance->LoopingMode != LOOP_Never);
		}
		else
		{
			AUDIO_MIXER_CHECK_AUDIO_PLAT_THREAD(MixerDevice);
			check(!AsyncRealtimeAudioTask);
			AsyncRealtimeAudioTask = new FAsyncRealtimeAudioTask(MixerBuffer, SourceVoiceBuffers[BufferIndex]->AudioData.GetData(), WaveInstance->LoopingMode != LOOP_Never, BufferReadMode == EBufferReadMode::AsynchronousSkipFirstFrame);
			AsyncRealtimeAudioTask->StartBackgroundTask();

			// Not looping
			return false;
		}
	}
Esempio n. 9
0
bool USoundWave::IsReadyForFinishDestroy()
{
	const bool bIsStreamingInProgress = IStreamingManager::Get().GetAudioStreamingManager().IsStreamingInProgress(this);

	// Wait till streaming and decompression finishes before deleting resource.
	if ( !bIsStreamingInProgress && (( AudioDecompressor == nullptr ) || AudioDecompressor->IsDone()) )
	{
		if (ResourceState == ESoundWaveResourceState::NeedsFree)
		{
			DECLARE_CYCLE_STAT(TEXT("FAudioThreadTask.FreeResources"), STAT_AudioFreeResources, STATGROUP_AudioThreadCommands);

			USoundWave* SoundWave = this;
			ResourceState = ESoundWaveResourceState::Freeing;
			FAudioThread::RunCommandOnAudioThread([SoundWave]()
			{
				SoundWave->FreeResources();
			}, GET_STATID(STAT_AudioFreeResources));
		}
	}
	
	return ResourceState == ESoundWaveResourceState::Freed;
}
UObject* UMP3SoundFactory::FactoryCreateBinary(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn)
{
	FEditorDelegates::OnAssetPreImport.Broadcast(this, Class, InParent, Name, Type);

	if (mpg123_init == nullptr)
	{
		Warn->Logf(ELogVerbosity::Error, TEXT("Function pointer was null. Was %s found?"), DLL_NAME);
		FEditorDelegates::OnAssetPostImport.Broadcast(this, nullptr);
		return nullptr;
	}

	// if the sound already exists, remember the user settings
	USoundWave* ExistingSound = FindObject<USoundWave>(InParent, *Name.ToString());

	// stop playing the file, if it already exists (e.g. reimport)
	TArray<UAudioComponent*> ComponentsToRestart;
	FAudioDeviceManager* AudioDeviceManager = GEngine->GetAudioDeviceManager();
	if (AudioDeviceManager && ExistingSound)
	{
		AudioDeviceManager->StopSoundsUsingResource(ExistingSound, ComponentsToRestart);
	}

	// Read the mp3 header and make sure we have valid data
	UMP3Decoder Decoder(Warn);
	Decoder.Init(Buffer, BufferEnd);

	if (Decoder.BitsPerSample != 16)
	{
		Warn->Logf(ELogVerbosity::Error, TEXT("Unreal only supports 16bit WAVE data (%s)."), *Name.ToString());
		FEditorDelegates::OnAssetPostImport.Broadcast(this, nullptr);
		return nullptr;
	}

	if (Decoder.Channels != 1 && Decoder.Channels != 2)
	{
		Warn->Logf(ELogVerbosity::Error, TEXT("Unreal only supports 1-2 channel WAVE data (Mono/Stereo). (%s)."), *Name.ToString());
		FEditorDelegates::OnAssetPostImport.Broadcast(this, nullptr);
		return nullptr;
	}
	
	//on reimport, reuse settings, wipe data. otherwise create new. (UE4 WAVE import has some more checks, maybe implement, too?)

	USoundWave* Sound;
	
	if (ExistingSound && bMP3SoundFactoryIsReimport)
	{
		Sound = ExistingSound;
		Sound->FreeResources();
		Sound->InvalidateCompressedData();
	}
	else
	{
		Sound = NewObject<USoundWave>(InParent, Name, Flags);
	}

	Sound->AssetImportData->Update(GetCurrentFilename());

	TArray<uint8> RawWavBuffer;
	RawWavBuffer.Reserve((BufferEnd - Buffer) * 16);

	//actual decoding
	Decoder.Decode(RawWavBuffer);
		
	Sound->RawData.Lock(LOCK_READ_WRITE);
	void* LockedData = Sound->RawData.Realloc(RawWavBuffer.Num() * RawWavBuffer.GetTypeSize());
	FMemory::Memcpy(LockedData, RawWavBuffer.GetData(), RawWavBuffer.Num() * RawWavBuffer.GetTypeSize());
	Sound->RawData.Unlock();
	RawWavBuffer.Empty();

	// Calculate duration.
	Sound->Duration = (float)Decoder.SizeInBytes / Decoder.Samplerate / Decoder.Channels / (BITS_PER_SAMPLE / 8);
	Sound->SampleRate = Decoder.Samplerate;
	Sound->NumChannels = Decoder.Channels;
	Sound->RawPCMDataSize = Decoder.SizeInBytes;

	FEditorDelegates::OnAssetPostImport.Broadcast(this, Sound);

	if (ExistingSound)
	{
		Sound->PostEditChange();
	}

	for (int32 ComponentIndex = 0; ComponentIndex < ComponentsToRestart.Num(); ++ComponentIndex)
	{
		ComponentsToRestart[ComponentIndex]->Play();
	}

	return Sound;
}