删除Audio插件,更正修改目录
This commit is contained in:
parent
b8a2cbd287
commit
ff9ad93e3a
567
Build/Windows/FileOpenOrder/CookerOpenOrder.log
Normal file
567
Build/Windows/FileOpenOrder/CookerOpenOrder.log
Normal file
@ -0,0 +1,567 @@
|
||||
"../../../Engine/Content/EditorResources/S_Actor.ubulk" 0
|
||||
"../../../Engine/Content/EditorResources/S_Actor.uasset" 1
|
||||
"../../../Engine/Content/EditorResources/S_Actor.uexp" 2
|
||||
"../../../Engine/Content/EditorResources/S_BoxReflectionCapture.uasset" 3
|
||||
"../../../Engine/Content/EditorResources/S_BoxReflectionCapture.uexp" 4
|
||||
"../../../Engine/Content/EngineResources/DefaultTexture.ubulk" 5
|
||||
"../../../Engine/Content/EngineResources/DefaultTexture.uasset" 6
|
||||
"../../../Engine/Content/EngineResources/DefaultTexture.uexp" 7
|
||||
"../../../Engine/Content/EngineResources/DefaultTextureCube.uasset" 8
|
||||
"../../../Engine/Content/EngineResources/DefaultTextureCube.uexp" 9
|
||||
"../../../Engine/Content/EngineResources/DefaultVolumeTexture2D.uasset" 10
|
||||
"../../../Engine/Content/EngineResources/DefaultVolumeTexture2D.uexp" 11
|
||||
"../../../Engine/Content/EngineResources/DefaultVolumeTexture.uasset" 12
|
||||
"../../../Engine/Content/EngineResources/DefaultVolumeTexture.uexp" 13
|
||||
"../../../Engine/Content/EditorResources/S_Trigger.ubulk" 14
|
||||
"../../../Engine/Content/EditorResources/S_Trigger.uasset" 15
|
||||
"../../../Engine/Content/EditorResources/S_Trigger.uexp" 16
|
||||
"../../../Engine/Content/EditorResources/S_TriggerBox.uasset" 17
|
||||
"../../../Engine/Content/EditorResources/S_TriggerBox.uexp" 18
|
||||
"../../../Engine/Content/EditorResources/S_TriggerCapsule.uasset" 19
|
||||
"../../../Engine/Content/EditorResources/S_TriggerCapsule.uexp" 20
|
||||
"../../../Engine/Content/EditorResources/S_TriggerSphere.uasset" 21
|
||||
"../../../Engine/Content/EditorResources/S_TriggerSphere.uexp" 22
|
||||
"../../../Engine/Content/EngineMeshes/Sphere.ubulk" 23
|
||||
"../../../Engine/Content/EngineMeshes/Sphere.uasset" 24
|
||||
"../../../Engine/Content/EngineMeshes/Sphere.uexp" 25
|
||||
"../../../Engine/Content/EngineResources/GradientTexture0.uasset" 26
|
||||
"../../../Engine/Content/EngineResources/GradientTexture0.uexp" 27
|
||||
"../../../Engine/Content/EngineResources/Black.uasset" 28
|
||||
"../../../Engine/Content/EngineResources/Black.uexp" 29
|
||||
"../../../Engine/Content/VREditor/LaserPointer/VR_LaserPower_01.ubulk" 30
|
||||
"../../../Engine/Content/VREditor/LaserPointer/VR_LaserPower_01.uasset" 31
|
||||
"../../../Engine/Content/VREditor/LaserPointer/VR_LaserPower_01.uexp" 32
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/TransformGizmoMaterial.uasset" 33
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/TransformGizmoMaterial.uexp" 34
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/TranslucentTransformGizmoMaterial.uasset" 35
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/TranslucentTransformGizmoMaterial.uexp" 36
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/PlaneTranslationHandle.ubulk" 37
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/PlaneTranslationHandle.uasset" 38
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/PlaneTranslationHandle.uexp" 39
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/BoundingBoxCorner.ubulk" 40
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/BoundingBoxCorner.uasset" 41
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/BoundingBoxCorner.uexp" 42
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/BoundingBoxEdge.ubulk" 43
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/BoundingBoxEdge.uasset" 44
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/BoundingBoxEdge.uexp" 45
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/Main.uasset" 46
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/Main.uexp" 47
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/Xray.uasset" 48
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/Xray.uexp" 49
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/SM_Sequencer_Node.ubulk" 50
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/SM_Sequencer_Node.uasset" 51
|
||||
"../../../Engine/Content/VREditor/TransformGizmo/SM_Sequencer_Node.uexp" 52
|
||||
"../../../Engine/Content/EditorMaterials/Camera/CineMat.uasset" 53
|
||||
"../../../Engine/Content/EditorMaterials/Camera/CineMat.uexp" 54
|
||||
"../../../Engine/Content/EditorMaterials/Camera/MI_CineMat_Rig.uasset" 55
|
||||
"../../../Engine/Content/EditorMaterials/Camera/MI_CineMat_Rig.uexp" 56
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Base.ubulk" 57
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Base.uasset" 58
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Base.uexp" 59
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Arm.ubulk" 60
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Arm.uasset" 61
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Arm.uexp" 62
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Mount.ubulk" 63
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Mount.uasset" 64
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Mount.uexp" 65
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Body.ubulk" 66
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Body.uasset" 67
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_CraneRig_Body.uexp" 68
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_RailRig_Track.ubulk" 69
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_RailRig_Track.uasset" 70
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_RailRig_Track.uexp" 71
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_RailRig_Mount.ubulk" 72
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_RailRig_Mount.uasset" 73
|
||||
"../../../Engine/Content/EditorMeshes/Camera/SM_RailRig_Mount.uexp" 74
|
||||
"../../../Engine/Content/EngineMaterials/T_Default_Material_Grid_M.ubulk" 75
|
||||
"../../../Engine/Content/EngineMaterials/T_Default_Material_Grid_M.uasset" 76
|
||||
"../../../Engine/Content/EngineMaterials/T_Default_Material_Grid_M.uexp" 77
|
||||
"../../../Engine/Content/EngineMaterials/T_Default_Material_Grid_N.ubulk" 78
|
||||
"../../../Engine/Content/EngineMaterials/T_Default_Material_Grid_N.uasset" 79
|
||||
"../../../Engine/Content/EngineMaterials/T_Default_Material_Grid_N.uexp" 80
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions01/Opacity/CameraDepthFade.uasset" 81
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions01/Opacity/CameraDepthFade.uexp" 82
|
||||
"../../../Engine/Content/EngineMaterials/WorldGridMaterial.uasset" 83
|
||||
"../../../Engine/Content/EngineMaterials/WorldGridMaterial.uexp" 84
|
||||
"../../../Engine/Content/ArtTools/RenderToTexture/Meshes/S_1_Unit_Plane.ubulk" 85
|
||||
"../../../Engine/Content/ArtTools/RenderToTexture/Meshes/S_1_Unit_Plane.uasset" 86
|
||||
"../../../Engine/Content/ArtTools/RenderToTexture/Meshes/S_1_Unit_Plane.uexp" 87
|
||||
"../../../Engine/Content/EditorMaterials/ParticleSystems/PSysThumbnail_NoImage.ubulk" 88
|
||||
"../../../Engine/Content/EditorMaterials/ParticleSystems/PSysThumbnail_NoImage.uasset" 89
|
||||
"../../../Engine/Content/EditorMaterials/ParticleSystems/PSysThumbnail_NoImage.uexp" 90
|
||||
"../../../Engine/Content/EditorMaterials/ParticleSystems/PSysThumbnail_OOD.ubulk" 91
|
||||
"../../../Engine/Content/EditorMaterials/ParticleSystems/PSysThumbnail_OOD.uasset" 92
|
||||
"../../../Engine/Content/EditorMaterials/ParticleSystems/PSysThumbnail_OOD.uexp" 93
|
||||
"../../../Engine/Content/EditorLandscapeResources/SplineEditorMeshMat.uasset" 94
|
||||
"../../../Engine/Content/EditorLandscapeResources/SplineEditorMeshMat.uexp" 95
|
||||
"../../../Engine/Content/EditorLandscapeResources/SplineEditorMesh.ubulk" 96
|
||||
"../../../Engine/Content/EditorLandscapeResources/SplineEditorMesh.uasset" 97
|
||||
"../../../Engine/Content/EditorLandscapeResources/SplineEditorMesh.uexp" 98
|
||||
"../../../Engine/Content/EditorResources/S_Solver.ubulk" 99
|
||||
"../../../Engine/Content/EditorResources/S_Solver.uasset" 100
|
||||
"../../../Engine/Content/EditorResources/S_Solver.uexp" 101
|
||||
"../../../Engine/Plugins/Media/MediaPlate/Content/SM_MediaPlateScreen.ubulk" 102
|
||||
"../../../Engine/Plugins/Media/MediaPlate/Content/SM_MediaPlateScreen.uasset" 103
|
||||
"../../../Engine/Plugins/Media/MediaPlate/Content/SM_MediaPlateScreen.uexp" 104
|
||||
"../../../Engine/Content/EngineMaterials/Good64x64TilingNoiseHighFreq.uasset" 105
|
||||
"../../../Engine/Content/EngineMaterials/Good64x64TilingNoiseHighFreq.uexp" 106
|
||||
"../../../Engine/Content/EngineMaterials/DefaultBokeh.uasset" 107
|
||||
"../../../Engine/Content/EngineMaterials/DefaultBokeh.uexp" 108
|
||||
"../../../Engine/Content/EngineMaterials/PreintegratedSkinBRDF.uasset" 109
|
||||
"../../../Engine/Content/EngineMaterials/PreintegratedSkinBRDF.uexp" 110
|
||||
"../../../Engine/Content/EngineMaterials/MiniFont.uasset" 111
|
||||
"../../../Engine/Content/EngineMaterials/MiniFont.uexp" 112
|
||||
"../../../Engine/Content/EngineMaterials/WeightMapPlaceholderTexture.uasset" 113
|
||||
"../../../Engine/Content/EngineMaterials/WeightMapPlaceholderTexture.uexp" 114
|
||||
"../../../Engine/Content/EngineMaterials/DefaultWhiteGrid.ubulk" 115
|
||||
"../../../Engine/Content/EngineMaterials/DefaultWhiteGrid.uasset" 116
|
||||
"../../../Engine/Content/EngineMaterials/DefaultWhiteGrid.uexp" 117
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/WorldPositionOffset/CameraOffset.uasset" 118
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/WorldPositionOffset/CameraOffset.uexp" 119
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/M_Manip.uasset" 120
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/M_Manip.uexp" 121
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/PlaceholderTextures/DummySpriteTexture.ubulk" 122
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/PlaceholderTextures/DummySpriteTexture.uasset" 123
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/PlaceholderTextures/DummySpriteTexture.uexp" 124
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/DefaultSpriteMaterial.uasset" 125
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/DefaultSpriteMaterial.uexp" 126
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/OpaqueUnlitSpriteMaterial.uasset" 127
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/OpaqueUnlitSpriteMaterial.uexp" 128
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/MaskedUnlitSpriteMaterial.uasset" 129
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/MaskedUnlitSpriteMaterial.uexp" 130
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/DummySprite.uasset" 131
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/DummySprite.uexp" 132
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/DefaultPaperTerrainMaterial.uasset" 133
|
||||
"../../../Engine/Plugins/2D/Paper2D/Content/DefaultPaperTerrainMaterial.uexp" 134
|
||||
"../../../Engine/Content/Animation/DefaultRecorderBoneCompression.uasset" 135
|
||||
"../../../Engine/Content/Animation/DefaultRecorderBoneCompression.uexp" 136
|
||||
"../../../Engine/Content/Animation/DefaultAnimCurveCompressionSettings.uasset" 137
|
||||
"../../../Engine/Content/Animation/DefaultAnimCurveCompressionSettings.uexp" 138
|
||||
"../../../Engine/Content/Animation/DefaultAnimBoneCompressionSettings.uasset" 139
|
||||
"../../../Engine/Content/Animation/DefaultAnimBoneCompressionSettings.uexp" 140
|
||||
"../../../Engine/Content/EngineMaterials/DefaultMaterial.uasset" 141
|
||||
"../../../Engine/Content/EngineMaterials/DefaultMaterial.uexp" 142
|
||||
"../../../Engine/Content/BasicShapes/Sphere.ubulk" 143
|
||||
"../../../Engine/Content/BasicShapes/Sphere.uasset" 144
|
||||
"../../../Engine/Content/BasicShapes/Sphere.uexp" 145
|
||||
"../../../Engine/Content/BasicShapes/Plane.ubulk" 146
|
||||
"../../../Engine/Content/BasicShapes/Plane.uasset" 147
|
||||
"../../../Engine/Content/BasicShapes/Plane.uexp" 148
|
||||
"../../../Engine/Content/BasicShapes/Cylinder.ubulk" 149
|
||||
"../../../Engine/Content/BasicShapes/Cylinder.uasset" 150
|
||||
"../../../Engine/Content/BasicShapes/Cylinder.uexp" 151
|
||||
"../../../Engine/Content/BasicShapes/Cube.ubulk" 152
|
||||
"../../../Engine/Content/BasicShapes/Cube.uasset" 153
|
||||
"../../../Engine/Content/BasicShapes/Cube.uexp" 154
|
||||
"../../../Engine/Content/BasicShapes/Cone.ubulk" 155
|
||||
"../../../Engine/Content/BasicShapes/Cone.uasset" 156
|
||||
"../../../Engine/Content/BasicShapes/Cone.uexp" 157
|
||||
"../../../Engine/Content/EditorMaterials/PreviewShadowIndicator.ubulk" 158
|
||||
"../../../Engine/Content/EditorMaterials/PreviewShadowIndicator.uasset" 159
|
||||
"../../../Engine/Content/EditorMaterials/PreviewShadowIndicator.uexp" 160
|
||||
"../../../Engine/Content/EditorMaterials/PreviewShadowIndicatorMaterial.uasset" 161
|
||||
"../../../Engine/Content/EditorMaterials/PreviewShadowIndicatorMaterial.uexp" 162
|
||||
"../../../Engine/Content/EditorMaterials/PhAT_UnselectedMaterial.uasset" 163
|
||||
"../../../Engine/Content/EditorMaterials/PhAT_UnselectedMaterial.uexp" 164
|
||||
"../../../Engine/Content/EditorMaterials/PhAT_NoCollisionMaterial.uasset" 165
|
||||
"../../../Engine/Content/EditorMaterials/PhAT_NoCollisionMaterial.uexp" 166
|
||||
"../../../Engine/Content/EngineResources/WhiteSquareTexture.uasset" 167
|
||||
"../../../Engine/Content/EngineResources/WhiteSquareTexture.uexp" 168
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough.uasset" 169
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough.uexp" 170
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Translucent.uasset" 171
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Translucent.uexp" 172
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Translucent_OneSided.uasset" 173
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Translucent_OneSided.uexp" 174
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Opaque.uasset" 175
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Opaque.uexp" 176
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Opaque_OneSided.uasset" 177
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Opaque_OneSided.uexp" 178
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Masked_OneSided.uasset" 179
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Masked_OneSided.uexp" 180
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Masked.uasset" 181
|
||||
"../../../Engine/Content/EngineMaterials/Widget3DPassThrough_Masked.uexp" 182
|
||||
"../../../Engine/Content/EngineMaterials/STBlueNoise_vec2_128x128x64.uasset" 183
|
||||
"../../../Engine/Content/EngineMaterials/STBlueNoise_vec2_128x128x64.uexp" 184
|
||||
"../../../Engine/Content/EngineMaterials/STBlueNoise_scalar_128x128x64.uasset" 185
|
||||
"../../../Engine/Content/EngineMaterials/STBlueNoise_scalar_128x128x64.uexp" 186
|
||||
"../../../Engine/Content/EngineMaterials/RemoveSurfaceMaterial.uasset" 187
|
||||
"../../../Engine/Content/EngineMaterials/RemoveSurfaceMaterial.uexp" 188
|
||||
"../../../Engine/Content/EngineMaterials/DefaultCalibrationGrayscale.uasset" 189
|
||||
"../../../Engine/Content/EngineMaterials/DefaultCalibrationGrayscale.uexp" 190
|
||||
"../../../Engine/Content/EngineMaterials/PPM_DefaultCalibrationGrayscale.uasset" 191
|
||||
"../../../Engine/Content/EngineMaterials/PPM_DefaultCalibrationGrayscale.uexp" 192
|
||||
"../../../Engine/Content/EngineMaterials/DefaultCalibrationColor.uasset" 193
|
||||
"../../../Engine/Content/EngineMaterials/DefaultCalibrationColor.uexp" 194
|
||||
"../../../Engine/Content/EngineMaterials/PPM_DefaultCalibrationColor.uasset" 195
|
||||
"../../../Engine/Content/EngineMaterials/PPM_DefaultCalibrationColor.uexp" 196
|
||||
"../../../Engine/Plugins/Runtime/MeshModelingToolset/Content/Materials/M_DynamicMeshComponentVtxColor.uasset" 197
|
||||
"../../../Engine/Plugins/Runtime/MeshModelingToolset/Content/Materials/M_DynamicMeshComponentVtxColor.uexp" 198
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultTexturePipeline.uasset" 199
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultTexturePipeline.uexp" 200
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultSceneLevelPipeline.uasset" 201
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultSceneLevelPipeline.uexp" 202
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultSceneAssetsPipeline.uasset" 203
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultSceneAssetsPipeline.uexp" 204
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultMaterialPipeline.uasset" 205
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultMaterialPipeline.uexp" 206
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultAssetsPipeline.uasset" 207
|
||||
"../../../Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultAssetsPipeline.uexp" 208
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/game_wind_noise.ubulk" 209
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/game_wind_noise.uasset" 210
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/game_wind_noise.uexp" 211
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/UnpackDirection.uasset" 212
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/UnpackDirection.uexp" 213
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/ObjectLocalBounds.uasset" 214
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/ObjectLocalBounds.uexp" 215
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/BreakOutFloat3Components.uasset" 216
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/BreakOutFloat3Components.uexp" 217
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/UVs/BoundingBoxBased_0-1_UVW.uasset" 218
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/UVs/BoundingBoxBased_0-1_UVW.uexp" 219
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/VectorLength.uasset" 220
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/VectorLength.uexp" 221
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/UnpackInteger3.uasset" 222
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/UnpackInteger3.uexp" 223
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeCameraFacing.uasset" 224
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeCameraFacing.uexp" 225
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/WorldPositionOffset/ObjectScale.uasset" 226
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/WorldPositionOffset/ObjectScale.uexp" 227
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/SafeNormalize.uasset" 228
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/SafeNormalize.uexp" 229
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeWindMotion.uasset" 230
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeWindMotion.uexp" 231
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeBranchMotion.uasset" 232
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeBranchMotion.uexp" 233
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeWind.uasset" 234
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeWind.uexp" 235
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/EmptyNormal.uasset" 236
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/EmptyNormal.uexp" 237
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/Empty.uasset" 238
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/Empty.uexp" 239
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeMaster.uasset" 240
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeMaster.uexp" 241
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeBillboard.uasset" 242
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeBillboard.uexp" 243
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeBillboardMaster.uasset" 244
|
||||
"../../../Engine/Plugins/Editor/SpeedTreeImporter/Content/SpeedTree9/SpeedTreeBillboardMaster.uexp" 245
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/DefaultGizmoLibraryNormalized.uasset" 246
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/DefaultGizmoLibraryNormalized.uexp" 247
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_solid.ubulk" 248
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_solid.uasset" 249
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_solid.uexp" 250
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_3mm.ubulk" 251
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_3mm.uasset" 252
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_3mm.uexp" 253
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_1mm.ubulk" 254
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_1mm.uasset" 255
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Wedge_1mm.uexp" 256
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_solid.ubulk" 257
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_solid.uasset" 258
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_solid.uexp" 259
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_3mm.ubulk" 260
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_3mm.uasset" 261
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_3mm.uexp" 262
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_1mm.ubulk" 263
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_1mm.uasset" 264
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Triangle_1mm.uexp" 265
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_solid.ubulk" 266
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_solid.uasset" 267
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_solid.uexp" 268
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_3mm.ubulk" 269
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_3mm.uasset" 270
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_3mm.uexp" 271
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_1mm.ubulk" 272
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_1mm.uasset" 273
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Star4_1mm.uexp" 274
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_solid.ubulk" 275
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_solid.uasset" 276
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_solid.uexp" 277
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_3mm.ubulk" 278
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_3mm.uasset" 279
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_3mm.uexp" 280
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_1mm.ubulk" 281
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_1mm.uasset" 282
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Square_1mm.uexp" 283
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_solid.ubulk" 284
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_solid.uasset" 285
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_solid.uexp" 286
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_3mm.ubulk" 287
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_3mm.uasset" 288
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_3mm.uexp" 289
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_1mm.ubulk" 290
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_1mm.uasset" 291
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Sphere_1mm.uexp" 292
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_solid.ubulk" 293
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_solid.uasset" 294
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_solid.uexp" 295
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_3mm.ubulk" 296
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_3mm.uasset" 297
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_3mm.uexp" 298
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_1mm.ubulk" 299
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_1mm.uasset" 300
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedTriangle_1mm.uexp" 301
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_solid.ubulk" 302
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_solid.uasset" 303
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_solid.uexp" 304
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_3mm.ubulk" 305
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_3mm.uasset" 306
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_3mm.uexp" 307
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_1mm.ubulk" 308
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_1mm.uasset" 309
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_RoundedSquare_1mm.uexp" 310
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_solid.ubulk" 311
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_solid.uasset" 312
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_solid.uexp" 313
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_3mm.ubulk" 314
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_3mm.uasset" 315
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_3mm.uexp" 316
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_1mm.ubulk" 317
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_1mm.uasset" 318
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_QuarterCircle_1mm.uexp" 319
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_solid.ubulk" 320
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_solid.uasset" 321
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_solid.uexp" 322
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_3mm.ubulk" 323
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_3mm.uasset" 324
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_3mm.uexp" 325
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_1mm.ubulk" 326
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_1mm.uasset" 327
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Pyramid_1mm.uexp" 328
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_solid.ubulk" 329
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_solid.uasset" 330
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_solid.uexp" 331
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_3mm.ubulk" 332
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_3mm.uasset" 333
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_3mm.uexp" 334
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_1mm.ubulk" 335
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_1mm.uasset" 336
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Octagon_1mm.uexp" 337
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_solid.ubulk" 338
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_solid.uasset" 339
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_solid.uexp" 340
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_3mm.ubulk" 341
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_3mm.uasset" 342
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_3mm.uexp" 343
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_1mm.ubulk" 344
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_1mm.uasset" 345
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Hexagon_1mm.uexp" 346
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_solid.ubulk" 347
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_solid.uasset" 348
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_solid.uexp" 349
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_3mm.ubulk" 350
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_3mm.uasset" 351
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_3mm.uexp" 352
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_1mm.ubulk" 353
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_1mm.uasset" 354
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_HalfCircle_1mm.uexp" 355
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_solid.ubulk" 356
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_solid.uasset" 357
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_solid.uexp" 358
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_3mm.ubulk" 359
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_3mm.uasset" 360
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_3mm.uexp" 361
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_1mm.ubulk" 362
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_1mm.uasset" 363
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Diamond_1mm.uexp" 364
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_solid.ubulk" 365
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_solid.uasset" 366
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_solid.uexp" 367
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_3mm.ubulk" 368
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_3mm.uasset" 369
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_3mm.uexp" 370
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_1mm.ubulk" 371
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_1mm.uasset" 372
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Circle_1mm.uexp" 373
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_solid.ubulk" 374
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_solid.uasset" 375
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_solid.uexp" 376
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_3mm.ubulk" 377
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_3mm.uasset" 378
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_3mm.uexp" 379
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_1mm.ubulk" 380
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_1mm.uasset" 381
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Box_1mm.uexp" 382
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_solid.ubulk" 383
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_solid.uasset" 384
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_solid.uexp" 385
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_3mm.ubulk" 386
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_3mm.uasset" 387
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_3mm.uexp" 388
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_1mm.ubulk" 389
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_1mm.uasset" 390
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow_1mm.uexp" 391
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_solid.ubulk" 392
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_solid.uasset" 393
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_solid.uexp" 394
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_3mm.ubulk" 395
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_3mm.uasset" 396
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_3mm.uexp" 397
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_1mm.ubulk" 398
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_1mm.uasset" 399
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow4_1mm.uexp" 400
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_solid.ubulk" 401
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_solid.uasset" 402
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_solid.uexp" 403
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_3mm.ubulk" 404
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_3mm.uasset" 405
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_3mm.uexp" 406
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_1mm.ubulk" 407
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_1mm.uasset" 408
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRig_Arrow2_1mm.uexp" 409
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRigXRayMaterial.uasset" 410
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRigXRayMaterial.uexp" 411
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRigGizmoMaterial.uasset" 412
|
||||
"../../../Engine/Plugins/Animation/ControlRig/Content/Controls/ControlRigGizmoMaterial.uexp" 413
|
||||
"../../../Engine/Content/EngineSounds/Master.uasset" 414
|
||||
"../../../Engine/Content/EngineSounds/Master.uexp" 415
|
||||
"../../../Engine/Content/EngineMaterials/PhAT_JointLimitMaterial.uasset" 416
|
||||
"../../../Engine/Content/EngineMaterials/PhAT_JointLimitMaterial.uexp" 417
|
||||
"../../../Engine/Content/EngineMaterials/NaniteHiddenSectionMaterial.uasset" 418
|
||||
"../../../Engine/Content/EngineMaterials/NaniteHiddenSectionMaterial.uexp" 419
|
||||
"../../../Engine/Content/EngineMaterials/InvalidLightmapSettings.ubulk" 420
|
||||
"../../../Engine/Content/EngineMaterials/InvalidLightmapSettings.uasset" 421
|
||||
"../../../Engine/Content/EngineMaterials/InvalidLightmapSettings.uexp" 422
|
||||
"../../../Engine/Content/EngineMaterials/M_InvalidLightmapSettings.uasset" 423
|
||||
"../../../Engine/Content/EngineMaterials/M_InvalidLightmapSettings.uexp" 424
|
||||
"../../../Engine/Content/EngineMaterials/GizmoMaterial.uasset" 425
|
||||
"../../../Engine/Content/EngineMaterials/GizmoMaterial.uexp" 426
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenEmissiveMap_VT.uasset" 427
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenEmissiveMap_VT.uexp" 428
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenGrayscaleMap_VT.uasset" 429
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenGrayscaleMap_VT.uexp" 430
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenLinearColor_VT.uasset" 431
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenLinearColor_VT.uexp" 432
|
||||
"../../../Engine/Content/EngineMaterials/Black_1x1_EXR_Texture_VT.uasset" 433
|
||||
"../../../Engine/Content/EngineMaterials/Black_1x1_EXR_Texture_VT.uexp" 434
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenDiffuseMap_VT.uasset" 435
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenDiffuseMap_VT.uexp" 436
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenNormalMap_VT.uasset" 437
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenNormalMap_VT.uexp" 438
|
||||
"../../../Engine/Content/EngineMaterials/FlattenMaterial_WS_Normal_VT.uasset" 439
|
||||
"../../../Engine/Content/EngineMaterials/FlattenMaterial_WS_Normal_VT.uexp" 440
|
||||
"../../../Engine/Content/EngineMaterials/FlattenMaterial_VT.uasset" 441
|
||||
"../../../Engine/Content/EngineMaterials/FlattenMaterial_VT.uexp" 442
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenNormalMap.uasset" 443
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenNormalMap.uexp" 444
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenGrayscaleMap.uasset" 445
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenGrayscaleMap.uexp" 446
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenDiffuseMap.uasset" 447
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenDiffuseMap.uexp" 448
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/PivotPainter2/Black_1x1_EXR_Texture.uasset" 449
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/PivotPainter2/Black_1x1_EXR_Texture.uexp" 450
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenEmissiveMap.uasset" 451
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenEmissiveMap.uexp" 452
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenLinearColor.uasset" 453
|
||||
"../../../Engine/Content/EngineMaterials/BaseFlattenLinearColor.uexp" 454
|
||||
"../../../Engine/Content/EngineMaterials/FlattenMaterial.uasset" 455
|
||||
"../../../Engine/Content/EngineMaterials/FlattenMaterial.uexp" 456
|
||||
"../../../Engine/Content/EngineMaterials/DefaultWhiteGrid_Low.uasset" 457
|
||||
"../../../Engine/Content/EngineMaterials/DefaultWhiteGrid_Low.uexp" 458
|
||||
"../../../Engine/Content/EngineMaterials/EmissiveMeshMaterial.uasset" 459
|
||||
"../../../Engine/Content/EngineMaterials/EmissiveMeshMaterial.uexp" 460
|
||||
"../../../Engine/Content/EngineFonts/RobotoDistanceField.uasset" 461
|
||||
"../../../Engine/Content/EngineFonts/RobotoDistanceField.uexp" 462
|
||||
"../../../Engine/Content/EngineMaterials/DefaultTextMaterialOpaque.uasset" 463
|
||||
"../../../Engine/Content/EngineMaterials/DefaultTextMaterialOpaque.uexp" 464
|
||||
"../../../Engine/Content/EngineMaterials/DefaultDiffuse.ubulk" 465
|
||||
"../../../Engine/Content/EngineMaterials/DefaultDiffuse.uasset" 466
|
||||
"../../../Engine/Content/EngineMaterials/DefaultDiffuse.uexp" 467
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/BreakOutFloat2Components.uasset" 468
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/BreakOutFloat2Components.uexp" 469
|
||||
"../../../Engine/Content/EngineMaterials/DefaultPostProcessMaterial.uasset" 470
|
||||
"../../../Engine/Content/EngineMaterials/DefaultPostProcessMaterial.uexp" 471
|
||||
"../../../Engine/Content/EngineMaterials/DefaultPhysicalMaterial.uasset" 472
|
||||
"../../../Engine/Content/EngineMaterials/DefaultPhysicalMaterial.uexp" 473
|
||||
"../../../Engine/Content/EngineMaterials/DefaultLightFunctionMaterial.uasset" 474
|
||||
"../../../Engine/Content/EngineMaterials/DefaultLightFunctionMaterial.uexp" 475
|
||||
"../../../Engine/Content/EngineMaterials/DefaultDestructiblePhysicalMaterial.uasset" 476
|
||||
"../../../Engine/Content/EngineMaterials/DefaultDestructiblePhysicalMaterial.uexp" 477
|
||||
"../../../Engine/Content/EngineMaterials/DefaultDeferredDecalMaterial.uasset" 478
|
||||
"../../../Engine/Content/EngineMaterials/DefaultDeferredDecalMaterial.uexp" 479
|
||||
"../../../Engine/Content/EngineMaterials/DefaultBloomKernel.uasset" 480
|
||||
"../../../Engine/Content/EngineMaterials/DefaultBloomKernel.uexp" 481
|
||||
"../../../Engine/Content/MobileResources/HUD/VirtualJoystick_Background.uasset" 482
|
||||
"../../../Engine/Content/MobileResources/HUD/VirtualJoystick_Background.uexp" 483
|
||||
"../../../Engine/Content/MobileResources/HUD/VirtualJoystick_Thumb.uasset" 484
|
||||
"../../../Engine/Content/MobileResources/HUD/VirtualJoystick_Thumb.uexp" 485
|
||||
"../../../Engine/Content/MobileResources/HUD/DefaultVirtualJoysticks.uasset" 486
|
||||
"../../../Engine/Content/MobileResources/HUD/DefaultVirtualJoysticks.uexp" 487
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/CloudWeatherTexture.uasset" 488
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/CloudWeatherTexture.uexp" 489
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/MakeFloat2.uasset" 490
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/MakeFloat2.uexp" 491
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/CloudGradientTexture.uasset" 492
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/CloudGradientTexture.uexp" 493
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_NoiseShape64.ubulk" 494
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_NoiseShape64.uasset" 495
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_NoiseShape64.uexp" 496
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_VolumeNoiseShape64.uasset" 497
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_VolumeNoiseShape64.uexp" 498
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_NoiseErosion.ubulk" 499
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_NoiseErosion.uasset" 500
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_NoiseErosion.uexp" 501
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_VolumeNoiseErosion32.uasset" 502
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/T_VolumeNoiseErosion32.uexp" 503
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/m_SimpleVolumetricCloud.uasset" 504
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/m_SimpleVolumetricCloud.uexp" 505
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/m_SimpleVolumetricCloud_Inst.uasset" 506
|
||||
"../../../Engine/Content/EngineSky/VolumetricClouds/m_SimpleVolumetricCloud_Inst.uexp" 507
|
||||
"../../../Engine/Content/EngineResources/FilmGrains/Marcie_Grain_v3_128_M2_000.uasset" 508
|
||||
"../../../Engine/Content/EngineResources/FilmGrains/Marcie_Grain_v3_128_M2_000.uexp" 509
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoLight.uexp" 510
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoLight.uasset" 511
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoLight.ufont" 512
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoBold.uexp" 513
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoBold.uasset" 514
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoBold.ufont" 515
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoRegular.uexp" 516
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoRegular.uasset" 517
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoRegular.ufont" 518
|
||||
"../../../Engine/Content/EngineFonts/Faces/DroidSansFallback.uexp" 519
|
||||
"../../../Engine/Content/EngineFonts/Faces/DroidSansFallback.uasset" 520
|
||||
"../../../Engine/Content/EngineFonts/Faces/DroidSansFallback.ufont" 521
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoItalic.uexp" 522
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoItalic.uasset" 523
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoItalic.ufont" 524
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoBoldItalic.uexp" 525
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoBoldItalic.uasset" 526
|
||||
"../../../Engine/Content/EngineFonts/Faces/RobotoBoldItalic.ufont" 527
|
||||
"../../../Engine/Content/EngineFonts/Roboto.uasset" 528
|
||||
"../../../Engine/Content/EngineFonts/Roboto.uexp" 529
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/CameraDirectionVector.uasset" 530
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions02/Utility/CameraDirectionVector.uexp" 531
|
||||
"../../../Engine/Content/EngineDebugMaterials/VolumeToRender.uasset" 532
|
||||
"../../../Engine/Content/EngineDebugMaterials/VolumeToRender.uexp" 533
|
||||
"../../../Engine/Content/EngineDebugMaterials/M_VolumeRenderSphereTracePP.uasset" 534
|
||||
"../../../Engine/Content/EngineDebugMaterials/M_VolumeRenderSphereTracePP.uexp" 535
|
||||
"../../../Engine/Content/EngineDebugMaterials/M_SimpleUnlitTranslucent.uasset" 536
|
||||
"../../../Engine/Content/EngineDebugMaterials/M_SimpleUnlitTranslucent.uexp" 537
|
||||
"../../../Engine/Content/EngineDebugMaterials/DebugMeshMaterial.uasset" 538
|
||||
"../../../Engine/Content/EngineDebugMaterials/DebugMeshMaterial.uexp" 539
|
||||
"../../../Engine/Content/EngineDebugMaterials/DebugEditorMaterial.uasset" 540
|
||||
"../../../Engine/Content/EngineDebugMaterials/DebugEditorMaterial.uexp" 541
|
||||
"../../../Engine/Content/EngineDamageTypes/DmgTypeBP_Environmental.uasset" 542
|
||||
"../../../Engine/Content/EngineDamageTypes/DmgTypeBP_Environmental.uexp" 543
|
||||
"../../../Engine/Content/EditorResources/S_Terrain.ubulk" 544
|
||||
"../../../Engine/Content/EditorResources/S_Terrain.uasset" 545
|
||||
"../../../Engine/Content/EditorResources/S_Terrain.uexp" 546
|
||||
"../../../Engine/Content/EditorResources/BSPVertex.uasset" 547
|
||||
"../../../Engine/Content/EditorResources/BSPVertex.uexp" 548
|
||||
"../../../Engine/Content/EditorResources/SequenceRecorder/RecordingIndicator.uasset" 549
|
||||
"../../../Engine/Content/EditorResources/SequenceRecorder/RecordingIndicator.uexp" 550
|
||||
"../../../Engine/Content/EditorResources/SequenceRecorder/Countdown.uasset" 551
|
||||
"../../../Engine/Content/EditorResources/SequenceRecorder/Countdown.uexp" 552
|
||||
"../../../Engine/Content/EditorLandscapeResources/DefaultAlphaTexture.uasset" 553
|
||||
"../../../Engine/Content/EditorLandscapeResources/DefaultAlphaTexture.uexp" 554
|
||||
"../../../Engine/Content/EditorLandscapeResources/DataLayer.uasset" 555
|
||||
"../../../Engine/Content/EditorLandscapeResources/DataLayer.uexp" 556
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions01/Shading/PowerToRoughness.uasset" 557
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions01/Shading/PowerToRoughness.uexp" 558
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions01/Shading/ConvertFromDiffSpec.uasset" 559
|
||||
"../../../Engine/Content/Functions/Engine_MaterialFunctions01/Shading/ConvertFromDiffSpec.uexp" 560
|
||||
"D:/Project/Cut5/Content/MainMap.uexp" 561
|
||||
"D:/Project/Cut5/Content/MainMap.umap" 562
|
||||
"../../../Engine/Content/Maps/Entry_BuiltData.uasset" 563
|
||||
"../../../Engine/Content/Maps/Entry_BuiltData.uexp" 564
|
||||
"../../../Engine/Content/Maps/Entry.uexp" 565
|
||||
"../../../Engine/Content/Maps/Entry.umap" 566
|
3553
Build/Windows/FileOpenOrder/EditorOpenOrder.log
Normal file
3553
Build/Windows/FileOpenOrder/EditorOpenOrder.log
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -28,11 +28,7 @@
|
||||
{
|
||||
"Name": "SoundUtilities",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "RuntimeAudioImporter",
|
||||
"Enabled": true,
|
||||
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/81fd278e318e4235a028d3fdf46bf036"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
Binary file not shown.
Binary file not shown.
BIN
DefaultProject/DefaultProject.bin
Normal file
BIN
DefaultProject/DefaultProject.bin
Normal file
Binary file not shown.
@ -1,55 +0,0 @@
|
||||
<Project(DefaultProject)>
|
||||
<Standard>
|
||||
<File>
|
||||
<Author>Sch</Author>
|
||||
</File>
|
||||
</Standard>
|
||||
<DeviceList>
|
||||
<PlayerLightList/>
|
||||
<DMLightList/>
|
||||
<GuangZhenList>
|
||||
<GuangZhen>
|
||||
<ID>2</ID>
|
||||
<RoleName>光阵</RoleName>
|
||||
</GuangZhen>
|
||||
</GuangZhenList>
|
||||
<RotationSpeakerList>
|
||||
<RotationSpeaker>
|
||||
<ID>0</ID>
|
||||
<RoleName>音频R</RoleName>
|
||||
</RotationSpeaker>
|
||||
</RotationSpeakerList>
|
||||
<ProjectorList>
|
||||
<Projector>
|
||||
<ID>1</ID>
|
||||
<RoleName>投影仪</RoleName>
|
||||
</Projector>
|
||||
</ProjectorList>
|
||||
</DeviceList>
|
||||
<CardList/>
|
||||
<KeyBoard/>
|
||||
<ProcessList>
|
||||
<ProcessA>
|
||||
<ProcessB>
|
||||
<ID/>
|
||||
<AutoNext/>
|
||||
<TimeLength/>
|
||||
<SoundList>
|
||||
<Sound>
|
||||
<URL/>
|
||||
<Loop/>
|
||||
<Mode/>
|
||||
<Round/>
|
||||
<Timecode/>
|
||||
<VolumeEventList>
|
||||
<VolumeEvent>
|
||||
<TimeCode/>
|
||||
<Value/>
|
||||
</VolumeEvent>
|
||||
</VolumeEventList>
|
||||
</Sound>
|
||||
</SoundList>
|
||||
</ProcessB>
|
||||
</ProcessA>
|
||||
</ProcessList>
|
||||
</Project(DefaultProject)>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 2.9 KiB |
@ -1,28 +0,0 @@
|
||||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 1,
|
||||
"VersionName": "1.0",
|
||||
"FriendlyName": "Runtime Audio Importer",
|
||||
"Description": "Runtime Audio Importer is an open-source plugin for importing audio of various formats at runtime, including MP3, WAV, FLAC, OGG Vorbis, BINK, and RAW (int8, uint8, int16, uint16, int32, uint32, float32).",
|
||||
"Category": "Audio",
|
||||
"CreatedBy": "Georgy Treshchev",
|
||||
"CreatedByURL": "https://github.com/gtreshchev",
|
||||
"DocsURL": "https://github.com/gtreshchev/RuntimeAudioImporter/wiki",
|
||||
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/81fd278e318e4235a028d3fdf46bf036",
|
||||
"SupportURL": "https://georgy.dev/",
|
||||
"EngineVersion": "5.2.0",
|
||||
"CanContainContent": true,
|
||||
"Installed": true,
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "RuntimeAudioImporter",
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "Default"
|
||||
},
|
||||
{
|
||||
"Name": "RuntimeAudioImporterEditor",
|
||||
"Type": "Editor",
|
||||
"LoadingPhase": "Default"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Codecs/BINK_RuntimeCodec.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "Codecs/RAW_RuntimeCodec.h"
|
||||
#include "HAL/PlatformProperties.h"
|
||||
#include "HAL/UnrealMemory.h"
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_BINK_DECODE_SUPPORT
|
||||
#include "BinkAudioInfo.h"
|
||||
#include "Interfaces/IAudioFormat.h"
|
||||
#endif
|
||||
|
||||
#define INCLUDE_BINK
|
||||
#include "CodecIncludes.h"
|
||||
#undef INCLUDE_BINK
|
||||
|
||||
|
||||
/**
|
||||
* Taken from AudioFormatBink.cpp
|
||||
*/
|
||||
namespace
|
||||
{
|
||||
uint8 GetCompressionLevelFromQualityIndex(int32 InQualityIndex)
|
||||
{
|
||||
// Bink goes from 0 (best) to 9 (worst), but is basically unusable below 4
|
||||
static constexpr float BinkLowest = 4;
|
||||
static constexpr float BinkHighest = 0;
|
||||
|
||||
// Map Quality 1 (lowest) to 40 (highest)
|
||||
static constexpr float QualityLowest = 1;
|
||||
static constexpr float QualityHighest = 40;
|
||||
|
||||
return FMath::GetMappedRangeValueClamped(FVector2D(QualityLowest, QualityHighest), FVector2D(BinkLowest, BinkHighest), InQualityIndex);
|
||||
}
|
||||
|
||||
void* BinkAlloc(size_t Bytes)
|
||||
{
|
||||
return FMemory::Malloc(Bytes, 16);
|
||||
}
|
||||
|
||||
void BinkFree(void* Ptr)
|
||||
{
|
||||
FMemory::Free(Ptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool FBINK_RuntimeCodec::CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData)
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_BINK_DECODE_SUPPORT
|
||||
FBinkAudioInfo AudioInfo;
|
||||
FSoundQualityInfo SoundQualityInfo;
|
||||
|
||||
if (!AudioInfo.ReadCompressedInfo(AudioData.GetView().GetData(), AudioData.GetView().Num(), &SoundQualityInfo) || SoundQualityInfo.SampleDataSize == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support BINK decoding"), FPlatformProperties::IniPlatformName());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FBINK_RuntimeCodec::GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Retrieving header information for the BINK audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to retrieve audio header information in the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_BINK_DECODE_SUPPORT
|
||||
FBinkAudioInfo AudioInfo;
|
||||
FSoundQualityInfo SoundQualityInfo;
|
||||
|
||||
if (!AudioInfo.ReadCompressedInfo(EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), &SoundQualityInfo) || SoundQualityInfo.SampleDataSize == 0)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to read BINK compressed info"));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
HeaderInfo.Duration = SoundQualityInfo.Duration;
|
||||
HeaderInfo.SampleRate = SoundQualityInfo.SampleRate;
|
||||
HeaderInfo.NumOfChannels = SoundQualityInfo.NumChannels;
|
||||
HeaderInfo.PCMDataSize = SoundQualityInfo.SampleDataSize / sizeof(int16);
|
||||
HeaderInfo.AudioFormat = GetAudioFormat();
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully retrieved header information for FLAC audio format.\nHeader info: %s"), *HeaderInfo.ToString());
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support BINK decoding"), FPlatformProperties::IniPlatformName());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FBINK_RuntimeCodec::Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Encoding uncompressed audio data to BINK audio format.\nDecoded audio info: %s.\nQuality: %d"), *DecodedData.ToString(), Quality);
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_BINK_ENCODE_SUPPORT
|
||||
const uint8 CompressionLevel = GetCompressionLevelFromQualityIndex(Quality);
|
||||
|
||||
int16* TempInt16Buffer;
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<float, int16>(DecodedData.PCMInfo.PCMData.GetView().GetData(), DecodedData.PCMInfo.PCMData.GetView().Num(), TempInt16Buffer);
|
||||
|
||||
void* CompressedData = nullptr;
|
||||
uint32_t CompressedDataLen = 0;
|
||||
UECompressBinkAudio(static_cast<void*>(TempInt16Buffer), DecodedData.PCMInfo.PCMData.GetView().Num() * sizeof(int16), DecodedData.SoundWaveBasicInfo.SampleRate, DecodedData.SoundWaveBasicInfo.NumOfChannels, CompressionLevel, 1, BinkAlloc, BinkFree, &CompressedData, &CompressedDataLen);
|
||||
|
||||
if (CompressedDataLen <= 0)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to decode BINK audio data: the uncompressed data is empty"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Populating the encoded audio data
|
||||
{
|
||||
EncodedData.AudioData = FRuntimeBulkDataBuffer<uint8>(static_cast<uint8*>(CompressedData), CompressedDataLen);
|
||||
EncodedData.AudioFormat = ERuntimeAudioFormat::Bink;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully encoded uncompressed audio data to BINK audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support BINK encoding"), FPlatformProperties::IniPlatformName());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FBINK_RuntimeCodec::Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Decoding BINK audio data to uncompressed audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to decode audio data using the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_BINK_DECODE_SUPPORT
|
||||
FBinkAudioInfo AudioInfo;
|
||||
FSoundQualityInfo SoundQualityInfo;
|
||||
|
||||
// Parse the audio header for the relevant information
|
||||
if (!AudioInfo.ReadCompressedInfo(EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), &SoundQualityInfo))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to read BINK compressed info"));
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray64<uint8> PCMData;
|
||||
|
||||
// Decompress all the sample data
|
||||
PCMData.Empty(SoundQualityInfo.SampleDataSize);
|
||||
PCMData.AddZeroed(SoundQualityInfo.SampleDataSize);
|
||||
AudioInfo.ExpandFile(PCMData.GetData(), &SoundQualityInfo);
|
||||
|
||||
// Getting the number of frames
|
||||
DecodedData.PCMInfo.PCMNumOfFrames = PCMData.Num() / SoundQualityInfo.NumChannels / sizeof(int16);
|
||||
|
||||
const int64 NumOfSamples = PCMData.Num() / sizeof(int16);
|
||||
|
||||
// Transcoding int16 to float format
|
||||
{
|
||||
float* TempFloatBuffer;
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<int16, float>(reinterpret_cast<int16*>(PCMData.GetData()), NumOfSamples, TempFloatBuffer);
|
||||
DecodedData.PCMInfo.PCMData = FRuntimeBulkDataBuffer<float>(TempFloatBuffer, NumOfSamples);
|
||||
}
|
||||
|
||||
// Getting basic audio information
|
||||
{
|
||||
DecodedData.SoundWaveBasicInfo.Duration = SoundQualityInfo.Duration;
|
||||
DecodedData.SoundWaveBasicInfo.NumOfChannels = SoundQualityInfo.NumChannels;
|
||||
DecodedData.SoundWaveBasicInfo.SampleRate = SoundQualityInfo.SampleRate;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully decoded BINK audio data to uncompressed audio format.\nDecoded audio info: %s"), *DecodedData.ToString());
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support BINK decoding"), FPlatformProperties::IniPlatformName());
|
||||
return false;
|
||||
#endif
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
/**
|
||||
* Replacing C dynamic memory management functions
|
||||
* (calloc, malloc, free, realloc, memset, memcpy) with FMemory ones
|
||||
*/
|
||||
#undef calloc
|
||||
#undef malloc
|
||||
#undef free
|
||||
#undef realloc
|
||||
#undef memset
|
||||
#undef memcpy
|
||||
|
||||
#define calloc(Count, Size) [&]() { void* MemPtr = FMemory::Malloc(Count * Size); if (MemPtr) { FMemory::Memset(MemPtr, 0, Count * Size); } return MemPtr; }()
|
||||
#define malloc(Count) FMemory::Malloc(Count)
|
||||
#define free(Original) FMemory::Free(Original)
|
||||
#define realloc(Original, Count) FMemory::Realloc(Original, Count)
|
||||
#define memset(Dest, Char, Count) FMemory::Memset(Dest, Char, Count)
|
||||
#define memcpy(Dest, Src, Count) FMemory::Memcpy(Dest, Src, Count)
|
||||
|
||||
#ifdef INCLUDE_MP3
|
||||
#define DRMP3_API static
|
||||
#define DRMP3_PRIVATE static
|
||||
#include "ThirdParty/dr_mp3.h"
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_WAV
|
||||
#define DRWAV_API static
|
||||
#define DRWAV_PRIVATE static
|
||||
#include "ThirdParty/dr_wav.h"
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_FLAC
|
||||
#define DRFLAC_API static
|
||||
#define DRFLAC_PRIVATE static
|
||||
#include "ThirdParty/dr_flac.h"
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_VORBIS
|
||||
#if PLATFORM_SUPPORTS_VORBIS_CODEC
|
||||
#pragma pack(push, 8)
|
||||
#include "vorbis/vorbisenc.h"
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_BINK_ENCODE_SUPPORT
|
||||
#ifdef INCLUDE_BINK
|
||||
#include "binka_ue_file_header.h"
|
||||
#include "binka_ue_encode.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef calloc
|
||||
#undef malloc
|
||||
#undef free
|
||||
#undef realloc
|
||||
#undef memset
|
||||
#undef memcpy
|
@ -1,101 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Codecs/FLAC_RuntimeCodec.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "HAL/UnrealMemory.h"
|
||||
|
||||
#define INCLUDE_FLAC
|
||||
#include "CodecIncludes.h"
|
||||
#undef INCLUDE_FLAC
|
||||
|
||||
bool FFLAC_RuntimeCodec::CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData)
|
||||
{
|
||||
drflac* FLAC = drflac_open_memory(AudioData.GetView().GetData(), AudioData.GetView().Num(), nullptr);
|
||||
|
||||
if (!FLAC)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
drflac_close(FLAC);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FFLAC_RuntimeCodec::GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Retrieving header information for FLAC audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to retrieve audio header information in the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
drflac* FLAC = drflac_open_memory(EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), nullptr);
|
||||
if (!FLAC)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to initialize FLAC Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
HeaderInfo.Duration = static_cast<float>(FLAC->totalPCMFrameCount) / FLAC->sampleRate;
|
||||
HeaderInfo.NumOfChannels = FLAC->channels;
|
||||
HeaderInfo.SampleRate = FLAC->sampleRate;
|
||||
HeaderInfo.PCMDataSize = FLAC->totalPCMFrameCount * FLAC->channels;
|
||||
HeaderInfo.AudioFormat = GetAudioFormat();
|
||||
}
|
||||
|
||||
drflac_close(FLAC);
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully retrieved header information for FLAC audio format.\nHeader info: %s"), *HeaderInfo.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FFLAC_RuntimeCodec::Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality)
|
||||
{
|
||||
ensureMsgf(false, TEXT("FLAC codec does not support encoding at the moment"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FFLAC_RuntimeCodec::Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Decoding FLAC audio data to uncompressed audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to decode audio data using the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
// Initializing FLAC codec
|
||||
drflac* FLAC_Decoder = drflac_open_memory(EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), nullptr);
|
||||
|
||||
if (!FLAC_Decoder)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to initialize FLAC Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocating memory for PCM data
|
||||
float* TempPCMData = static_cast<float*>(FMemory::Malloc(FLAC_Decoder->totalPCMFrameCount * FLAC_Decoder->channels * sizeof(float)));
|
||||
|
||||
if (!TempPCMData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to allocate memory for FLAC Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filling in PCM data and getting the number of frames
|
||||
DecodedData.PCMInfo.PCMNumOfFrames = drflac_read_pcm_frames_f32(FLAC_Decoder, FLAC_Decoder->totalPCMFrameCount, TempPCMData);
|
||||
|
||||
// Getting PCM data size
|
||||
const int64 TempPCMDataSize = static_cast<int64>(DecodedData.PCMInfo.PCMNumOfFrames * FLAC_Decoder->channels);
|
||||
|
||||
DecodedData.PCMInfo.PCMData = FRuntimeBulkDataBuffer<float>(TempPCMData, TempPCMDataSize);
|
||||
|
||||
// Getting basic audio information
|
||||
{
|
||||
DecodedData.SoundWaveBasicInfo.Duration = static_cast<float>(FLAC_Decoder->totalPCMFrameCount) / FLAC_Decoder->sampleRate;
|
||||
DecodedData.SoundWaveBasicInfo.NumOfChannels = FLAC_Decoder->channels;
|
||||
DecodedData.SoundWaveBasicInfo.SampleRate = FLAC_Decoder->sampleRate;
|
||||
}
|
||||
|
||||
drflac_close(FLAC_Decoder);
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully decoded FLAC audio data to uncompressed audio format.\nDecoded audio info: %s"), *DecodedData.ToString());
|
||||
return true;
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Codecs/MP3_RuntimeCodec.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "HAL/UnrealMemory.h"
|
||||
|
||||
#define INCLUDE_MP3
|
||||
#include "CodecIncludes.h"
|
||||
#undef INCLUDE_MP3
|
||||
|
||||
bool FMP3_RuntimeCodec::CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData)
|
||||
{
|
||||
drmp3 MP3;
|
||||
|
||||
if (!drmp3_init_memory(&MP3, AudioData.GetView().GetData(), AudioData.GetView().Num(), nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
drmp3_uninit(&MP3);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FMP3_RuntimeCodec::GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Retrieving header information for MP3 audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to retrieve audio header information in the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
drmp3 MP3;
|
||||
if (!drmp3_init_memory(&MP3, EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), nullptr))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to initialize MP3 Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const drmp3_uint64 PCMFrameCount = drmp3_get_pcm_frame_count(&MP3);
|
||||
|
||||
{
|
||||
HeaderInfo.Duration = static_cast<float>(PCMFrameCount) / MP3.sampleRate;
|
||||
HeaderInfo.NumOfChannels = MP3.channels;
|
||||
HeaderInfo.SampleRate = MP3.sampleRate;
|
||||
HeaderInfo.PCMDataSize = PCMFrameCount * MP3.channels;
|
||||
HeaderInfo.AudioFormat = GetAudioFormat();
|
||||
}
|
||||
|
||||
drmp3_uninit(&MP3);
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully retrieved header information for MP3 audio format.\nHeader info: %s"), *HeaderInfo.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FMP3_RuntimeCodec::Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality)
|
||||
{
|
||||
ensureMsgf(false, TEXT("MP3 codec does not support encoding at the moment"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FMP3_RuntimeCodec::Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Decoding MP3 audio data to uncompressed audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to decode audio data using the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
drmp3 MP3_Decoder;
|
||||
|
||||
// Initializing MP3 codec
|
||||
if (!drmp3_init_memory(&MP3_Decoder, EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), nullptr))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to initialize MP3 Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const drmp3_uint64 PCMFrameCount = drmp3_get_pcm_frame_count(&MP3_Decoder);
|
||||
|
||||
// Allocating memory for PCM data
|
||||
float* TempPCMData = static_cast<float*>(FMemory::Malloc(PCMFrameCount * MP3_Decoder.channels * sizeof(float)));
|
||||
|
||||
if (!TempPCMData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to allocate memory for MP3 Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filling in PCM data and getting the number of frames
|
||||
DecodedData.PCMInfo.PCMNumOfFrames = drmp3_read_pcm_frames_f32(&MP3_Decoder, PCMFrameCount, TempPCMData);
|
||||
|
||||
// Getting PCM data size
|
||||
const int64 TempPCMDataSize = static_cast<int64>(DecodedData.PCMInfo.PCMNumOfFrames * MP3_Decoder.channels);
|
||||
|
||||
DecodedData.PCMInfo.PCMData = FRuntimeBulkDataBuffer<float>(TempPCMData, TempPCMDataSize);
|
||||
|
||||
// Getting basic audio information
|
||||
{
|
||||
DecodedData.SoundWaveBasicInfo.Duration = static_cast<float>(PCMFrameCount) / MP3_Decoder.sampleRate;
|
||||
DecodedData.SoundWaveBasicInfo.NumOfChannels = MP3_Decoder.channels;
|
||||
DecodedData.SoundWaveBasicInfo.SampleRate = MP3_Decoder.sampleRate;
|
||||
}
|
||||
|
||||
drmp3_uninit(&MP3_Decoder);
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully decoded MP3 audio data to uncompressed audio format.\nDecoded audio info: %s"), *DecodedData.ToString());
|
||||
return true;
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Codecs/RuntimeCodecFactory.h"
|
||||
#include "Codecs/BaseRuntimeCodec.h"
|
||||
|
||||
#include "Codecs/MP3_RuntimeCodec.h"
|
||||
#include "Codecs/WAV_RuntimeCodec.h"
|
||||
#include "Codecs/FLAC_RuntimeCodec.h"
|
||||
#include "Codecs/VORBIS_RuntimeCodec.h"
|
||||
#include "Codecs/BINK_RuntimeCodec.h"
|
||||
|
||||
#include "Misc/Paths.h"
|
||||
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
|
||||
TUniquePtr<FBaseRuntimeCodec> FRuntimeCodecFactory::GetCodec(const FString& FilePath)
|
||||
{
|
||||
const FString Extension = FPaths::GetExtension(FilePath, false).ToLower();
|
||||
|
||||
if (Extension == TEXT("mp3"))
|
||||
{
|
||||
return MakeUnique<FMP3_RuntimeCodec>();
|
||||
}
|
||||
if (Extension == TEXT("wav") || Extension == TEXT("wave"))
|
||||
{
|
||||
return MakeUnique<FWAV_RuntimeCodec>();
|
||||
}
|
||||
if (Extension == TEXT("flac"))
|
||||
{
|
||||
return MakeUnique<FFLAC_RuntimeCodec>();
|
||||
}
|
||||
if (Extension == TEXT("ogg") || Extension == TEXT("oga") || Extension == TEXT("sb0"))
|
||||
{
|
||||
return MakeUnique<FVORBIS_RuntimeCodec>();
|
||||
}
|
||||
if (Extension == TEXT("bink") || Extension == TEXT("binka") || Extension == TEXT("bnk"))
|
||||
{
|
||||
return MakeUnique<FBINK_RuntimeCodec>();
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Warning, TEXT("Failed to determine the audio codec for '%s' using its file name"), *FilePath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TUniquePtr<FBaseRuntimeCodec> FRuntimeCodecFactory::GetCodec(ERuntimeAudioFormat AudioFormat)
|
||||
{
|
||||
switch (AudioFormat)
|
||||
{
|
||||
case ERuntimeAudioFormat::Mp3:
|
||||
return MakeUnique<FMP3_RuntimeCodec>();
|
||||
case ERuntimeAudioFormat::Wav:
|
||||
return MakeUnique<FWAV_RuntimeCodec>();
|
||||
case ERuntimeAudioFormat::Flac:
|
||||
return MakeUnique<FFLAC_RuntimeCodec>();
|
||||
case ERuntimeAudioFormat::OggVorbis:
|
||||
return MakeUnique<FVORBIS_RuntimeCodec>();
|
||||
case ERuntimeAudioFormat::Bink:
|
||||
return MakeUnique<FBINK_RuntimeCodec>();
|
||||
default:
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to determine the audio codec for the %s format"), *UEnum::GetValueAsString(AudioFormat));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TUniquePtr<FBaseRuntimeCodec> FRuntimeCodecFactory::GetCodec(const FRuntimeBulkDataBuffer<uint8>& AudioData)
|
||||
{
|
||||
TUniquePtr<FBaseRuntimeCodec> MP3_Codec = MakeUnique<FMP3_RuntimeCodec>();
|
||||
if (MP3_Codec->CheckAudioFormat(AudioData))
|
||||
{
|
||||
return MoveTemp(MP3_Codec);
|
||||
}
|
||||
|
||||
TUniquePtr<FBaseRuntimeCodec> FLAC_Codec = MakeUnique<FFLAC_RuntimeCodec>();
|
||||
if (FLAC_Codec->CheckAudioFormat(AudioData))
|
||||
{
|
||||
return MoveTemp(FLAC_Codec);
|
||||
}
|
||||
|
||||
TUniquePtr<FBaseRuntimeCodec> VORBIS_Codec = MakeUnique<FVORBIS_RuntimeCodec>();
|
||||
if (VORBIS_Codec->CheckAudioFormat(AudioData))
|
||||
{
|
||||
return MoveTemp(VORBIS_Codec);
|
||||
}
|
||||
|
||||
TUniquePtr<FBaseRuntimeCodec> BINK_Codec = MakeUnique<FBINK_RuntimeCodec>();
|
||||
if (BINK_Codec->CheckAudioFormat(AudioData))
|
||||
{
|
||||
return MoveTemp(BINK_Codec);
|
||||
}
|
||||
|
||||
TUniquePtr<FBaseRuntimeCodec> WAV_Codec = MakeUnique<FWAV_RuntimeCodec>();
|
||||
if (WAV_Codec->CheckAudioFormat(AudioData))
|
||||
{
|
||||
return MoveTemp(WAV_Codec);
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to determine the audio codec based on the audio data of size %lld bytes"), static_cast<int64>(AudioData.GetView().Num()));
|
||||
return nullptr;
|
||||
}
|
@ -1,289 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Codecs/VORBIS_RuntimeCodec.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "Codecs/RAW_RuntimeCodec.h"
|
||||
#include "HAL/PlatformProperties.h"
|
||||
#include "HAL/UnrealMemory.h"
|
||||
|
||||
#include "VorbisAudioInfo.h"
|
||||
#include "Interfaces/IAudioFormat.h"
|
||||
#ifndef WITH_OGGVORBIS
|
||||
#define WITH_OGGVORBIS 0
|
||||
#endif
|
||||
|
||||
#define INCLUDE_VORBIS
|
||||
#include "CodecIncludes.h"
|
||||
#undef INCLUDE_VORBIS
|
||||
|
||||
bool FVORBIS_RuntimeCodec::CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData)
|
||||
{
|
||||
#if WITH_OGGVORBIS
|
||||
FVorbisAudioInfo AudioInfo;
|
||||
FSoundQualityInfo SoundQualityInfo;
|
||||
|
||||
if (!AudioInfo.ReadCompressedInfo(AudioData.GetView().GetData(), AudioData.GetView().Num(), &SoundQualityInfo) || SoundQualityInfo.SampleDataSize == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support VORBIS decoding"), FPlatformProperties::IniPlatformName());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FVORBIS_RuntimeCodec::GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Retrieving header information for VORBIS audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to retrieve audio header information in the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
#if WITH_OGGVORBIS
|
||||
FVorbisAudioInfo AudioInfo;
|
||||
FSoundQualityInfo SoundQualityInfo;
|
||||
|
||||
if (!AudioInfo.ReadCompressedInfo(EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), &SoundQualityInfo) || SoundQualityInfo.SampleDataSize == 0)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to read VORBIS compressed info"));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
HeaderInfo.Duration = SoundQualityInfo.Duration;
|
||||
HeaderInfo.SampleRate = SoundQualityInfo.SampleRate;
|
||||
HeaderInfo.NumOfChannels = SoundQualityInfo.NumChannels;
|
||||
HeaderInfo.PCMDataSize = SoundQualityInfo.SampleDataSize / sizeof(int16);
|
||||
HeaderInfo.AudioFormat = GetAudioFormat();
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully retrieved header information for VORBIS audio format.\nHeader info: %s"), *HeaderInfo.ToString());
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support VORBIS decoding"), FPlatformProperties::IniPlatformName());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FVORBIS_RuntimeCodec::Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Encoding uncompressed audio data to VORBIS audio format.\nDecoded audio info: %s.\nQuality: %d"), *DecodedData.ToString(), Quality);
|
||||
|
||||
#if PLATFORM_SUPPORTS_VORBIS_CODEC
|
||||
TArray<uint8> EncodedAudioData;
|
||||
|
||||
const uint32 NumOfFrames = DecodedData.PCMInfo.PCMNumOfFrames;
|
||||
const uint32 NumOfChannels = DecodedData.SoundWaveBasicInfo.NumOfChannels;
|
||||
const uint32 SampleRate = DecodedData.SoundWaveBasicInfo.SampleRate;
|
||||
|
||||
// Encoding Vorbis data
|
||||
{
|
||||
vorbis_info VorbisInfo;
|
||||
vorbis_info_init(&VorbisInfo);
|
||||
|
||||
if (vorbis_encode_init_vbr(&VorbisInfo, NumOfChannels, SampleRate, static_cast<float>(Quality) / 100) < 0)
|
||||
{
|
||||
vorbis_info_clear(&VorbisInfo);
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to initialize VORBIS encoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the comment
|
||||
vorbis_comment VorbisComment;
|
||||
{
|
||||
vorbis_comment_init(&VorbisComment);
|
||||
vorbis_comment_add_tag(&VorbisComment, "ENCODER", "RuntimeAudioImporter");
|
||||
}
|
||||
|
||||
// Start making a vorbis block
|
||||
vorbis_dsp_state VorbisDspState;
|
||||
vorbis_block VorbisBlock;
|
||||
{
|
||||
vorbis_analysis_init(&VorbisDspState, &VorbisInfo);
|
||||
vorbis_block_init(&VorbisDspState, &VorbisBlock);
|
||||
}
|
||||
|
||||
// Ogg packet stuff
|
||||
ogg_packet OggPacket, OggComment, OggCode;
|
||||
ogg_page OggPage;
|
||||
ogg_stream_state OggStreamState;
|
||||
|
||||
{
|
||||
ogg_stream_init(&OggStreamState, 0);
|
||||
vorbis_analysis_headerout(&VorbisDspState, &VorbisComment, &OggPacket, &OggComment, &OggCode);
|
||||
ogg_stream_packetin(&OggStreamState, &OggPacket);
|
||||
ogg_stream_packetin(&OggStreamState, &OggComment);
|
||||
ogg_stream_packetin(&OggStreamState, &OggCode);
|
||||
}
|
||||
|
||||
auto CleanUpVORBIS = [&]()
|
||||
{
|
||||
ogg_stream_clear(&OggStreamState);
|
||||
vorbis_block_clear(&VorbisBlock);
|
||||
vorbis_dsp_clear(&VorbisDspState);
|
||||
vorbis_comment_clear(&VorbisComment);
|
||||
vorbis_info_clear(&VorbisInfo);
|
||||
};
|
||||
|
||||
// Do stuff until we don't do stuff anymore since we need the data on a separate page
|
||||
while (ogg_stream_flush(&OggStreamState, &OggPage))
|
||||
{
|
||||
EncodedAudioData.Append(static_cast<uint8*>(OggPage.header), OggPage.header_len);
|
||||
EncodedAudioData.Append(static_cast<uint8*>(OggPage.body), OggPage.body_len);
|
||||
}
|
||||
|
||||
uint32 FramesEncoded{0}, FramesRead{0};
|
||||
|
||||
bool bEndOfBitstream{false};
|
||||
|
||||
while (!bEndOfBitstream)
|
||||
{
|
||||
constexpr uint32 FramesSplitCount = 1024;
|
||||
|
||||
// Getting frames for encoding
|
||||
uint32 FramesToEncode{NumOfFrames - FramesRead};
|
||||
|
||||
// Analyze buffers
|
||||
float** AnalysisBuffer = vorbis_analysis_buffer(&VorbisDspState, FramesToEncode);
|
||||
|
||||
// Make sure we don't read more than FramesSplitCount, since libvorbis can segfault if we read too much at once
|
||||
if (FramesToEncode > FramesSplitCount)
|
||||
{
|
||||
FramesToEncode = FramesSplitCount;
|
||||
}
|
||||
|
||||
if (!DecodedData.PCMInfo.PCMData.GetView().GetData() || !AnalysisBuffer)
|
||||
{
|
||||
CleanUpVORBIS();
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to create VORBIS analysis buffers"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deinterleave for the encoder
|
||||
for (uint32 FrameIndex = 0; FrameIndex < FramesToEncode; ++FrameIndex)
|
||||
{
|
||||
const float* Frame = DecodedData.PCMInfo.PCMData.GetView().GetData() + (FrameIndex + FramesEncoded) * NumOfChannels;
|
||||
|
||||
for (uint32 ChannelIndex = 0; ChannelIndex < NumOfChannels; ++ChannelIndex)
|
||||
{
|
||||
AnalysisBuffer[ChannelIndex][FrameIndex] = Frame[ChannelIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Set how many frames we wrote
|
||||
if (vorbis_analysis_wrote(&VorbisDspState, FramesToEncode) < 0)
|
||||
{
|
||||
CleanUpVORBIS();
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to read VORBIS frames"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Separate AnalysisBuffer into separate blocks, then chunk those blocks into pages
|
||||
while (vorbis_analysis_blockout(&VorbisDspState, &VorbisBlock) == 1)
|
||||
{
|
||||
// Perform actual analysis
|
||||
vorbis_analysis(&VorbisBlock, nullptr);
|
||||
|
||||
// Determine the bitrate on this block
|
||||
vorbis_bitrate_addblock(&VorbisBlock);
|
||||
|
||||
// Flush all available vorbis blocks into packets, then append the resulting pages to the output buffer
|
||||
while (vorbis_bitrate_flushpacket(&VorbisDspState, &OggPacket))
|
||||
{
|
||||
ogg_stream_packetin(&OggStreamState, &OggPacket);
|
||||
|
||||
while (!bEndOfBitstream)
|
||||
{
|
||||
// Write data if we have a page
|
||||
if (!ogg_stream_pageout(&OggStreamState, &OggPage))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
EncodedAudioData.Append(static_cast<uint8*>(OggPage.header), OggPage.header_len);
|
||||
EncodedAudioData.Append(static_cast<uint8*>(OggPage.body), OggPage.body_len);
|
||||
|
||||
// End if we need to
|
||||
if (ogg_page_eos(&OggPage))
|
||||
{
|
||||
bEndOfBitstream = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Increment
|
||||
FramesEncoded += FramesToEncode;
|
||||
FramesRead += FramesToEncode;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
CleanUpVORBIS();
|
||||
}
|
||||
|
||||
// Populating the encoded audio data
|
||||
{
|
||||
EncodedData.AudioData = FRuntimeBulkDataBuffer<uint8>(EncodedAudioData);
|
||||
EncodedData.AudioFormat = ERuntimeAudioFormat::OggVorbis;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully encoded uncompressed audio data to VORBIS audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support VORBIS encoding"), FPlatformProperties::IniPlatformName());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FVORBIS_RuntimeCodec::Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Decoding VORBIS audio data to uncompressed audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to decode audio data using the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
#if WITH_OGGVORBIS
|
||||
FVorbisAudioInfo AudioInfo;
|
||||
FSoundQualityInfo SoundQualityInfo;
|
||||
|
||||
// Parse the audio header for the relevant information
|
||||
if (!AudioInfo.ReadCompressedInfo(EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), &SoundQualityInfo))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to read VORBIS compressed info"));
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray64<uint8> PCMData;
|
||||
|
||||
// Decompress all the sample data
|
||||
PCMData.Empty(SoundQualityInfo.SampleDataSize);
|
||||
PCMData.AddZeroed(SoundQualityInfo.SampleDataSize);
|
||||
AudioInfo.ExpandFile(PCMData.GetData(), &SoundQualityInfo);
|
||||
|
||||
// Getting the number of frames
|
||||
DecodedData.PCMInfo.PCMNumOfFrames = PCMData.Num() / SoundQualityInfo.NumChannels / sizeof(int16);
|
||||
|
||||
const int64 NumOfSamples = PCMData.Num() / sizeof(int16);
|
||||
|
||||
// Transcoding int16 to float format
|
||||
{
|
||||
float* TempFloatBuffer;
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<int16, float>(reinterpret_cast<int16*>(PCMData.GetData()), NumOfSamples, TempFloatBuffer);
|
||||
DecodedData.PCMInfo.PCMData = FRuntimeBulkDataBuffer<float>(TempFloatBuffer, NumOfSamples);
|
||||
}
|
||||
|
||||
// Getting basic audio information
|
||||
{
|
||||
DecodedData.SoundWaveBasicInfo.Duration = SoundQualityInfo.Duration;
|
||||
DecodedData.SoundWaveBasicInfo.NumOfChannels = SoundQualityInfo.NumChannels;
|
||||
DecodedData.SoundWaveBasicInfo.SampleRate = SoundQualityInfo.SampleRate;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully decoded VORBIS audio data to uncompressed audio format.\nDecoded audio info: %s"), *DecodedData.ToString());
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Your platform (%hs) does not support VORBIS decoding"), FPlatformProperties::IniPlatformName());
|
||||
#endif
|
||||
}
|
@ -1,211 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Codecs/WAV_RuntimeCodec.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "HAL/UnrealMemory.h"
|
||||
|
||||
#define INCLUDE_WAV
|
||||
#include "CodecIncludes.h"
|
||||
#include "Codecs/RAW_RuntimeCodec.h"
|
||||
#undef INCLUDE_WAV
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Check and fix the WAV audio data with the correct byte size in the RIFF container
|
||||
* Made by https://github.com/kass-kass
|
||||
*/
|
||||
bool CheckAndFixWavDurationErrors(const FRuntimeBulkDataBuffer<uint8>& WavData)
|
||||
{
|
||||
drwav WAV;
|
||||
|
||||
// Initializing WAV codec
|
||||
if (!drwav_init_memory(&WAV, WavData.GetView().GetData(), WavData.GetView().Num(), nullptr))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to initialize WAV Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the container is RIFF (not Wave64 or any other containers)
|
||||
if (WAV.container != drwav_container_riff)
|
||||
{
|
||||
drwav_uninit(&WAV);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get 4-byte field at byte 4, which is the overall file size as uint32, according to RIFF specification.
|
||||
// If the field is set to nothing (hex FFFFFFFF), replace the incorrectly set field with the actual size.
|
||||
// The field should be (size of file - 8 bytes), as the chunk identifier for the whole file (4 bytes spelling out RIFF at the start of the file), and the chunk length (4 bytes that we're replacing) are excluded.
|
||||
if (BytesToHex(WavData.GetView().GetData() + 4, 4) == "FFFFFFFF")
|
||||
{
|
||||
const int32 ActualFileSize = WavData.GetView().Num() - 8;
|
||||
FMemory::Memcpy(WavData.GetView().GetData() + 4, &ActualFileSize, 4);
|
||||
}
|
||||
|
||||
// Search for the place in the file after the chunk id "data", which is where the data length is stored.
|
||||
// First 36 bytes are skipped, as they're always "RIFF", 4 bytes filesize, "WAVE", "fmt ", and 20 bytes of format data.
|
||||
uint32 DataSizeLocation = INDEX_NONE;
|
||||
for (uint32 Index = 36; Index < static_cast<uint32>(WavData.GetView().Num()) - 4; ++Index)
|
||||
{
|
||||
// "64617461" - hex for string "data"
|
||||
if (BytesToHex(WavData.GetView().GetData() + Index, 4) == "64617461")
|
||||
{
|
||||
DataSizeLocation = Index + 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Should never happen, but just in case
|
||||
if (DataSizeLocation == INDEX_NONE)
|
||||
{
|
||||
drwav_uninit(&WAV);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Same process as replacing full file size, except DataSize counts bytes from end of DataSize int to end of file.
|
||||
if (BytesToHex(WavData.GetView().GetData() + DataSizeLocation, 4) == "FFFFFFFF")
|
||||
{
|
||||
// -4 to not include the DataSize int itself
|
||||
const uint32 ActualDataSize = WavData.GetView().Num() - DataSizeLocation - 4;
|
||||
|
||||
FMemory::Memcpy(WavData.GetView().GetData() + DataSizeLocation, &ActualDataSize, 4);
|
||||
}
|
||||
|
||||
drwav_uninit(&WAV);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FWAV_RuntimeCodec::CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData)
|
||||
{
|
||||
drwav WAV;
|
||||
|
||||
CheckAndFixWavDurationErrors(AudioData);
|
||||
|
||||
if (!drwav_init_memory(&WAV, AudioData.GetView().GetData(), AudioData.GetView().Num(), nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
drwav_uninit(&WAV);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWAV_RuntimeCodec::GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Retrieving header information for WAV audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to retrieve audio header information in the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
drwav WAV;
|
||||
if (!drwav_init_memory(&WAV, EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), nullptr))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to initialize WAV Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
HeaderInfo.Duration = static_cast<float>(WAV.totalPCMFrameCount) / WAV.sampleRate;
|
||||
HeaderInfo.NumOfChannels = WAV.channels;
|
||||
HeaderInfo.SampleRate = WAV.sampleRate;
|
||||
HeaderInfo.PCMDataSize = WAV.totalPCMFrameCount * WAV.channels;
|
||||
HeaderInfo.AudioFormat = GetAudioFormat();
|
||||
}
|
||||
|
||||
drwav_uninit(&WAV);
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully retrieved header information for WAV audio format.\nHeader info: %s"), *HeaderInfo.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWAV_RuntimeCodec::Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Encoding uncompressed audio data to WAV audio format.\nDecoded audio info: %s."), *DecodedData.ToString());
|
||||
|
||||
drwav WAV_Encoder;
|
||||
|
||||
drwav_data_format WAV_Format;
|
||||
{
|
||||
WAV_Format.container = drwav_container_riff;
|
||||
WAV_Format.format = DR_WAVE_FORMAT_PCM;
|
||||
WAV_Format.channels = DecodedData.SoundWaveBasicInfo.NumOfChannels;
|
||||
WAV_Format.sampleRate = DecodedData.SoundWaveBasicInfo.SampleRate;
|
||||
WAV_Format.bitsPerSample = 16;
|
||||
}
|
||||
|
||||
void* CompressedData = nullptr;
|
||||
size_t CompressedDataLen;
|
||||
|
||||
if (!drwav_init_memory_write(&WAV_Encoder, &CompressedData, &CompressedDataLen, &WAV_Format, nullptr))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to initialize WAV Encoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
int16* TempInt16BBuffer;
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<float, int16>(DecodedData.PCMInfo.PCMData.GetView().GetData(), DecodedData.PCMInfo.PCMData.GetView().Num(), TempInt16BBuffer);
|
||||
|
||||
drwav_write_pcm_frames(&WAV_Encoder, DecodedData.PCMInfo.PCMNumOfFrames, TempInt16BBuffer);
|
||||
drwav_uninit(&WAV_Encoder);
|
||||
FMemory::Free(TempInt16BBuffer);
|
||||
|
||||
// Populating the encoded audio data
|
||||
{
|
||||
EncodedData.AudioData = FRuntimeBulkDataBuffer<uint8>(static_cast<uint8*>(CompressedData), static_cast<int64>(CompressedDataLen));
|
||||
EncodedData.AudioFormat = ERuntimeAudioFormat::Wav;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully encoded uncompressed audio data to WAV audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWAV_RuntimeCodec::Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Decoding WAV audio data to uncompressed audio format.\nEncoded audio info: %s"), *EncodedData.ToString());
|
||||
|
||||
ensureAlwaysMsgf(EncodedData.AudioFormat == GetAudioFormat(), TEXT("Attempting to decode audio data using the '%s' codec, but the data format is encoded in '%s'"),
|
||||
*UEnum::GetValueAsString(GetAudioFormat()), *UEnum::GetValueAsString(EncodedData.AudioFormat));
|
||||
|
||||
if (!CheckAndFixWavDurationErrors(EncodedData.AudioData))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Something went wrong while fixing WAV audio data duration error"));
|
||||
return false;
|
||||
}
|
||||
|
||||
drwav WAV_Decoder;
|
||||
|
||||
// Initializing WAV codec
|
||||
if (!drwav_init_memory(&WAV_Decoder, EncodedData.AudioData.GetView().GetData(), EncodedData.AudioData.GetView().Num(), nullptr))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to initialize WAV Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocating memory for PCM data
|
||||
float* TempPCMData = static_cast<float*>(FMemory::Malloc(WAV_Decoder.totalPCMFrameCount * WAV_Decoder.channels * sizeof(float)));
|
||||
if (!TempPCMData)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to allocate memory for WAV Decoder"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filling PCM data and getting the number of frames
|
||||
DecodedData.PCMInfo.PCMNumOfFrames = drwav_read_pcm_frames_f32(&WAV_Decoder, WAV_Decoder.totalPCMFrameCount, TempPCMData);
|
||||
|
||||
// Getting PCM data size
|
||||
const int64 TempPCMDataSize = static_cast<int64>(DecodedData.PCMInfo.PCMNumOfFrames * WAV_Decoder.channels);
|
||||
|
||||
DecodedData.PCMInfo.PCMData = FRuntimeBulkDataBuffer<float>(TempPCMData, TempPCMDataSize);
|
||||
|
||||
// Getting basic audio information
|
||||
{
|
||||
DecodedData.SoundWaveBasicInfo.Duration = static_cast<float>(WAV_Decoder.totalPCMFrameCount) / WAV_Decoder.sampleRate;
|
||||
DecodedData.SoundWaveBasicInfo.NumOfChannels = WAV_Decoder.channels;
|
||||
DecodedData.SoundWaveBasicInfo.SampleRate = WAV_Decoder.sampleRate;
|
||||
}
|
||||
|
||||
drwav_uninit(&WAV_Decoder);
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully decoded WAV audio data to uncompressed audio format.\nDecoded audio info: %s"), *DecodedData.ToString());
|
||||
return true;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
#include "MetaSound/MetasoundImportedWave.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
|
||||
namespace RuntimeAudioImporter
|
||||
{
|
||||
const FString PluginAuthor = TEXT("Georgy Treshchev");
|
||||
const FText PluginNodeMissingPrompt = NSLOCTEXT("RuntimeAudioImporter", "DefaultMissingNodePrompt", "The node was likely removed, renamed, or the RuntimeAudioImporter plugin is not loaded.");
|
||||
|
||||
FImportedWave::FImportedWave(const TUniquePtr<Audio::IProxyData>& InInitData)
|
||||
{
|
||||
if (InInitData.IsValid())
|
||||
{
|
||||
if (InInitData->CheckTypeCast<FSoundWaveProxy>())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully retrieved proxy data from Imported Sound Wave"));
|
||||
SoundWaveProxy = MakeShared<FSoundWaveProxy, ESPMode::ThreadSafe>(InInitData->GetAs<FSoundWaveProxy>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,148 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
#include "CoreMinimal.h"
|
||||
#include "Internationalization/Text.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
|
||||
#include "MetasoundWave.h"
|
||||
#include "MetasoundFacade.h"
|
||||
#include "MetasoundParamHelper.h"
|
||||
#include "MetasoundExecutableOperator.h"
|
||||
#include "MetasoundNodeRegistrationMacro.h"
|
||||
#include "MetasoundStandardNodesCategories.h"
|
||||
#include "MetasoundDataTypeRegistrationMacro.h"
|
||||
#include "MetasoundVertex.h"
|
||||
#include "MetaSound/MetasoundImportedWave.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "MetasoundImportedWaveToWaveAsset"
|
||||
|
||||
namespace RuntimeAudioImporter
|
||||
{
|
||||
namespace ImportedWaveToWaveAssetNodeParameterNames
|
||||
{
|
||||
METASOUND_PARAM(ParamImportedWave, "Imported Wave", "Input Imported Wave");
|
||||
METASOUND_PARAM(ParamWaveAsset, "Wave Asset", "Output Wave Asset");
|
||||
}
|
||||
|
||||
class FImportedWaveToWaveAssetNodeOperator : public Metasound::TExecutableOperator<FImportedWaveToWaveAssetNodeOperator>
|
||||
{
|
||||
public:
|
||||
FImportedWaveToWaveAssetNodeOperator(const FImportedWaveReadRef& InImportedWave)
|
||||
: ImportedWave(InImportedWave)
|
||||
, WaveAsset(Metasound::FWaveAssetWriteRef::CreateNew(nullptr))
|
||||
{
|
||||
Execute();
|
||||
}
|
||||
|
||||
static const Metasound::FNodeClassMetadata& GetNodeInfo()
|
||||
{
|
||||
auto InitNodeInfo = []() -> Metasound::FNodeClassMetadata
|
||||
{
|
||||
Metasound::FNodeClassMetadata Metadata
|
||||
{
|
||||
Metasound::FNodeClassName{"RuntimeAudioImporter", "ImportedWaveToWaveAsset", ""},
|
||||
1, // Major Version
|
||||
0, // Minor Version
|
||||
LOCTEXT("ImportedWaveToWaveAssetNode_Name", "Imported Wave To Wave Asset"),
|
||||
LOCTEXT("ImportedWaveToWaveAssetNode_Description", "Converts Imported Wave to Wave Asset parameter."),
|
||||
RuntimeAudioImporter::PluginAuthor,
|
||||
RuntimeAudioImporter::PluginNodeMissingPrompt,
|
||||
GetDefaultInterface(),
|
||||
{METASOUND_LOCTEXT("RuntimeAudioImporter_Metasound_Category", "RuntimeAudioImporter")},
|
||||
{
|
||||
METASOUND_LOCTEXT("RuntimeAudioImporter_Metasound_Keyword", "RuntimeAudioImported"),
|
||||
METASOUND_LOCTEXT("ImportedSoundWave_Metasound_Keyword", "ImportedSoundWave")
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
return Metadata;
|
||||
};
|
||||
|
||||
static const Metasound::FNodeClassMetadata Info = InitNodeInfo();
|
||||
|
||||
return Info;
|
||||
}
|
||||
|
||||
static const Metasound::FVertexInterface& GetDefaultInterface()
|
||||
{
|
||||
using namespace Metasound;
|
||||
using namespace ImportedWaveToWaveAssetNodeParameterNames;
|
||||
|
||||
static const FVertexInterface DefaultInterface(
|
||||
FInputVertexInterface(TInputDataVertex<FImportedWave>(METASOUND_GET_PARAM_NAME_AND_METADATA(ParamImportedWave))
|
||||
),
|
||||
FOutputVertexInterface(TOutputDataVertex<FWaveAsset>(METASOUND_GET_PARAM_NAME_AND_METADATA(ParamWaveAsset))
|
||||
)
|
||||
);
|
||||
|
||||
return DefaultInterface;
|
||||
}
|
||||
|
||||
static TUniquePtr<IOperator> CreateOperator(const Metasound::FCreateOperatorParams& InParams, Metasound::FBuildErrorArray& OutErrors)
|
||||
{
|
||||
using namespace Metasound;
|
||||
using namespace ImportedWaveToWaveAssetNodeParameterNames;
|
||||
|
||||
const FDataReferenceCollection& InputDataRefs = InParams.InputDataReferences;
|
||||
|
||||
FImportedWaveReadRef ImportedWaveIn = InputDataRefs.GetDataReadReferenceOrConstruct<FImportedWave>(METASOUND_GET_PARAM_NAME(ParamImportedWave));
|
||||
|
||||
return MakeUnique<FImportedWaveToWaveAssetNodeOperator>(ImportedWaveIn);
|
||||
}
|
||||
|
||||
virtual Metasound::FDataReferenceCollection GetInputs() const override
|
||||
{
|
||||
using namespace Metasound;
|
||||
using namespace ImportedWaveToWaveAssetNodeParameterNames;
|
||||
|
||||
FDataReferenceCollection InputDataReferences;
|
||||
InputDataReferences.AddDataReadReference(METASOUND_GET_PARAM_NAME(ParamImportedWave), FImportedWaveReadRef(ImportedWave));
|
||||
|
||||
return InputDataReferences;
|
||||
}
|
||||
|
||||
virtual Metasound::FDataReferenceCollection GetOutputs() const override
|
||||
{
|
||||
using namespace Metasound;
|
||||
using namespace ImportedWaveToWaveAssetNodeParameterNames;
|
||||
|
||||
FDataReferenceCollection OutputDataReferences;
|
||||
OutputDataReferences.AddDataReadReference(METASOUND_GET_PARAM_NAME(ParamWaveAsset), FWaveAssetWriteRef(WaveAsset));
|
||||
|
||||
return OutputDataReferences;
|
||||
}
|
||||
|
||||
void Execute()
|
||||
{
|
||||
using namespace Metasound;
|
||||
if (ImportedWave->IsSoundWaveValid())
|
||||
{
|
||||
if (!WaveAsset->GetSoundWaveProxy().IsValid())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully transmitted proxy data from Imported Wave to Wave Asset"));
|
||||
*WaveAsset = FWaveAsset(MakeShared<FSoundWaveProxy>(*ImportedWave->GetSoundWaveProxy().Get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FImportedWaveReadRef ImportedWave;
|
||||
Metasound::FWaveAssetWriteRef WaveAsset;
|
||||
};
|
||||
|
||||
class FImportedWaveToWaveAssetNode : public Metasound::FNodeFacade
|
||||
{
|
||||
public:
|
||||
FImportedWaveToWaveAssetNode(const Metasound::FNodeInitData& InInitData)
|
||||
: FNodeFacade(InInitData.InstanceName, InInitData.InstanceID, Metasound::TFacadeOperatorClass<FImportedWaveToWaveAssetNodeOperator>())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
METASOUND_REGISTER_NODE(FImportedWaveToWaveAssetNode);
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
#endif
|
@ -1,9 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "PreImportedSoundAsset.h"
|
||||
|
||||
|
||||
UPreImportedSoundAsset::UPreImportedSoundAsset()
|
||||
: AudioFormat(ERuntimeAudioFormat::Mp3)
|
||||
{
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "RuntimeAudioImporter.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FRuntimeAudioImporterModule"
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
#include "MetasoundDataTypeRegistrationMacro.h"
|
||||
#include "MetasoundFrontendRegistries.h"
|
||||
#include "MetasoundWave.h"
|
||||
#include "MetaSound/MetasoundImportedWave.h"
|
||||
#include "Sound/ImportedSoundWave.h"
|
||||
|
||||
REGISTER_METASOUND_DATATYPE(RuntimeAudioImporter::FImportedWave, "ImportedWave", Metasound::ELiteralType::UObjectProxy, UImportedSoundWave);
|
||||
#endif
|
||||
|
||||
void FRuntimeAudioImporterModule::StartupModule()
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
FModuleManager::Get().LoadModuleChecked("MetasoundEngine");
|
||||
FMetasoundFrontendRegistryContainer::Get()->RegisterPendingNodes();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FRuntimeAudioImporterModule::ShutdownModule()
|
||||
{
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FRuntimeAudioImporterModule, RuntimeAudioImporter)
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogRuntimeAudioImporter);
|
File diff suppressed because it is too large
Load Diff
@ -1,205 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Sound/CapturableSoundWave.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
#include "AudioThread.h"
|
||||
#include "Async/Async.h"
|
||||
|
||||
UCapturableSoundWave::UCapturableSoundWave(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
void UCapturableSoundWave::BeginDestroy()
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
AudioCapture.AbortStream();
|
||||
AudioCapture.CloseStream();
|
||||
#endif
|
||||
|
||||
Super::BeginDestroy();
|
||||
}
|
||||
|
||||
UCapturableSoundWave* UCapturableSoundWave::CreateCapturableSoundWave()
|
||||
{
|
||||
if (!IsInGameThread())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to create a sound wave outside of the game thread"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NewObject<UCapturableSoundWave>();
|
||||
}
|
||||
|
||||
void UCapturableSoundWave::GetAvailableAudioInputDevices(const FOnGetAvailableAudioInputDevicesResult& Result)
|
||||
{
|
||||
GetAvailableAudioInputDevices(FOnGetAvailableAudioInputDevicesResultNative::CreateLambda([Result](const TArray<FRuntimeAudioInputDeviceInfo>& AvailableDevices)
|
||||
{
|
||||
Result.ExecuteIfBound(AvailableDevices);
|
||||
}));
|
||||
}
|
||||
|
||||
void UCapturableSoundWave::GetAvailableAudioInputDevices(const FOnGetAvailableAudioInputDevicesResultNative& Result)
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
if (!IsInAudioThread())
|
||||
{
|
||||
FAudioThread::RunCommandOnAudioThread([Result]()
|
||||
{
|
||||
GetAvailableAudioInputDevices(Result);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto ExecuteResult = [Result](const TArray<FRuntimeAudioInputDeviceInfo>& AvailableDevices)
|
||||
{
|
||||
AsyncTask(ENamedThreads::GameThread, [Result, AvailableDevices]()
|
||||
{
|
||||
Result.ExecuteIfBound(AvailableDevices);
|
||||
});
|
||||
};
|
||||
|
||||
TArray<FRuntimeAudioInputDeviceInfo> AvailableDevices;
|
||||
|
||||
Audio::FAudioCapture AudioCapture;
|
||||
TArray<Audio::FCaptureDeviceInfo> InputDevices;
|
||||
|
||||
AudioCapture.GetCaptureDevicesAvailable(InputDevices);
|
||||
|
||||
for (const Audio::FCaptureDeviceInfo& CaptureDeviceInfo : InputDevices)
|
||||
{
|
||||
AvailableDevices.Add(FRuntimeAudioInputDeviceInfo(CaptureDeviceInfo));
|
||||
}
|
||||
|
||||
ExecuteResult(AvailableDevices);
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to get available audio input devices as its support is disabled (please enable in RuntimeAudioImporter.Build.cs)"));
|
||||
Result.ExecuteIfBound(TArray<FRuntimeAudioInputDeviceInfo>());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UCapturableSoundWave::StartCapture(int32 DeviceId)
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
if (AudioCapture.IsStreamOpen())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to start capture as the stream is already open"));
|
||||
return false;
|
||||
}
|
||||
|
||||
Audio::FOnCaptureFunction OnCapture = [this](const float* PCMData, int32 NumFrames, int32 NumOfChannels,
|
||||
#if UE_VERSION_NEWER_THAN(4, 25, 0)
|
||||
int32 InSampleRate,
|
||||
#endif
|
||||
double StreamTime, bool bOverFlow)
|
||||
{
|
||||
if (AudioCapture.IsCapturing())
|
||||
{
|
||||
const int64 PCMDataSize = NumOfChannels * NumFrames;
|
||||
const int64 PCMDataSizeInBytes = PCMDataSize * sizeof(float);
|
||||
|
||||
if (PCMDataSizeInBytes > TNumericLimits<int32>::Max())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to append audio data as the size of the data exceeds the maximum size of int32 (PCMDataSizeInBytes: %lld, Max: %d)"), PCMDataSizeInBytes, TNumericLimits<int32>::Max());
|
||||
return;
|
||||
}
|
||||
|
||||
AppendAudioDataFromRAW(TArray<uint8>(reinterpret_cast<const uint8*>(PCMData), static_cast<int32>(PCMDataSizeInBytes)), ERuntimeRAWAudioFormat::Float32,
|
||||
#if UE_VERSION_NEWER_THAN(4, 25, 0)
|
||||
InSampleRate
|
||||
#else
|
||||
AudioCapture.GetSampleRate()
|
||||
#endif
|
||||
, NumOfChannels);
|
||||
}
|
||||
};
|
||||
|
||||
Audio::FAudioCaptureDeviceParams Params = Audio::FAudioCaptureDeviceParams();
|
||||
Params.DeviceIndex = DeviceId;
|
||||
|
||||
if (!AudioCapture.OpenCaptureStream(Params, MoveTemp(OnCapture), 1024))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to open capturing stream for sound wave %s"), *GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AudioCapture.StartStream())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to start capturing for sound wave %s"), *GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully started capturing for sound wave %s"), *GetName());
|
||||
return true;
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to start capturing as its support is disabled (please enable in RuntimeAudioImporter.Build.cs)"));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UCapturableSoundWave::StopCapture()
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
if (AudioCapture.IsStreamOpen())
|
||||
{
|
||||
AudioCapture.CloseStream();
|
||||
}
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to stop capturing as its support is disabled (please enable in RuntimeAudioImporter.Build.cs)"));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UCapturableSoundWave::ToggleMute(bool bMute)
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
if (!AudioCapture.IsStreamOpen())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to toggle mute for %s as the stream is not open"), *GetName());
|
||||
return false;
|
||||
}
|
||||
if (bMute)
|
||||
{
|
||||
if (!AudioCapture.IsCapturing())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to mute as the stream for %s is already closed"), *GetName());
|
||||
return false;
|
||||
}
|
||||
if (!AudioCapture.StopStream())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to mute the stream for sound wave %s"), *GetName());
|
||||
return false;
|
||||
}
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully muted the stream for sound wave %s"), *GetName());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AudioCapture.IsCapturing())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to unmute as the stream for %s is already open"), *GetName());
|
||||
return false;
|
||||
}
|
||||
if (!AudioCapture.StartStream())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to unmute the stream for sound wave %s"), *GetName());
|
||||
return false;
|
||||
}
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully unmuted the stream for sound wave %s"), *GetName());
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to toggle mute as its support is disabled (please enable in RuntimeAudioImporter.Build.cs)"));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UCapturableSoundWave::IsCapturing() const
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
return AudioCapture.IsCapturing();
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to get capturing state as its support is disabled (please enable in RuntimeAudioImporter.Build.cs)"));
|
||||
return false;
|
||||
#endif
|
||||
}
|
@ -1,667 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Sound/ImportedSoundWave.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
#include "AudioDevice.h"
|
||||
#include "Async/Async.h"
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
#include "Codecs/VORBIS_RuntimeCodec.h"
|
||||
#endif
|
||||
#include "Codecs/RAW_RuntimeCodec.h"
|
||||
#include "UObject/GCObjectScopeGuard.h"
|
||||
|
||||
UImportedSoundWave::UImportedSoundWave(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
, DurationOffset(0)
|
||||
, PlaybackFinishedBroadcast(false)
|
||||
, PlayedNumOfFrames(0)
|
||||
, PCMBufferInfo(MakeUnique<FPCMStruct>())
|
||||
, bStopSoundOnPlaybackFinish(true)
|
||||
{
|
||||
ensure(PCMBufferInfo);
|
||||
|
||||
#if UE_VERSION_NEWER_THAN(5, 0, 0)
|
||||
SetImportedSampleRate(0);
|
||||
#endif
|
||||
SetSampleRate(0);
|
||||
NumChannels = 0;
|
||||
Duration = 0;
|
||||
bProcedural = true;
|
||||
DecompressionType = EDecompressionType::DTYPE_Procedural;
|
||||
SoundGroup = ESoundGroup::SOUNDGROUP_Default;
|
||||
SetPrecacheState(ESoundWavePrecacheState::Done);
|
||||
}
|
||||
|
||||
UImportedSoundWave* UImportedSoundWave::CreateImportedSoundWave()
|
||||
{
|
||||
if (!IsInGameThread())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to create a sound wave outside of the game thread"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NewObject<UImportedSoundWave>();
|
||||
}
|
||||
|
||||
Audio::EAudioMixerStreamDataFormat::Type UImportedSoundWave::GetGeneratedPCMDataFormat() const
|
||||
{
|
||||
return Audio::EAudioMixerStreamDataFormat::Type::Float;
|
||||
}
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
TSharedPtr<Audio::IProxyData> UImportedSoundWave::CreateProxyData(const Audio::FProxyDataInitParams& InitParams)
|
||||
{
|
||||
if (SoundWaveDataPtr)
|
||||
{
|
||||
SoundWaveDataPtr->OverrideRuntimeFormat(Audio::NAME_OGG);
|
||||
}
|
||||
return USoundWave::CreateProxyData(InitParams);
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::InitAudioResource(FName Format)
|
||||
{
|
||||
// Only OGG format is supported for audio resource initialization
|
||||
if (Format != Audio::NAME_OGG)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("RuntimeAudioImporter does not support audio format '%s' for initialization. Supported format: %s"), *Format.ToString(), *Audio::NAME_OGG.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SoundWaveDataPtr->GetResourceSize() > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
FDecodedAudioStruct DecodedAudioInfo;
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
{
|
||||
DecodedAudioInfo.PCMInfo = GetPCMBuffer();
|
||||
FSoundWaveBasicStruct SoundWaveBasicInfo;
|
||||
{
|
||||
SoundWaveBasicInfo.NumOfChannels = NumChannels;
|
||||
SoundWaveBasicInfo.SampleRate = GetSampleRate();
|
||||
SoundWaveBasicInfo.Duration = Duration;
|
||||
}
|
||||
DecodedAudioInfo.SoundWaveBasicInfo = SoundWaveBasicInfo;
|
||||
}
|
||||
}
|
||||
|
||||
FVORBIS_RuntimeCodec VorbisCodec;
|
||||
FEncodedAudioStruct EncodedAudioInfo;
|
||||
if (!VorbisCodec.Encode(MoveTemp(DecodedAudioInfo), EncodedAudioInfo, 100))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Something went wrong while encoding Vorbis audio data"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EncodedAudioInfo.AudioData.GetView().Num() <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FByteBulkData CompressedBulkData;
|
||||
|
||||
// Filling in the compressed data
|
||||
{
|
||||
CompressedBulkData.Lock(LOCK_READ_WRITE);
|
||||
FMemory::Memcpy(CompressedBulkData.Realloc(EncodedAudioInfo.AudioData.GetView().Num()), EncodedAudioInfo.AudioData.GetView().GetData(), EncodedAudioInfo.AudioData.GetView().Num());
|
||||
CompressedBulkData.Unlock();
|
||||
}
|
||||
|
||||
USoundWave::InitAudioResource(CompressedBulkData);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::IsSeekable() const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return PCMBufferInfo.IsValid() && PCMBufferInfo.Get()->PCMData.GetView().Num() > 0 && PCMBufferInfo.Get()->PCMNumOfFrames > 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32 UImportedSoundWave::OnGeneratePCMAudio(TArray<uint8>& OutAudio, int32 NumSamples)
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
if (!PCMBufferInfo.IsValid())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ensure there is enough number of frames. Lack of frames means audio playback has finished
|
||||
if (GetNumOfPlayedFrames_Internal() >= PCMBufferInfo->PCMNumOfFrames)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Getting the remaining number of samples if the required number of samples is greater than the total available number
|
||||
if (GetNumOfPlayedFrames_Internal() + (static_cast<uint32>(NumSamples) / static_cast<uint32>(NumChannels)) >= PCMBufferInfo->PCMNumOfFrames)
|
||||
{
|
||||
NumSamples = (PCMBufferInfo->PCMNumOfFrames - GetNumOfPlayedFrames_Internal()) * NumChannels;
|
||||
}
|
||||
|
||||
// Retrieving a part of PCM data
|
||||
float* RetrievedPCMDataPtr = PCMBufferInfo->PCMData.GetView().GetData() + (GetNumOfPlayedFrames_Internal() * NumChannels);
|
||||
const int32 RetrievedPCMDataSize = NumSamples * sizeof(float);
|
||||
|
||||
// Ensure we got a valid PCM data
|
||||
if (RetrievedPCMDataSize <= 0 || !RetrievedPCMDataPtr)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to get PCM audio from imported sound wave since the retrieved PCM data is invalid"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Filling in OutAudio array with the retrieved PCM data
|
||||
OutAudio = TArray<uint8>(reinterpret_cast<uint8*>(RetrievedPCMDataPtr), RetrievedPCMDataSize);
|
||||
|
||||
// Increasing the number of frames played
|
||||
SetNumOfPlayedFrames_Internal(GetNumOfPlayedFrames_Internal() + (NumSamples / NumChannels));
|
||||
|
||||
if (OnGeneratePCMDataNative.IsBound() || OnGeneratePCMData.IsBound())
|
||||
{
|
||||
TArray<float> PCMData(RetrievedPCMDataPtr, NumSamples);
|
||||
AsyncTask(ENamedThreads::GameThread, [this, PCMData = MoveTemp(PCMData)]() mutable
|
||||
{
|
||||
if (OnGeneratePCMDataNative.IsBound())
|
||||
{
|
||||
OnGeneratePCMDataNative.Broadcast(PCMData);
|
||||
}
|
||||
|
||||
if (OnGeneratePCMData.IsBound())
|
||||
{
|
||||
OnGeneratePCMData.Broadcast(PCMData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return NumSamples;
|
||||
}
|
||||
|
||||
void UImportedSoundWave::BeginDestroy()
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Warning, TEXT("Imported sound wave ('%s') data will be cleared because it is being unloaded"), *GetName());
|
||||
|
||||
Super::BeginDestroy();
|
||||
}
|
||||
|
||||
void UImportedSoundWave::Parse(FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances)
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
#if UE_VERSION_NEWER_THAN(5, 0, 0)
|
||||
if (ActiveSound.PlaybackTime == 0.f)
|
||||
{
|
||||
RewindPlaybackTime_Internal(ParseParams.StartTime);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stopping all other active sounds that are using the same sound wave, so that only one sound wave can be played at a time
|
||||
const TArray<FActiveSound*>& ActiveSounds = AudioDevice->GetActiveSounds();
|
||||
for (FActiveSound* ActiveSoundPtr : ActiveSounds)
|
||||
{
|
||||
if (ActiveSoundPtr->GetSound() == this && &ActiveSound != ActiveSoundPtr)
|
||||
{
|
||||
AudioDevice->StopActiveSound(ActiveSoundPtr);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveSound.PlaybackTime = GetPlaybackTime_Internal();
|
||||
|
||||
if (IsPlaybackFinished_Internal())
|
||||
{
|
||||
if (!PlaybackFinishedBroadcast)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Warning, TEXT("Playback of the sound wave '%s' has been completed"), *GetName());
|
||||
|
||||
PlaybackFinishedBroadcast = true;
|
||||
|
||||
if (OnAudioPlaybackFinishedNative.IsBound() || OnAudioPlaybackFinished.IsBound())
|
||||
{
|
||||
AsyncTask(ENamedThreads::GameThread, [this]()
|
||||
{
|
||||
if (OnAudioPlaybackFinishedNative.IsBound())
|
||||
{
|
||||
OnAudioPlaybackFinishedNative.Broadcast();
|
||||
}
|
||||
|
||||
if (OnAudioPlaybackFinished.IsBound())
|
||||
{
|
||||
OnAudioPlaybackFinished.Broadcast();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!bLooping)
|
||||
{
|
||||
if (bStopSoundOnPlaybackFinish)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Playback of the sound wave '%s' has reached the end and will be stopped"), *GetName());
|
||||
AudioDevice->StopActiveSound(&ActiveSound);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("The sound wave '%s' will be looped"), *GetName());
|
||||
ActiveSound.PlaybackTime = 0.f;
|
||||
RewindPlaybackTime_Internal(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
Super::Parse(AudioDevice, NodeWaveInstanceHash, ActiveSound, ParseParams, WaveInstances);
|
||||
}
|
||||
|
||||
void UImportedSoundWave::PopulateAudioDataFromDecodedInfo(FDecodedAudioStruct&& DecodedAudioInfo)
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
const FString DecodedAudioInfoString = DecodedAudioInfo.ToString();
|
||||
|
||||
Duration = DecodedAudioInfo.SoundWaveBasicInfo.Duration;
|
||||
#if UE_VERSION_NEWER_THAN(5, 0, 0)
|
||||
SetImportedSampleRate(0);
|
||||
#endif
|
||||
SetSampleRate(DecodedAudioInfo.SoundWaveBasicInfo.SampleRate);
|
||||
NumChannels = DecodedAudioInfo.SoundWaveBasicInfo.NumOfChannels;
|
||||
|
||||
PCMBufferInfo->PCMData = MoveTemp(DecodedAudioInfo.PCMInfo.PCMData);
|
||||
PCMBufferInfo->PCMNumOfFrames = DecodedAudioInfo.PCMInfo.PCMNumOfFrames;
|
||||
|
||||
if (OnPopulateAudioDataNative.IsBound() || OnPopulateAudioData.IsBound())
|
||||
{
|
||||
TArray<float> PCMData(PCMBufferInfo->PCMData.GetView().GetData(), PCMBufferInfo->PCMData.GetView().Num());
|
||||
AsyncTask(ENamedThreads::GameThread, [this, PCMData = MoveTemp(PCMData)]() mutable
|
||||
{
|
||||
if (OnPopulateAudioDataNative.IsBound())
|
||||
{
|
||||
OnPopulateAudioDataNative.Broadcast(PCMData);
|
||||
}
|
||||
|
||||
if (OnPopulateAudioData.IsBound())
|
||||
{
|
||||
OnPopulateAudioData.Broadcast(PCMData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("The audio data has been populated successfully. Information about audio data:\n%s"), *DecodedAudioInfoString);
|
||||
}
|
||||
|
||||
void UImportedSoundWave::PrepareSoundWaveForMetaSounds(const FOnPrepareSoundWaveForMetaSoundsResult& Result)
|
||||
{
|
||||
PrepareSoundWaveForMetaSounds(FOnPrepareSoundWaveForMetaSoundsResultNative::CreateWeakLambda(this, [Result](bool bSucceeded)
|
||||
{
|
||||
Result.ExecuteIfBound(bSucceeded);
|
||||
}));
|
||||
}
|
||||
|
||||
void UImportedSoundWave::PrepareSoundWaveForMetaSounds(const FOnPrepareSoundWaveForMetaSoundsResultNative& Result)
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [this, Result]()
|
||||
{
|
||||
FGCObjectScopeGuard Guard(this);
|
||||
|
||||
auto ExecuteResult = [Result](bool bSucceeded)
|
||||
{
|
||||
AsyncTask(ENamedThreads::GameThread, [Result, bSucceeded]()
|
||||
{
|
||||
Result.ExecuteIfBound(bSucceeded);
|
||||
});
|
||||
};
|
||||
|
||||
const bool bSucceeded = InitAudioResource(Audio::NAME_OGG);
|
||||
if (bSucceeded)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully prepared the sound wave '%s' for MetaSounds"), *GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to initialize audio resource to prepare the sound wave '%s' for MetaSounds"), *GetName());
|
||||
}
|
||||
|
||||
ExecuteResult(bSucceeded);
|
||||
});
|
||||
#else
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("PrepareSoundWaveForMetaSounds works only for Unreal Engine version >= 5.2 and if explicitly enabled in RuntimeAudioImporter.Build.cs"));
|
||||
Result.ExecuteIfBound(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UImportedSoundWave::ReleaseMemory()
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
UE_LOG(LogRuntimeAudioImporter, Warning, TEXT("Releasing memory for the sound wave '%s'"), *GetName());
|
||||
PCMBufferInfo->PCMData.Empty();
|
||||
PCMBufferInfo->PCMNumOfFrames = 0;
|
||||
}
|
||||
|
||||
void UImportedSoundWave::ReleasePlayedAudioData(const FOnPlayedAudioDataReleaseResult& Result)
|
||||
{
|
||||
ReleasePlayedAudioData(FOnPlayedAudioDataReleaseResultNative::CreateWeakLambda(this, [Result](bool bSucceeded)
|
||||
{
|
||||
Result.ExecuteIfBound(bSucceeded);
|
||||
}));
|
||||
}
|
||||
|
||||
void UImportedSoundWave::ReleasePlayedAudioData(const FOnPlayedAudioDataReleaseResultNative& Result)
|
||||
{
|
||||
AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [this, Result]() mutable
|
||||
{
|
||||
FGCObjectScopeGuard Guard(this);
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
auto ExecuteResult = [Result](bool bSucceeded)
|
||||
{
|
||||
AsyncTask(ENamedThreads::GameThread, [Result, bSucceeded]()
|
||||
{
|
||||
Result.ExecuteIfBound(bSucceeded);
|
||||
});
|
||||
};
|
||||
|
||||
if (GetNumOfPlayedFrames_Internal() == 0)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Warning, TEXT("No audio data will be released because the current playback time is zero"));
|
||||
ExecuteResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const int64 OldNumOfPCMData = PCMBufferInfo->PCMData.GetView().Num();
|
||||
if (GetNumOfPlayedFrames_Internal() >= PCMBufferInfo->PCMNumOfFrames)
|
||||
{
|
||||
ReleaseMemory();
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully released all PCM data (%lld)"), OldNumOfPCMData);
|
||||
ExecuteResult(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const int64 NewPCMDataSize = (PCMBufferInfo->PCMNumOfFrames - GetNumOfPlayedFrames_Internal()) * NumChannels;
|
||||
float* NewPCMDataPtr = static_cast<float*>(FMemory::Malloc(NewPCMDataSize * sizeof(float)));
|
||||
if (!NewPCMDataPtr)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to allocate new memory to free already played audio data"));
|
||||
ExecuteResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// PCM data offset to retrieve remaining data for playback
|
||||
const int64 PCMDataOffset = GetNumOfPlayedFrames_Internal() * NumChannels;
|
||||
|
||||
FMemory::Memcpy(NewPCMDataPtr, PCMBufferInfo->PCMData.GetView().GetData() + PCMDataOffset, NewPCMDataSize * sizeof(float));
|
||||
PCMBufferInfo->PCMData = FRuntimeBulkDataBuffer<float>(NewPCMDataPtr, NewPCMDataSize);
|
||||
|
||||
// Decreasing the amount of PCM frames
|
||||
PCMBufferInfo->PCMNumOfFrames -= GetNumOfPlayedFrames_Internal();
|
||||
|
||||
// Decreasing duration and increasing duration offset
|
||||
{
|
||||
const float DurationOffsetToReduce = GetPlaybackTime_Internal();
|
||||
Duration -= DurationOffsetToReduce;
|
||||
DurationOffset += DurationOffsetToReduce;
|
||||
}
|
||||
|
||||
PlayedNumOfFrames = 0;
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully released %lld number of PCM data"), static_cast<int64>(OldNumOfPCMData - PCMBufferInfo->PCMData.GetView().Num()));
|
||||
ExecuteResult(true);
|
||||
});
|
||||
}
|
||||
|
||||
void UImportedSoundWave::SetLooping(bool bLoop)
|
||||
{
|
||||
bLooping = bLoop;
|
||||
}
|
||||
|
||||
void UImportedSoundWave::SetSubtitles(const TArray<FEditableSubtitleCue>& InSubtitles)
|
||||
{
|
||||
Subtitles.Empty();
|
||||
|
||||
for (const FEditableSubtitleCue& Subtitle : InSubtitles)
|
||||
{
|
||||
FSubtitleCue ConvertedSubtitle;
|
||||
{
|
||||
ConvertedSubtitle.Text = Subtitle.Text;
|
||||
ConvertedSubtitle.Time = Subtitle.Time;
|
||||
}
|
||||
|
||||
Subtitles.Add(ConvertedSubtitle);
|
||||
}
|
||||
}
|
||||
|
||||
void UImportedSoundWave::SetVolume(float InVolume)
|
||||
{
|
||||
Volume = InVolume;
|
||||
}
|
||||
|
||||
void UImportedSoundWave::SetPitch(float InPitch)
|
||||
{
|
||||
Pitch = InPitch;
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::RewindPlaybackTime(float PlaybackTime)
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return RewindPlaybackTime_Internal(PlaybackTime - GetDurationOffset_Internal());
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::RewindPlaybackTime_Internal(float PlaybackTime)
|
||||
{
|
||||
if (PlaybackTime > Duration)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to rewind playback time for the imported sound wave '%s' by time '%f' because total length is '%f'"), *GetName(), PlaybackTime, Duration);
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetNumOfPlayedFrames_Internal(PlaybackTime * SampleRate);
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::ResampleSoundWave(int32 NewSampleRate)
|
||||
{
|
||||
if (NewSampleRate == GetSampleRate())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Warning, TEXT("Skipping resampling the imported sound wave '%s' because the new sample rate '%d' is the same as the current sample rate '%d'"), *GetName(), NewSampleRate, GetSampleRate());
|
||||
return true;
|
||||
}
|
||||
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
Audio::FAlignedFloatBuffer NewPCMData;
|
||||
Audio::FAlignedFloatBuffer SourcePCMData = Audio::FAlignedFloatBuffer(PCMBufferInfo->PCMData.GetView().GetData(), PCMBufferInfo->PCMData.GetView().Num());
|
||||
|
||||
if (!FRAW_RuntimeCodec::ResampleRAWData(SourcePCMData, GetNumOfChannels(), GetSampleRate(), NewSampleRate, NewPCMData))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to resample the imported sound wave '%s' from sample rate '%d' to sample rate '%d'"), *GetName(), GetSampleRate(), NewSampleRate);
|
||||
return false;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully resampled the imported sound wave '%s' from sample rate '%d' to sample rate '%d'"), *GetName(), GetSampleRate(), NewSampleRate);
|
||||
SampleRate = NewSampleRate;
|
||||
{
|
||||
PCMBufferInfo->PCMNumOfFrames = NewPCMData.Num() / GetNumOfChannels();
|
||||
PCMBufferInfo->PCMData = FRuntimeBulkDataBuffer<float>(NewPCMData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::MixSoundWaveChannels(int32 NewNumOfChannels)
|
||||
{
|
||||
if (NewNumOfChannels == GetNumOfChannels())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Warning, TEXT("Skipping mixing the imported sound wave '%s' because the new number of channels '%d' is the same as the current number of channels '%d'"), *GetName(), NewNumOfChannels, GetNumOfChannels());
|
||||
return true;
|
||||
}
|
||||
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
Audio::FAlignedFloatBuffer NewPCMData;
|
||||
Audio::FAlignedFloatBuffer SourcePCMData = Audio::FAlignedFloatBuffer(PCMBufferInfo->PCMData.GetView().GetData(), PCMBufferInfo->PCMData.GetView().Num());
|
||||
|
||||
if (!FRAW_RuntimeCodec::MixChannelsRAWData(SourcePCMData, GetSampleRate(), GetNumOfChannels(), NewNumOfChannels, NewPCMData))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to mix the imported sound wave '%s' from number of channels '%d' to number of channels '%d'"), *GetName(), GetNumOfChannels(), NewNumOfChannels);
|
||||
return false;
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully mixed the imported sound wave '%s' from number of channels '%d' to number of channels '%d'"), *GetName(), GetNumOfChannels(), NewNumOfChannels);
|
||||
NumChannels = NewNumOfChannels;
|
||||
{
|
||||
PCMBufferInfo->PCMNumOfFrames = NewPCMData.Num() / GetNumOfChannels();
|
||||
PCMBufferInfo->PCMData = FRuntimeBulkDataBuffer<float>(NewPCMData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::SetNumOfPlayedFrames(uint32 NumOfFrames)
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return SetNumOfPlayedFrames_Internal(NumOfFrames);
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::SetNumOfPlayedFrames_Internal(uint32 NumOfFrames)
|
||||
{
|
||||
if (NumOfFrames < 0 || NumOfFrames > PCMBufferInfo->PCMNumOfFrames)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Cannot change the current frame for the imported sound wave '%s' to frame '%d' because the total number of frames is '%d'"), *GetName(), NumOfFrames, PCMBufferInfo->PCMNumOfFrames);
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayedNumOfFrames = NumOfFrames;
|
||||
|
||||
ResetPlaybackFinish();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 UImportedSoundWave::GetNumOfPlayedFrames() const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return GetNumOfPlayedFrames_Internal();
|
||||
}
|
||||
|
||||
uint32 UImportedSoundWave::GetNumOfPlayedFrames_Internal() const
|
||||
{
|
||||
return PlayedNumOfFrames;
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetPlaybackTime() const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return GetPlaybackTime_Internal() + GetDurationOffset_Internal();
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetPlaybackTime_Internal() const
|
||||
{
|
||||
if (GetNumOfPlayedFrames() == 0 || SampleRate <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<float>(GetNumOfPlayedFrames()) / SampleRate;
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetDurationConst() const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return GetDurationConst_Internal() + GetDurationOffset_Internal();
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetDurationConst_Internal() const
|
||||
{
|
||||
return Duration;
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetDuration()
|
||||
#if UE_VERSION_NEWER_THAN(5, 0, 0)
|
||||
const
|
||||
#endif
|
||||
{
|
||||
return GetDurationConst();
|
||||
}
|
||||
|
||||
int32 UImportedSoundWave::GetSampleRate() const
|
||||
{
|
||||
return SampleRate;
|
||||
}
|
||||
|
||||
int32 UImportedSoundWave::GetNumOfChannels() const
|
||||
{
|
||||
return NumChannels;
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetPlaybackPercentage() const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
if (GetNumOfPlayedFrames_Internal() == 0 || PCMBufferInfo->PCMNumOfFrames == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<float>(GetNumOfPlayedFrames_Internal()) / PCMBufferInfo->PCMNumOfFrames * 100;
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::IsPlaybackFinished() const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return IsPlaybackFinished_Internal();
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetDurationOffset() const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return DurationOffset;
|
||||
}
|
||||
|
||||
float UImportedSoundWave::GetDurationOffset_Internal() const
|
||||
{
|
||||
return DurationOffset;
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::IsPlaybackFinished_Internal() const
|
||||
{
|
||||
// Are there enough frames for future playback from the current ones or not
|
||||
const bool bOutOfFrames = GetNumOfPlayedFrames_Internal() >= PCMBufferInfo->PCMNumOfFrames;
|
||||
|
||||
// Is PCM data valid
|
||||
const bool bValidPCMData = PCMBufferInfo.IsValid();
|
||||
|
||||
return bOutOfFrames && bValidPCMData;
|
||||
}
|
||||
|
||||
bool UImportedSoundWave::GetAudioHeaderInfo(FRuntimeAudioHeaderInfo& HeaderInfo) const
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
if (!PCMBufferInfo.IsValid())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to retrieve audio header information due to an invalid PCM buffer"));
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
HeaderInfo.Duration = GetDurationConst();
|
||||
HeaderInfo.AudioFormat = ERuntimeAudioFormat::Auto;
|
||||
HeaderInfo.SampleRate = GetSampleRate();
|
||||
HeaderInfo.NumOfChannels = NumChannels;
|
||||
HeaderInfo.PCMDataSize = PCMBufferInfo->PCMData.GetView().Num();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UImportedSoundWave::ResetPlaybackFinish()
|
||||
{
|
||||
PlaybackFinishedBroadcast = false;
|
||||
}
|
||||
|
||||
TArray<float> UImportedSoundWave::GetPCMBufferCopy()
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
return TArray<float>(PCMBufferInfo.Get()->PCMData.GetView().GetData(), PCMBufferInfo.Get()->PCMData.GetView().Num());
|
||||
}
|
||||
|
||||
const FPCMStruct& UImportedSoundWave::GetPCMBuffer() const
|
||||
{
|
||||
return *PCMBufferInfo.Get();
|
||||
}
|
@ -1,320 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "Sound/StreamingSoundWave.h"
|
||||
#include "RuntimeAudioImporterLibrary.h"
|
||||
#include "Codecs/RAW_RuntimeCodec.h"
|
||||
|
||||
#include "Async/Async.h"
|
||||
#include "UObject/GCObjectScopeGuard.h"
|
||||
#include "SampleBuffer.h"
|
||||
|
||||
UStreamingSoundWave::UStreamingSoundWave(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
PlaybackFinishedBroadcast = true;
|
||||
|
||||
// No need to stop the sound after the end of streaming sound wave playback, assuming the PCM data can be filled after that
|
||||
// (except if this is overridden in SetStopSoundOnPlaybackFinish)
|
||||
bStopSoundOnPlaybackFinish = false;
|
||||
|
||||
// No need to loop streaming sound wave by default
|
||||
bLooping = false;
|
||||
|
||||
// It is necessary to populate the sample rate and the number of channels to make the streaming wave playable even if there is no audio data
|
||||
// (since the audio data may be filled in after the sound wave starts playing)
|
||||
{
|
||||
SetSampleRate(44100);
|
||||
NumChannels = 2;
|
||||
}
|
||||
|
||||
bFilledInitialAudioData = false;
|
||||
NumOfPreAllocatedByteData = 0;
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::PopulateAudioDataFromDecodedInfo(FDecodedAudioStruct&& DecodedAudioInfo)
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
if (!DecodedAudioInfo.IsValid())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to continue populating the audio data because the decoded info is invalid"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the initial audio data if it hasn't already been filled in
|
||||
if (!bFilledInitialAudioData)
|
||||
{
|
||||
SetSampleRate(DecodedAudioInfo.SoundWaveBasicInfo.SampleRate);
|
||||
NumChannels = DecodedAudioInfo.SoundWaveBasicInfo.NumOfChannels;
|
||||
bFilledInitialAudioData = true;
|
||||
}
|
||||
|
||||
// Check if the number of channels and the sampling rate of the sound wave and the input audio data match
|
||||
if (SampleRate != DecodedAudioInfo.SoundWaveBasicInfo.SampleRate || NumChannels != DecodedAudioInfo.SoundWaveBasicInfo.NumOfChannels)
|
||||
{
|
||||
Audio::FAlignedFloatBuffer WaveData(DecodedAudioInfo.PCMInfo.PCMData.GetView().GetData(), DecodedAudioInfo.PCMInfo.PCMData.GetView().Num());
|
||||
|
||||
// Resampling if needed
|
||||
if (SampleRate != DecodedAudioInfo.SoundWaveBasicInfo.SampleRate)
|
||||
{
|
||||
Audio::FAlignedFloatBuffer ResamplerOutputData;
|
||||
if (!FRAW_RuntimeCodec::ResampleRAWData(WaveData, GetNumOfChannels(), GetSampleRate(), DecodedAudioInfo.SoundWaveBasicInfo.SampleRate, ResamplerOutputData))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to resample audio data to the sound wave's sample rate. Resampling failed"));
|
||||
return;
|
||||
}
|
||||
WaveData = MoveTemp(ResamplerOutputData);
|
||||
}
|
||||
|
||||
// Mixing the channels if needed
|
||||
if (NumChannels != DecodedAudioInfo.SoundWaveBasicInfo.NumOfChannels)
|
||||
{
|
||||
Audio::FAlignedFloatBuffer WaveDataTemp;
|
||||
if (!FRAW_RuntimeCodec::MixChannelsRAWData(WaveData, DecodedAudioInfo.SoundWaveBasicInfo.SampleRate, GetNumOfChannels(), DecodedAudioInfo.SoundWaveBasicInfo.NumOfChannels, WaveDataTemp))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to mix audio data to the sound wave's number of channels. Mixing failed"));
|
||||
return;
|
||||
}
|
||||
WaveData = MoveTemp(WaveDataTemp);
|
||||
}
|
||||
|
||||
DecodedAudioInfo.PCMInfo.PCMData = FRuntimeBulkDataBuffer<float>(WaveData);
|
||||
}
|
||||
|
||||
// Do not reallocate the entire PCM buffer if it has free space to fill in
|
||||
if (static_cast<uint64>(NumOfPreAllocatedByteData) >= DecodedAudioInfo.PCMInfo.PCMData.GetView().Num() * sizeof(float))
|
||||
{
|
||||
// This should be changed somehow to work with the new calculations
|
||||
FMemory::Memcpy(reinterpret_cast<uint8*>(PCMBufferInfo->PCMData.GetView().GetData()) + ((PCMBufferInfo->PCMData.GetView().Num() * sizeof(float)) - NumOfPreAllocatedByteData), DecodedAudioInfo.PCMInfo.PCMData.GetView().GetData(), DecodedAudioInfo.PCMInfo.PCMData.GetView().Num() * sizeof(float));
|
||||
NumOfPreAllocatedByteData -= DecodedAudioInfo.PCMInfo.PCMData.GetView().Num() * sizeof(float);
|
||||
NumOfPreAllocatedByteData = NumOfPreAllocatedByteData < 0 ? 0 : NumOfPreAllocatedByteData;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int64 NewPCMDataSize = ((PCMBufferInfo->PCMData.GetView().Num() * sizeof(float)) + (DecodedAudioInfo.PCMInfo.PCMData.GetView().Num() * sizeof(float)) - NumOfPreAllocatedByteData) / sizeof(float);
|
||||
float* NewPCMDataPtr = static_cast<float*>(FMemory::Malloc(NewPCMDataSize * sizeof(float)));
|
||||
|
||||
if (!NewPCMDataPtr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Adding new PCM data at the end
|
||||
{
|
||||
FMemory::Memcpy(NewPCMDataPtr, PCMBufferInfo->PCMData.GetView().GetData(), (PCMBufferInfo->PCMData.GetView().Num() * sizeof(float)) - NumOfPreAllocatedByteData);
|
||||
FMemory::Memcpy(reinterpret_cast<uint8*>(NewPCMDataPtr) + ((PCMBufferInfo->PCMData.GetView().Num() * sizeof(float)) - NumOfPreAllocatedByteData), DecodedAudioInfo.PCMInfo.PCMData.GetView().GetData(), DecodedAudioInfo.PCMInfo.PCMData.GetView().Num() * sizeof(float));
|
||||
}
|
||||
|
||||
PCMBufferInfo->PCMData = FRuntimeBulkDataBuffer<float>(NewPCMDataPtr, NewPCMDataSize);
|
||||
NumOfPreAllocatedByteData = 0;
|
||||
}
|
||||
|
||||
PCMBufferInfo->PCMNumOfFrames += DecodedAudioInfo.PCMInfo.PCMNumOfFrames;
|
||||
Duration += DecodedAudioInfo.SoundWaveBasicInfo.Duration;
|
||||
ResetPlaybackFinish();
|
||||
|
||||
if (OnPopulateAudioDataNative.IsBound() || OnPopulateAudioData.IsBound())
|
||||
{
|
||||
TArray<float> PCMData(DecodedAudioInfo.PCMInfo.PCMData.GetView().GetData(), DecodedAudioInfo.PCMInfo.PCMData.GetView().Num());
|
||||
AsyncTask(ENamedThreads::GameThread, [this, PCMData = MoveTemp(PCMData)]() mutable
|
||||
{
|
||||
if (OnPopulateAudioDataNative.IsBound())
|
||||
{
|
||||
OnPopulateAudioDataNative.Broadcast(PCMData);
|
||||
}
|
||||
|
||||
if (OnPopulateAudioData.IsBound())
|
||||
{
|
||||
OnPopulateAudioData.Broadcast(PCMData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully added audio data to streaming sound wave.\nAdded audio info: %s"), *DecodedAudioInfo.ToString());
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::ReleaseMemory()
|
||||
{
|
||||
Super::ReleaseMemory();
|
||||
NumOfPreAllocatedByteData = 0;
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::ReleasePlayedAudioData(const FOnPlayedAudioDataReleaseResultNative& Result)
|
||||
{
|
||||
FScopeLock Lock(&DataGuard);
|
||||
const int64 NewPCMDataSize = (PCMBufferInfo->PCMNumOfFrames - GetNumOfPlayedFrames_Internal()) * NumChannels;
|
||||
|
||||
if (GetNumOfPlayedFrames_Internal() > 0 && NumOfPreAllocatedByteData > 0 && NewPCMDataSize < PCMBufferInfo->PCMData.GetView().Num())
|
||||
{
|
||||
NumOfPreAllocatedByteData -= (PCMBufferInfo->PCMData.GetView().Num() * sizeof(float)) - (NewPCMDataSize * sizeof(float));
|
||||
NumOfPreAllocatedByteData = NumOfPreAllocatedByteData < 0 ? 0 : NumOfPreAllocatedByteData;
|
||||
}
|
||||
Super::ReleasePlayedAudioData(Result);
|
||||
}
|
||||
|
||||
UStreamingSoundWave* UStreamingSoundWave::CreateStreamingSoundWave()
|
||||
{
|
||||
if (!IsInGameThread())
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to create a sound wave outside of the game thread"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NewObject<UStreamingSoundWave>();
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::PreAllocateAudioData(int64 NumOfBytesToPreAllocate, const FOnPreAllocateAudioDataResult& Result)
|
||||
{
|
||||
PreAllocateAudioData(NumOfBytesToPreAllocate, FOnPreAllocateAudioDataResultNative::CreateWeakLambda(this, [Result](bool bSucceeded)
|
||||
{
|
||||
Result.ExecuteIfBound(bSucceeded);
|
||||
}));
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::PreAllocateAudioData(int64 NumOfBytesToPreAllocate, const FOnPreAllocateAudioDataResultNative& Result)
|
||||
{
|
||||
AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [this, NumOfBytesToPreAllocate, Result]()
|
||||
{
|
||||
FGCObjectScopeGuard Guard(this);
|
||||
FScopeLock Lock(&DataGuard);
|
||||
|
||||
auto ExecuteResult = [Result](bool bSucceeded)
|
||||
{
|
||||
AsyncTask(ENamedThreads::GameThread, [Result, bSucceeded]()
|
||||
{
|
||||
Result.ExecuteIfBound(bSucceeded);
|
||||
});
|
||||
};
|
||||
|
||||
if (PCMBufferInfo->PCMData.GetView().Num() > 0 || NumOfPreAllocatedByteData > 0)
|
||||
{
|
||||
ensureMsgf(false, TEXT("Pre-allocation of PCM data can only be applied if the PCM data has not yet been allocated"));
|
||||
ExecuteResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
float* NewPCMDataPtr = static_cast<float*>(FMemory::Malloc(NumOfBytesToPreAllocate));
|
||||
if (!NewPCMDataPtr)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to allocate memory to pre-allocate streaming sound wave audio data"));
|
||||
ExecuteResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
NumOfPreAllocatedByteData = NumOfBytesToPreAllocate;
|
||||
PCMBufferInfo->PCMData = FRuntimeBulkDataBuffer<float>(NewPCMDataPtr, NumOfBytesToPreAllocate / sizeof(float));
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Successfully pre-allocated '%lld' number of bytes"), NumOfBytesToPreAllocate);
|
||||
ExecuteResult(true);
|
||||
});
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::AppendAudioDataFromEncoded(TArray<uint8> AudioData, ERuntimeAudioFormat AudioFormat)
|
||||
{
|
||||
AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [this, AudioData = MoveTemp(AudioData), AudioFormat]()
|
||||
{
|
||||
FEncodedAudioStruct EncodedAudioInfo(AudioData, AudioFormat);
|
||||
FDecodedAudioStruct DecodedAudioInfo;
|
||||
if (!URuntimeAudioImporterLibrary::DecodeAudioData(MoveTemp(EncodedAudioInfo), DecodedAudioInfo))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to decode audio data to populate streaming sound wave audio data"));
|
||||
return;
|
||||
}
|
||||
|
||||
PopulateAudioDataFromDecodedInfo(MoveTemp(DecodedAudioInfo));
|
||||
});
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::AppendAudioDataFromRAW(TArray<uint8> RAWData, ERuntimeRAWAudioFormat RAWFormat, int32 InSampleRate, int32 NumOfChannels)
|
||||
{
|
||||
AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [this, RAWData = MoveTemp(RAWData), RAWFormat, InSampleRate, NumOfChannels]() mutable
|
||||
{
|
||||
uint8* ByteDataPtr = RAWData.GetData();
|
||||
const int64 ByteDataSize = RAWData.Num();
|
||||
|
||||
float* Float32DataPtr = nullptr;
|
||||
int64 NumOfSamples = 0;
|
||||
|
||||
// Transcoding RAW data to 32-bit float data
|
||||
{
|
||||
switch (RAWFormat)
|
||||
{
|
||||
case ERuntimeRAWAudioFormat::Int8:
|
||||
{
|
||||
NumOfSamples = ByteDataSize / sizeof(int8);
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<int8, float>(reinterpret_cast<int8*>(ByteDataPtr), NumOfSamples, Float32DataPtr);
|
||||
break;
|
||||
}
|
||||
case ERuntimeRAWAudioFormat::UInt8:
|
||||
{
|
||||
NumOfSamples = ByteDataSize / sizeof(uint8);
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<uint8, float>(ByteDataPtr, NumOfSamples, Float32DataPtr);
|
||||
break;
|
||||
}
|
||||
case ERuntimeRAWAudioFormat::Int16:
|
||||
{
|
||||
NumOfSamples = ByteDataSize / sizeof(int16);
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<int16, float>(reinterpret_cast<int16*>(ByteDataPtr), NumOfSamples, Float32DataPtr);
|
||||
break;
|
||||
}
|
||||
case ERuntimeRAWAudioFormat::UInt16:
|
||||
{
|
||||
NumOfSamples = ByteDataSize / sizeof(uint16);
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<uint16, float>(reinterpret_cast<uint16*>(ByteDataPtr), NumOfSamples, Float32DataPtr);
|
||||
break;
|
||||
}
|
||||
case ERuntimeRAWAudioFormat::UInt32:
|
||||
{
|
||||
NumOfSamples = ByteDataSize / sizeof(uint32);
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<uint32, float>(reinterpret_cast<uint32*>(ByteDataPtr), NumOfSamples, Float32DataPtr);
|
||||
break;
|
||||
}
|
||||
case ERuntimeRAWAudioFormat::Int32:
|
||||
{
|
||||
NumOfSamples = ByteDataSize / sizeof(int32);
|
||||
FRAW_RuntimeCodec::TranscodeRAWData<int32, float>(reinterpret_cast<int32*>(ByteDataPtr), NumOfSamples, Float32DataPtr);
|
||||
break;
|
||||
}
|
||||
case ERuntimeRAWAudioFormat::Float32:
|
||||
{
|
||||
NumOfSamples = ByteDataSize / sizeof(float);
|
||||
Float32DataPtr = static_cast<float*>(FMemory::Memcpy(FMemory::Malloc(ByteDataSize), ByteDataPtr, ByteDataSize));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Float32DataPtr || NumOfSamples <= 0)
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Failed to transcode RAW data to decoded audio info"))
|
||||
return;
|
||||
}
|
||||
|
||||
FDecodedAudioStruct DecodedAudioInfo;
|
||||
{
|
||||
FPCMStruct PCMInfo;
|
||||
{
|
||||
PCMInfo.PCMData = FRuntimeBulkDataBuffer<float>(Float32DataPtr, NumOfSamples);
|
||||
PCMInfo.PCMNumOfFrames = NumOfSamples / NumOfChannels;
|
||||
}
|
||||
DecodedAudioInfo.PCMInfo = MoveTemp(PCMInfo);
|
||||
|
||||
FSoundWaveBasicStruct SoundWaveBasicInfo;
|
||||
{
|
||||
SoundWaveBasicInfo.NumOfChannels = NumOfChannels;
|
||||
SoundWaveBasicInfo.SampleRate = InSampleRate;
|
||||
SoundWaveBasicInfo.Duration = static_cast<float>(DecodedAudioInfo.PCMInfo.PCMNumOfFrames) / InSampleRate;
|
||||
}
|
||||
DecodedAudioInfo.SoundWaveBasicInfo = MoveTemp(SoundWaveBasicInfo);
|
||||
}
|
||||
|
||||
PopulateAudioDataFromDecodedInfo(MoveTemp(DecodedAudioInfo));
|
||||
});
|
||||
}
|
||||
|
||||
void UStreamingSoundWave::SetStopSoundOnPlaybackFinish(bool bStop)
|
||||
{
|
||||
bStopSoundOnPlaybackFinish = bStop;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "BaseRuntimeCodec.h"
|
||||
|
||||
class RUNTIMEAUDIOIMPORTER_API FBINK_RuntimeCodec : public FBaseRuntimeCodec
|
||||
{
|
||||
public:
|
||||
//~ Begin FBaseRuntimeCodec Interface
|
||||
virtual bool CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData) override;
|
||||
virtual bool GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo) override;
|
||||
virtual bool Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality) override;
|
||||
virtual bool Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData) override;
|
||||
virtual ERuntimeAudioFormat GetAudioFormat() const override { return ERuntimeAudioFormat::Bink; }
|
||||
//~ End FBaseRuntimeCodec Interface
|
||||
};
|
@ -1,63 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
|
||||
// TODO: Make FBaseRuntimeCodec an abstract class (currently not possible due to TUniquePtr requiring a non-abstract base class)
|
||||
|
||||
/**
|
||||
* Base runtime codec
|
||||
*/
|
||||
class RUNTIMEAUDIOIMPORTER_API FBaseRuntimeCodec
|
||||
{
|
||||
public:
|
||||
FBaseRuntimeCodec() = default;
|
||||
virtual ~FBaseRuntimeCodec() = default;
|
||||
|
||||
/**
|
||||
* Check if the given audio data appears to be valid
|
||||
*/
|
||||
virtual bool CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData)
|
||||
{
|
||||
ensureMsgf(false, TEXT("CheckAudioFormat cannot be called from base runtime codec"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve audio header information from an encoded source
|
||||
*/
|
||||
virtual bool GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo)
|
||||
{
|
||||
ensureMsgf(false, TEXT("GetHeaderInfo cannot be called from base runtime codec"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode uncompressed PCM data into a compressed format
|
||||
*/
|
||||
virtual bool Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality)
|
||||
{
|
||||
ensureMsgf(false, TEXT("Encode cannot be called from base runtime codec"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode compressed audio data into PCM format
|
||||
*/
|
||||
virtual bool Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData)
|
||||
{
|
||||
ensureMsgf(false, TEXT("Decode cannot be called from base runtime codec"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the format applicable to this codec
|
||||
*/
|
||||
virtual ERuntimeAudioFormat GetAudioFormat() const
|
||||
{
|
||||
ensureMsgf(false, TEXT("GetAudioFormat cannot be called from base runtime codec"));
|
||||
return ERuntimeAudioFormat::Invalid;
|
||||
}
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "BaseRuntimeCodec.h"
|
||||
|
||||
class RUNTIMEAUDIOIMPORTER_API FFLAC_RuntimeCodec : public FBaseRuntimeCodec
|
||||
{
|
||||
public:
|
||||
//~ Begin FBaseRuntimeCodec Interface
|
||||
virtual bool CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData) override;
|
||||
virtual bool GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo) override;
|
||||
virtual bool Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality) override;
|
||||
virtual bool Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData) override;
|
||||
virtual ERuntimeAudioFormat GetAudioFormat() const override { return ERuntimeAudioFormat::Flac; }
|
||||
//~ End FBaseRuntimeCodec Interface
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "BaseRuntimeCodec.h"
|
||||
|
||||
class RUNTIMEAUDIOIMPORTER_API FMP3_RuntimeCodec : public FBaseRuntimeCodec
|
||||
{
|
||||
public:
|
||||
//~ Begin FBaseRuntimeCodec Interface
|
||||
virtual bool CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData) override;
|
||||
virtual bool GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo) override;
|
||||
virtual bool Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality) override;
|
||||
virtual bool Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData) override;
|
||||
virtual ERuntimeAudioFormat GetAudioFormat() const override { return ERuntimeAudioFormat::Mp3; }
|
||||
//~ End FBaseRuntimeCodec Interface
|
||||
};
|
@ -1,168 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Math/UnrealMathUtility.h"
|
||||
#include "HAL/UnrealMemory.h"
|
||||
#include "RuntimeAudioImporterDefines.h"
|
||||
#include "SampleBuffer.h"
|
||||
#include "AudioResampler.h"
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
class RUNTIMEAUDIOIMPORTER_API FRAW_RuntimeCodec
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Getting the minimum and maximum values of the specified RAW format
|
||||
*
|
||||
* @note Key - Minimum, Value - Maximum
|
||||
*/
|
||||
template <typename IntegralType>
|
||||
static TTuple<long long, long long> GetRawMinAndMaxValues()
|
||||
{
|
||||
// Signed 8-bit integer
|
||||
if (std::is_same<IntegralType, int8>::value)
|
||||
{
|
||||
return TTuple<long long, long long>(std::numeric_limits<int8>::min(), std::numeric_limits<int8>::max());
|
||||
}
|
||||
|
||||
// Unsigned 8-bit integer
|
||||
if (std::is_same<IntegralType, uint8>::value)
|
||||
{
|
||||
return TTuple<long long, long long>(std::numeric_limits<uint8>::min(), std::numeric_limits<uint8>::max());
|
||||
}
|
||||
|
||||
// Signed 16-bit integer
|
||||
if (std::is_same<IntegralType, int16>::value)
|
||||
{
|
||||
return TTuple<long long, long long>(std::numeric_limits<int16>::min(), std::numeric_limits<int16>::max());
|
||||
}
|
||||
|
||||
// Unsigned 16-bit integer
|
||||
if (std::is_same<IntegralType, uint16>::value)
|
||||
{
|
||||
return TTuple<long long, long long>(std::numeric_limits<uint16>::min(), std::numeric_limits<uint16>::max());
|
||||
}
|
||||
|
||||
// Signed 32-bit integer
|
||||
if (std::is_same<IntegralType, int32>::value)
|
||||
{
|
||||
return TTuple<long long, long long>(std::numeric_limits<int32>::min(), std::numeric_limits<int32>::max());
|
||||
}
|
||||
|
||||
// Unsigned 32-bit integer
|
||||
if (std::is_same<IntegralType, uint32>::value)
|
||||
{
|
||||
return TTuple<long long, long long>(std::numeric_limits<uint32>::min(), std::numeric_limits<uint32>::max());
|
||||
}
|
||||
|
||||
// Floating point 32-bit
|
||||
if (std::is_same<IntegralType, float>::value)
|
||||
{
|
||||
return TTuple<long long, long long>(-1, 1);
|
||||
}
|
||||
|
||||
ensureMsgf(false, TEXT("Unsupported RAW format"));
|
||||
return TTuple<long long, long long>(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transcoding one RAW Data format to another
|
||||
*
|
||||
* @param RAWData_From RAW data for transcoding
|
||||
* @param RAWData_To Transcoded RAW data with the specified format
|
||||
*/
|
||||
template <typename IntegralTypeFrom, typename IntegralTypeTo>
|
||||
static void TranscodeRAWData(const TArray64<uint8>& RAWData_From, TArray64<uint8>& RAWData_To)
|
||||
{
|
||||
const IntegralTypeFrom* DataFrom = reinterpret_cast<const IntegralTypeFrom*>(RAWData_From.GetData());
|
||||
const int64 RawDataSize = RAWData_From.Num() / sizeof(IntegralTypeFrom);
|
||||
|
||||
IntegralTypeTo* DataTo = nullptr;
|
||||
TranscodeRAWData<IntegralTypeFrom, IntegralTypeTo>(DataFrom, RawDataSize, DataTo);
|
||||
|
||||
RAWData_To = TArray64<uint8>(reinterpret_cast<uint8*>(DataTo), RawDataSize * sizeof(IntegralTypeTo));
|
||||
FMemory::Free(DataTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transcoding one RAW Data format to another
|
||||
*
|
||||
* @param RAWDataFrom Pointer to memory location of the RAW data for transcoding
|
||||
* @param NumOfSamples Number of samples in the RAW data
|
||||
* @param RAWDataTo Pointer to memory location of the transcoded RAW data with the specified format. The number of samples is RAWDataSize
|
||||
*/
|
||||
template <typename IntegralTypeFrom, typename IntegralTypeTo>
|
||||
static void TranscodeRAWData(const IntegralTypeFrom* RAWDataFrom, int64 NumOfSamples, IntegralTypeTo*& RAWDataTo)
|
||||
{
|
||||
/** Creating an empty PCM buffer */
|
||||
RAWDataTo = static_cast<IntegralTypeTo*>(FMemory::Malloc(NumOfSamples * sizeof(IntegralTypeTo)));
|
||||
|
||||
const TTuple<long long, long long> MinAndMaxValuesFrom{GetRawMinAndMaxValues<IntegralTypeFrom>()};
|
||||
const TTuple<long long, long long> MinAndMaxValuesTo{GetRawMinAndMaxValues<IntegralTypeTo>()};
|
||||
|
||||
/** Iterating through the RAW Data to transcode values using a divisor */
|
||||
for (int64 SampleIndex = 0; SampleIndex < NumOfSamples; ++SampleIndex)
|
||||
{
|
||||
RAWDataTo[SampleIndex] = static_cast<IntegralTypeTo>(FMath::GetMappedRangeValueClamped(FVector2D(MinAndMaxValuesFrom.Key, MinAndMaxValuesFrom.Value), FVector2D(MinAndMaxValuesTo.Key, MinAndMaxValuesTo.Value), RAWDataFrom[SampleIndex]));
|
||||
}
|
||||
|
||||
UE_LOG(LogRuntimeAudioImporter, Log, TEXT("Transcoding RAW data of size '%llu' (min: %lld, max: %lld) to size '%llu' (min: %lld, max: %lld)"),
|
||||
static_cast<uint64>(sizeof(IntegralTypeFrom)), MinAndMaxValuesFrom.Key, MinAndMaxValuesFrom.Value, static_cast<uint64>(sizeof(IntegralTypeTo)), MinAndMaxValuesTo.Key, MinAndMaxValuesTo.Value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resampling RAW Data to a different sample rate
|
||||
*
|
||||
* @param RAWData RAW data for resampling
|
||||
* @param NumOfChannels Number of channels in the RAW data
|
||||
* @param SourceSampleRate Source sample rate of the RAW data
|
||||
* @param DestinationSampleRate Destination sample rate of the RAW data
|
||||
* @param ResampledRAWData Resampled RAW data
|
||||
* @return True if the RAW data was successfully resampled
|
||||
*/
|
||||
static bool ResampleRAWData(Audio::FAlignedFloatBuffer& RAWData, int32 NumOfChannels, int32 SourceSampleRate, int32 DestinationSampleRate, Audio::FAlignedFloatBuffer& ResampledRAWData)
|
||||
{
|
||||
const Audio::FResamplingParameters ResampleParameters = {
|
||||
Audio::EResamplingMethod::BestSinc,
|
||||
NumOfChannels,
|
||||
static_cast<float>(SourceSampleRate),
|
||||
static_cast<float>(DestinationSampleRate),
|
||||
RAWData
|
||||
};
|
||||
|
||||
ResampledRAWData.AddUninitialized(Audio::GetOutputBufferSize(ResampleParameters));
|
||||
Audio::FResamplerResults ResampleResults;
|
||||
ResampleResults.OutBuffer = &ResampledRAWData;
|
||||
|
||||
if (!Audio::Resample(ResampleParameters, ResampleResults))
|
||||
{
|
||||
UE_LOG(LogRuntimeAudioImporter, Error, TEXT("Unable to resample audio data from %d to %d"), SourceSampleRate, DestinationSampleRate);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixing RAW Data to a different number of channels
|
||||
*
|
||||
* @param RAWData RAW data for mixing
|
||||
* @param SampleRate Sample rate of the RAW data
|
||||
* @param SourceNumOfChannels Source number of channels in the RAW data
|
||||
* @param DestinationNumOfChannels Destination number of channels in the RAW data
|
||||
* @param RemixedRAWData Remixed RAW data
|
||||
* @return True if the RAW data was successfully mixed
|
||||
*/
|
||||
static bool MixChannelsRAWData(Audio::FAlignedFloatBuffer& RAWData, int32 SampleRate, int32 SourceNumOfChannels, int32 DestinationNumOfChannels, Audio::FAlignedFloatBuffer& RemixedRAWData)
|
||||
{
|
||||
Audio::TSampleBuffer<float> PCMSampleBuffer(RAWData, SourceNumOfChannels, SampleRate);
|
||||
{
|
||||
PCMSampleBuffer.MixBufferToChannels(DestinationNumOfChannels);
|
||||
}
|
||||
RemixedRAWData = Audio::FAlignedFloatBuffer(PCMSampleBuffer.GetData(), PCMSampleBuffer.GetNumSamples());
|
||||
return true;
|
||||
}
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseRuntimeCodec.h"
|
||||
|
||||
/**
|
||||
* A factory for constructing the codecs used for encoding and decoding audio data
|
||||
*/
|
||||
class RUNTIMEAUDIOIMPORTER_API FRuntimeCodecFactory
|
||||
{
|
||||
public:
|
||||
FRuntimeCodecFactory() = default;
|
||||
virtual ~FRuntimeCodecFactory() = default;
|
||||
|
||||
/**
|
||||
* Get the codec based on the file path extension
|
||||
*
|
||||
* @param FilePath The file path from which to get the codec
|
||||
* @return The detected codec, or a nullptr if it could not be detected
|
||||
*/
|
||||
virtual TUniquePtr<FBaseRuntimeCodec> GetCodec(const FString& FilePath);
|
||||
|
||||
/**
|
||||
* Get the codec based on the audio format
|
||||
*
|
||||
* @param AudioFormat The format from which to get the codec
|
||||
* @return The detected codec, or a nullptr if it could not be detected
|
||||
*/
|
||||
virtual TUniquePtr<FBaseRuntimeCodec> GetCodec(ERuntimeAudioFormat AudioFormat);
|
||||
|
||||
/**
|
||||
* Get the codec based on the audio data (slower, but more reliable)
|
||||
*
|
||||
* @param AudioData The audio data from which to get the codec
|
||||
* @return The detected codec, or a nullptr if it could not be detected
|
||||
*/
|
||||
virtual TUniquePtr<FBaseRuntimeCodec> GetCodec(const FRuntimeBulkDataBuffer<uint8>& AudioData);
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "BaseRuntimeCodec.h"
|
||||
|
||||
class RUNTIMEAUDIOIMPORTER_API FVORBIS_RuntimeCodec : public FBaseRuntimeCodec
|
||||
{
|
||||
public:
|
||||
//~ Begin FBaseRuntimeCodec Interface
|
||||
virtual bool CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData) override;
|
||||
virtual bool GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo) override;
|
||||
virtual bool Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality) override;
|
||||
virtual bool Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData) override;
|
||||
virtual ERuntimeAudioFormat GetAudioFormat() const override { return ERuntimeAudioFormat::OggVorbis; }
|
||||
//~ End FBaseRuntimeCodec Interface
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "BaseRuntimeCodec.h"
|
||||
|
||||
class RUNTIMEAUDIOIMPORTER_API FWAV_RuntimeCodec : public FBaseRuntimeCodec
|
||||
{
|
||||
public:
|
||||
//~ Begin FBaseRuntimeCodec Interface
|
||||
virtual bool CheckAudioFormat(const FRuntimeBulkDataBuffer<uint8>& AudioData) override;
|
||||
virtual bool GetHeaderInfo(FEncodedAudioStruct EncodedData, FRuntimeAudioHeaderInfo& HeaderInfo) override;
|
||||
virtual bool Encode(FDecodedAudioStruct DecodedData, FEncodedAudioStruct& EncodedData, uint8 Quality) override;
|
||||
virtual bool Decode(FEncodedAudioStruct EncodedData, FDecodedAudioStruct& DecodedData) override;
|
||||
virtual ERuntimeAudioFormat GetAudioFormat() const override { return ERuntimeAudioFormat::Wav; }
|
||||
//~ End FBaseRuntimeCodec Interface
|
||||
};
|
@ -1,53 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
#include "MetasoundDataReference.h"
|
||||
#include "MetasoundDataTypeRegistrationMacro.h"
|
||||
#include "IAudioProxyInitializer.h"
|
||||
#include "Sound/SoundWave.h"
|
||||
|
||||
namespace RuntimeAudioImporter
|
||||
{
|
||||
extern const FString RUNTIMEAUDIOIMPORTER_API PluginAuthor;
|
||||
extern const FText RUNTIMEAUDIOIMPORTER_API PluginNodeMissingPrompt;
|
||||
|
||||
/**
|
||||
* FImportedWave is an alternative to FWaveAsset to hold proxy data obtained from UImportedSoundWave
|
||||
*/
|
||||
class RUNTIMEAUDIOIMPORTER_API FImportedWave
|
||||
{
|
||||
FSoundWaveProxyPtr SoundWaveProxy;
|
||||
|
||||
public:
|
||||
FImportedWave() = default;
|
||||
FImportedWave(const FImportedWave&) = default;
|
||||
FImportedWave& operator=(const FImportedWave& Other) = default;
|
||||
|
||||
FImportedWave(const TUniquePtr<Audio::IProxyData>& InInitData);
|
||||
|
||||
bool IsSoundWaveValid() const
|
||||
{
|
||||
return SoundWaveProxy.IsValid();
|
||||
}
|
||||
|
||||
const FSoundWaveProxyPtr& GetSoundWaveProxy() const
|
||||
{
|
||||
return SoundWaveProxy;
|
||||
}
|
||||
|
||||
const FSoundWaveProxy* operator->() const
|
||||
{
|
||||
return SoundWaveProxy.Get();
|
||||
}
|
||||
|
||||
FSoundWaveProxy* operator->()
|
||||
{
|
||||
return SoundWaveProxy.Get();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
DECLARE_METASOUND_DATA_REFERENCE_TYPES(RuntimeAudioImporter::FImportedWave, RUNTIMEAUDIOIMPORTER_API, FImportedWaveTypeInfo, FImportedWaveReadRef, FImportedWaveWriteRef)
|
||||
#endif
|
@ -1,42 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "PreImportedSoundAsset.generated.h"
|
||||
|
||||
/**
|
||||
* Pre-imported asset which collects MP3 audio data. Used if you want to load the MP3 file into the editor in advance
|
||||
*/
|
||||
UCLASS(BlueprintType, Category = "Pre Imported Sound Asset")
|
||||
class RUNTIMEAUDIOIMPORTER_API UPreImportedSoundAsset : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPreImportedSoundAsset();
|
||||
|
||||
/** Audio data array */
|
||||
UPROPERTY()
|
||||
TArray<uint8> AudioDataArray;
|
||||
|
||||
/** Audio data format */
|
||||
UPROPERTY(Category = "Info", VisibleAnywhere, Meta = (DisplayName = "Audio format"))
|
||||
ERuntimeAudioFormat AudioFormat;
|
||||
|
||||
/** Information about the basic details of an audio file. Used only for convenience in the editor */
|
||||
#if WITH_EDITORONLY_DATA
|
||||
UPROPERTY(Category = "File Path", VisibleAnywhere, Meta = (DisplayName = "Source file path"))
|
||||
FString SourceFilePath;
|
||||
|
||||
UPROPERTY(Category = "Info", VisibleAnywhere, Meta = (DisplayName = "Sound duration"))
|
||||
FString SoundDuration;
|
||||
|
||||
UPROPERTY(Category = "Info", VisibleAnywhere, Meta = (DisplayName = "Number of channels"))
|
||||
int32 NumberOfChannels;
|
||||
|
||||
UPROPERTY(Category = "Info", VisibleAnywhere, Meta = (DisplayName = "Sample rate"))
|
||||
int32 SampleRate;
|
||||
#endif
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
class FRuntimeAudioImporterModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "Logging/LogCategory.h"
|
||||
#include "Logging/LogMacros.h"
|
||||
#include "Logging/LogVerbosity.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogRuntimeAudioImporter, Log, All);
|
@ -1,483 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Sound/ImportedSoundWave.h"
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "RuntimeAudioImporterLibrary.generated.h"
|
||||
|
||||
class UPreImportedSoundAsset;
|
||||
class URuntimeAudioImporterLibrary;
|
||||
|
||||
/** Static delegate broadcasting the audio importer progress */
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FOnAudioImporterProgressNative, int32);
|
||||
|
||||
/** Dynamic delegate broadcasting the audio importer progress */
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAudioImporterProgress, int32, Percentage);
|
||||
|
||||
/** Static delegate broadcasting the audio importer result */
|
||||
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnAudioImporterResultNative, URuntimeAudioImporterLibrary*, UImportedSoundWave*, ERuntimeImportStatus);
|
||||
|
||||
/** Dynamic delegate broadcasting the audio importer result */
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnAudioImporterResult, URuntimeAudioImporterLibrary*, Importer, UImportedSoundWave*, ImportedSoundWave, ERuntimeImportStatus, Status);
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnAudioImporterResultNoDynamic, URuntimeAudioImporterLibrary*, UImportedSoundWave*, ERuntimeImportStatus);
|
||||
|
||||
/** Static delegate broadcasting the result of the conversion from SoundWave to ImportedSoundWave */
|
||||
DECLARE_DELEGATE_TwoParams(FOnRegularToAudioImporterSoundWaveConvertResultNative, bool, UImportedSoundWave*);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of the conversion from SoundWave to ImportedSoundWave */
|
||||
DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnRegularToAudioImporterSoundWaveConvertResult, bool, bSucceeded, UImportedSoundWave*, ImportedSoundWave);
|
||||
|
||||
|
||||
/** Static delegate broadcasting the result of the audio export to buffer */
|
||||
DECLARE_DELEGATE_TwoParams(FOnAudioExportToBufferResultNative, bool, const TArray64<uint8>&);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of the audio export to buffer */
|
||||
DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnAudioExportToBufferResult, bool, bSucceeded, const TArray<uint8>&, AudioData);
|
||||
|
||||
/** Static delegate broadcasting the result of the audio export to file */
|
||||
DECLARE_DELEGATE_OneParam(FOnAudioExportToFileResultNative, bool);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of the audio export to file */
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAudioExportToFileResult, bool, bSucceeded);
|
||||
|
||||
|
||||
/** Static delegate broadcasting the result of the RAW data transcoded from buffer */
|
||||
DECLARE_DELEGATE_TwoParams(FOnRAWDataTranscodeFromBufferResultNative, bool, const TArray64<uint8>&);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of the RAW data transcoded from buffer */
|
||||
DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnRAWDataTranscodeFromBufferResult, bool, bSucceeded, const TArray<uint8>&, RAWData);
|
||||
|
||||
|
||||
/** Static delegate broadcasting the result of the RAW data transcoded from file */
|
||||
DECLARE_DELEGATE_OneParam(FOnRAWDataTranscodeFromFileResultNative, bool);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of the RAW data transcoded from file */
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnRAWDataTranscodeFromFileResult, bool, bSucceeded);
|
||||
|
||||
|
||||
/** Static delegate broadcasting the result of retrieving audio header info */
|
||||
DECLARE_DELEGATE_TwoParams(FOnGetAudioHeaderInfoResultNative, bool, const FRuntimeAudioHeaderInfo&);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of retrieving audio header info */
|
||||
DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnGetAudioHeaderInfoResult, bool, bSucceeded, const FRuntimeAudioHeaderInfo&, HeaderInfo);
|
||||
|
||||
|
||||
/** Dynamic delegate broadcasting the result of scanning directory for audio files */
|
||||
DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnScanDirectoryForAudioFilesResult, bool, bSucceeded, const TArray<FString>&, AudioFilePaths);
|
||||
|
||||
/** Static delegate broadcasting the result of scanning directory for audio files */
|
||||
DECLARE_DELEGATE_TwoParams(FOnScanDirectoryForAudioFilesResultNative, bool, const TArray<FString>&);
|
||||
|
||||
|
||||
/**
|
||||
* Runtime Audio Importer library
|
||||
* Various functions related to working with audio data, including importing audio files, manually encoding and decoding audio data, and more
|
||||
*/
|
||||
UCLASS(BlueprintType, Category = "Runtime Audio Importer")
|
||||
class RUNTIMEAUDIOIMPORTER_API URuntimeAudioImporterLibrary : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Bind to know when audio import is on progress. Suitable for use in C++ */
|
||||
FOnAudioImporterProgressNative OnProgressNative;
|
||||
|
||||
/** Bind to know when audio import is on progress */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Runtime Audio Importer|Delegates")
|
||||
FOnAudioImporterProgress OnProgress;
|
||||
|
||||
/** Bind to know when audio import is complete (even if it fails). Suitable for use in C++ */
|
||||
FOnAudioImporterResultNative OnResultNative;
|
||||
|
||||
/** Bind to know when audio import is complete (even if it fails) */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Runtime Audio Importer|Delegates")
|
||||
FOnAudioImporterResult OnResult;
|
||||
|
||||
FOnAudioImporterResultNoDynamic OnResultNoDynamic;
|
||||
|
||||
/**
|
||||
* Tries to retrieve audio data from a given regular sound wave
|
||||
*
|
||||
* @param SoundWave The sound wave from which to obtain audio data
|
||||
* @param OutDecodedAudioInfo The decoded audio information. Populated only if the function returns true
|
||||
* @return True if the audio data was successfully retrieved
|
||||
*/
|
||||
static bool TryToRetrieveSoundWaveData(USoundWave* SoundWave, FDecodedAudioStruct& OutDecodedAudioInfo);
|
||||
|
||||
/**
|
||||
* Instantiate a RuntimeAudioImporter object
|
||||
*
|
||||
* @return The RuntimeAudioImporter object. Bind to it's OnProgress and OnResult delegates
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (Keywords = "Create, Audio, Runtime, MP3, FLAC, WAV, OGG, Vorbis"), Category = "Runtime Audio Importer")
|
||||
static URuntimeAudioImporterLibrary* CreateRuntimeAudioImporter();
|
||||
|
||||
/**
|
||||
* Import audio from a file
|
||||
*
|
||||
* @param FilePath Path to the audio file to import
|
||||
* @param AudioFormat Audio format
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (Keywords = "Importer, Transcoder, Converter, Runtime, MP3, FLAC, WAV, OGG, Vorbis"), Category = "Runtime Audio Importer|Import")
|
||||
void ImportAudioFromFile(const FString& FilePath, ERuntimeAudioFormat AudioFormat);
|
||||
|
||||
/**
|
||||
* Import audio from a pre-imported sound asset
|
||||
*
|
||||
* @param PreImportedSoundAsset PreImportedSoundAsset object reference
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (Keywords = "Importer, Transcoder, Converter, Runtime, MP3, FLAC, WAV, OGG, Vorbis, BINK"), Category = "Runtime Audio Importer|Import")
|
||||
void ImportAudioFromPreImportedSound(UPreImportedSoundAsset* PreImportedSoundAsset);
|
||||
|
||||
/**
|
||||
* Import audio from a buffer
|
||||
*
|
||||
* @param AudioData Audio data array
|
||||
* @param AudioFormat Audio format
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (Keywords = "Importer, Transcoder, Converter, Runtime, MP3, FLAC, WAV, OGG, Vorbis, BINK"), Category = "Runtime Audio Importer|Import")
|
||||
void ImportAudioFromBuffer(TArray<uint8> AudioData, ERuntimeAudioFormat AudioFormat);
|
||||
|
||||
/**
|
||||
* Import audio from a buffer. Suitable for use with 64-bit data size
|
||||
*
|
||||
* @param AudioData Audio data array
|
||||
* @param AudioFormat Audio format
|
||||
*/
|
||||
void ImportAudioFromBuffer(TArray64<uint8> AudioData, ERuntimeAudioFormat AudioFormat);
|
||||
|
||||
/**
|
||||
* Import audio from a RAW file. The audio data must not have headers and must be uncompressed
|
||||
*
|
||||
* @param FilePath Path to the audio file to import
|
||||
* @param RAWFormat RAW audio format
|
||||
* @param SampleRate The number of samples per second
|
||||
* @param NumOfChannels The number of channels (1 for mono, 2 for stereo, etc)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Import Audio From RAW File", Keywords = "PCM, RAW"), Category = "Runtime Audio Importer|Import")
|
||||
void ImportAudioFromRAWFile(const FString& FilePath, UPARAM(DisplayName = "RAW Format") ERuntimeRAWAudioFormat RAWFormat, int32 SampleRate = 44100, int32 NumOfChannels = 1);
|
||||
|
||||
/**
|
||||
* Import audio from a RAW buffer. The audio data must not have headers and must be uncompressed
|
||||
*
|
||||
* @param RAWBuffer RAW audio buffer
|
||||
* @param RAWFormat RAW audio format
|
||||
* @param SampleRate The number of samples per second
|
||||
* @param NumOfChannels The number of channels (1 for mono, 2 for stereo, etc)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Import Audio From RAW Buffer", Keywords = "PCM, RAW"), Category = "Runtime Audio Importer|Import")
|
||||
void ImportAudioFromRAWBuffer(UPARAM(DisplayName = "RAW Buffer") TArray<uint8> RAWBuffer, UPARAM(DisplayName = "RAW Format") ERuntimeRAWAudioFormat RAWFormat, int32 SampleRate = 44100, int32 NumOfChannels = 1);
|
||||
|
||||
/**
|
||||
* Import audio from a RAW buffer. The audio data must not have headers and must be uncompressed. Suitable for use with 64-bit data size
|
||||
*
|
||||
* @param RAWBuffer The RAW audio buffer
|
||||
* @param RAWFormat RAW audio format
|
||||
* @param SampleRate The number of samples per second
|
||||
* @param NumOfChannels The number of channels (1 for mono, 2 for stereo, etc)
|
||||
*/
|
||||
void ImportAudioFromRAWBuffer(TArray64<uint8> RAWBuffer, ERuntimeRAWAudioFormat RAWFormat, int32 SampleRate = 44100, int32 NumOfChannels = 1);
|
||||
|
||||
/**
|
||||
* Converts a regular SoundWave to an inherited sound wave of type ImportedSoundWave used in RuntimeAudioImporter
|
||||
*
|
||||
* @param SoundWave The regular USoundWave to convert
|
||||
* @param ImportedSoundWaveClass The subclass of UImportedSoundWave to create and convert to
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Convert")
|
||||
static void ConvertRegularToImportedSoundWave(USoundWave* SoundWave, TSubclassOf<UImportedSoundWave> ImportedSoundWaveClass, const FOnRegularToAudioImporterSoundWaveConvertResult& Result);
|
||||
|
||||
/**
|
||||
* Converts a regular SoundWave to an inherited sound wave of type ImportedSoundWave used in RuntimeAudioImporter. Suitable for use in C++
|
||||
*
|
||||
* @param SoundWave The regular USoundWave to convert
|
||||
* @param ImportedSoundWaveClass The subclass of UImportedSoundWave to create and convert to
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void ConvertRegularToImportedSoundWave(USoundWave* SoundWave, TSubclassOf<UImportedSoundWave> ImportedSoundWaveClass, const FOnRegularToAudioImporterSoundWaveConvertResultNative& Result);
|
||||
|
||||
/**
|
||||
* Transcode one RAW Data format into another from buffer
|
||||
*
|
||||
* @param RAWDataFrom The RAW audio data to transcode
|
||||
* @param RAWFormatFrom The original format of the RAW audio data
|
||||
* @param RAWFormatTo The desired format of the transcoded RAW audio data
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Transcode RAW Data From Buffer"), Category = "Runtime Audio Importer|Transcode")
|
||||
static void TranscodeRAWDataFromBuffer(UPARAM(DisplayName = "RAW Data From") TArray<uint8> RAWDataFrom, UPARAM(DisplayName = "RAW Format From") ERuntimeRAWAudioFormat RAWFormatFrom, UPARAM(DisplayName = "RAW Format To") ERuntimeRAWAudioFormat RAWFormatTo, const FOnRAWDataTranscodeFromBufferResult& Result);
|
||||
|
||||
/**
|
||||
* Transcode one RAW data format into another from buffer. Suitable for use with 64-bit data size
|
||||
*
|
||||
* @param RAWDataFrom The RAW audio data to transcode
|
||||
* @param RAWFormatFrom The original format of the RAW audio data
|
||||
* @param RAWFormatTo The desired format of the transcoded RAW audio data
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void TranscodeRAWDataFromBuffer(TArray64<uint8> RAWDataFrom, ERuntimeRAWAudioFormat RAWFormatFrom, ERuntimeRAWAudioFormat RAWFormatTo, const FOnRAWDataTranscodeFromBufferResultNative& Result);
|
||||
|
||||
/**
|
||||
* Transcode one RAW data format into another from file
|
||||
*
|
||||
* @param FilePathFrom Path to file with the RAW audio data to transcode
|
||||
* @param RAWFormatFrom The original format of the RAW audio data
|
||||
* @param FilePathTo File path for saving RAW data
|
||||
* @param RAWFormatTo The desired format of the transcoded RAW audio data
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Transcode RAW Data From File"), Category = "Runtime Audio Importer|Transcode")
|
||||
static void TranscodeRAWDataFromFile(const FString& FilePathFrom, UPARAM(DisplayName = "RAW Format From") ERuntimeRAWAudioFormat RAWFormatFrom, const FString& FilePathTo, UPARAM(DisplayName = "RAW Format To") ERuntimeRAWAudioFormat RAWFormatTo, const FOnRAWDataTranscodeFromFileResult& Result);
|
||||
|
||||
/**
|
||||
* Transcode one RAW data format into another from file. Suitable for use in C++
|
||||
*
|
||||
* @param FilePathFrom Path to file with the RAW audio data to transcode
|
||||
* @param RAWFormatFrom The original format of the RAW audio data
|
||||
* @param FilePathTo File path for saving RAW data
|
||||
* @param RAWFormatTo The desired format of the transcoded RAW audio data
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void TranscodeRAWDataFromFile(const FString& FilePathFrom, UPARAM(DisplayName = "RAW Format From") ERuntimeRAWAudioFormat RAWFormatFrom, const FString& FilePathTo, UPARAM(DisplayName = "RAW Format To") ERuntimeRAWAudioFormat RAWFormatTo, const FOnRAWDataTranscodeFromFileResultNative& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave to a file
|
||||
*
|
||||
* @param ImportedSoundWave Imported sound wave to be exported
|
||||
* @param AudioFormat The desired audio format for the exported file. Note that some formats may not be supported
|
||||
* @param SavePath The path where the exported file will be saved
|
||||
* @param Quality The quality of the encoded audio data, from 0 to 100
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Export")
|
||||
static void ExportSoundWaveToFile(UImportedSoundWave* ImportedSoundWave, const FString& SavePath, ERuntimeAudioFormat AudioFormat, uint8 Quality, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToFileResult& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave into file. Suitable for use in C++
|
||||
*
|
||||
* @param ImportedSoundWavePtr Imported sound wave to be exported
|
||||
* @param AudioFormat The desired audio format for the exported file. Note that some formats may not be supported
|
||||
* @param SavePath The path where the exported file will be saved
|
||||
* @param Quality The quality of the encoded audio data, from 0 to 100
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void ExportSoundWaveToFile(TWeakObjectPtr<UImportedSoundWave> ImportedSoundWavePtr, const FString& SavePath, ERuntimeAudioFormat AudioFormat, uint8 Quality, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToFileResultNative& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave into a buffer
|
||||
*
|
||||
* @param ImportedSoundWave Imported sound wave to be exported
|
||||
* @param AudioFormat The desired audio format for the exported file. Note that some formats may not be supported
|
||||
* @param Quality The quality of the encoded audio data, from 0 to 100
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Export")
|
||||
static void ExportSoundWaveToBuffer(UImportedSoundWave* ImportedSoundWave, ERuntimeAudioFormat AudioFormat, uint8 Quality, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToBufferResult& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave into a buffer. Suitable for use in C++
|
||||
*
|
||||
* @param ImportedSoundWavePtr Imported sound wave to be exported
|
||||
* @param AudioFormat The desired audio format for the exported file. Note that some formats may not be supported
|
||||
* @param Quality The quality of the encoded audio data, from 0 to 100
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void ExportSoundWaveToBuffer(TWeakObjectPtr<UImportedSoundWave> ImportedSoundWavePtr, ERuntimeAudioFormat AudioFormat, uint8 Quality, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToBufferResultNative& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave into a RAW file
|
||||
*
|
||||
* @param ImportedSoundWave Imported sound wave to be exported
|
||||
* @param RAWFormat Required RAW format for exporting
|
||||
* @param SavePath Path to save the file
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Export Sound Wave To RAW File"), Category = "Runtime Audio Importer|Export")
|
||||
static void ExportSoundWaveToRAWFile(UImportedSoundWave* ImportedSoundWave, const FString& SavePath, UPARAM(DisplayName = "RAW Format") ERuntimeRAWAudioFormat RAWFormat, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToFileResult& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave into a RAW file. Suitable for use in C++
|
||||
*
|
||||
* @param ImportedSoundWavePtr Imported sound wave to be exported
|
||||
* @param RAWFormat Required RAW format for exporting
|
||||
* @param SavePath Path to save the file
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void ExportSoundWaveToRAWFile(TWeakObjectPtr<UImportedSoundWave> ImportedSoundWavePtr, const FString& SavePath, ERuntimeRAWAudioFormat RAWFormat, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToFileResultNative& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave into a RAW buffer
|
||||
*
|
||||
* @param ImportedSoundWave Imported sound wave to be exported
|
||||
* @param RAWFormat Required RAW format for exporting
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Export Sound Wave To RAW Buffer"), Category = "Runtime Audio Importer|Export")
|
||||
static void ExportSoundWaveToRAWBuffer(UImportedSoundWave* ImportedSoundWave, UPARAM(DisplayName = "RAW Format") ERuntimeRAWAudioFormat RAWFormat, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToBufferResult& Result);
|
||||
|
||||
/**
|
||||
* Export the imported sound wave into a RAW buffer. Suitable for use with 64-bit data size
|
||||
*
|
||||
* @param ImportedSoundWavePtr Imported sound wave to be exported
|
||||
* @param RAWFormat Required RAW format for exporting
|
||||
* @param OverrideOptions Override options for the export
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void ExportSoundWaveToRAWBuffer(TWeakObjectPtr<UImportedSoundWave> ImportedSoundWavePtr, ERuntimeRAWAudioFormat RAWFormat, const FRuntimeAudioExportOverrideOptions& OverrideOptions, const FOnAudioExportToBufferResultNative& Result);
|
||||
|
||||
/**
|
||||
* Get the audio format based on file extension
|
||||
*
|
||||
* @param FilePath File path where to find the format (by extension)
|
||||
* @return The found audio format (e.g. mp3. flac, etc)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Utilities")
|
||||
static ERuntimeAudioFormat GetAudioFormat(const FString& FilePath);
|
||||
|
||||
/**
|
||||
* Determine the audio format based on audio data. A more advanced way to get the format
|
||||
*
|
||||
* @param AudioData Audio data array
|
||||
* @return The found audio format (e.g. mp3. flac, etc)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Utilities")
|
||||
static ERuntimeAudioFormat GetAudioFormatAdvanced(const TArray<uint8>& AudioData);
|
||||
|
||||
/**
|
||||
* Retrieve audio header (metadata) information from a file
|
||||
*
|
||||
* @param FilePath The path to the audio file from which header information will be retrieved
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Utilities")
|
||||
static void GetAudioHeaderInfoFromFile(const FString& FilePath, const FOnGetAudioHeaderInfoResult& Result);
|
||||
|
||||
/**
|
||||
* Retrieve audio header (metadata) information from a file. Suitable for use in C++
|
||||
*
|
||||
* @param FilePath The path to the audio file from which header information will be retrieved
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void GetAudioHeaderInfoFromFile(const FString& FilePath, const FOnGetAudioHeaderInfoResultNative& Result);
|
||||
|
||||
/**
|
||||
* Retrieve audio header (metadata) information from a buffer
|
||||
*
|
||||
* @param AudioData The audio data from which the header information will be retrieved
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Utilities")
|
||||
static void GetAudioHeaderInfoFromBuffer(TArray<uint8> AudioData, const FOnGetAudioHeaderInfoResult& Result);
|
||||
|
||||
/**
|
||||
* Retrieve audio header (metadata) information from a buffer. Suitable for use with 64-bit data size
|
||||
*
|
||||
* @param AudioData The audio data from which the header information will be retrieved
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void GetAudioHeaderInfoFromBuffer(TArray64<uint8> AudioData, const FOnGetAudioHeaderInfoResultNative& Result);
|
||||
|
||||
/**
|
||||
* Determine audio format based on audio data. A more advanced way to get the format. Suitable for use with 64-bit data size
|
||||
*
|
||||
* @param AudioData Audio data array
|
||||
* @return The found audio format (e.g. mp3. flac, etc)
|
||||
*/
|
||||
static ERuntimeAudioFormat GetAudioFormatAdvanced(const TArray64<uint8>& AudioData);
|
||||
|
||||
/**
|
||||
* Determine audio format based on audio data. A more advanced way to get the format. Suitable for use with 64-bit data size
|
||||
*
|
||||
* @param AudioData Audio data array
|
||||
* @return The found audio format (e.g. mp3. flac, etc)
|
||||
*/
|
||||
static ERuntimeAudioFormat GetAudioFormatAdvanced(const FRuntimeBulkDataBuffer<uint8>& AudioData);
|
||||
|
||||
/**
|
||||
* Convert seconds to string (hh:mm:ss or mm:ss depending on the number of seconds)
|
||||
*
|
||||
* @return hh:mm:ss or mm:ss string representation
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Runtime Audio Importer|Utilities")
|
||||
static FString ConvertSecondsToString(int64 Seconds);
|
||||
|
||||
/**
|
||||
* Scan the specified directory for audio files
|
||||
*
|
||||
* @param Directory The directory path to scan for audio files
|
||||
* @param bRecursive Whether to search for files recursively in subdirectories
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (Keywords = "Folder"), Category = "Runtime Audio Importer|Utilities")
|
||||
static void ScanDirectoryForAudioFiles(const FString& Directory, bool bRecursive, const FOnScanDirectoryForAudioFilesResult& Result);
|
||||
|
||||
/**
|
||||
* Scan the specified directory for audio files. Suitable for use in C++
|
||||
*
|
||||
* @param Directory The directory path to scan for audio files
|
||||
* @param bRecursive Whether to search for files recursively in subdirectories
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void ScanDirectoryForAudioFiles(const FString& Directory, bool bRecursive, const FOnScanDirectoryForAudioFilesResultNative& Result);
|
||||
|
||||
/**
|
||||
* Decode compressed audio data to uncompressed.
|
||||
*
|
||||
* @param EncodedAudioInfo The encoded audio data
|
||||
* @param DecodedAudioInfo The decoded audio data
|
||||
* @return Whether the decoding was successful or not
|
||||
*/
|
||||
static bool DecodeAudioData(FEncodedAudioStruct&& EncodedAudioInfo, FDecodedAudioStruct& DecodedAudioInfo);
|
||||
|
||||
/**
|
||||
* Encode uncompressed audio data to compressed.
|
||||
*
|
||||
* @param DecodedAudioInfo The decoded audio data
|
||||
* @param EncodedAudioInfo The encoded audio data
|
||||
* @param Quality The quality of the encoded audio data, from 0 to 100
|
||||
* @return Whether the encoding was successful or not
|
||||
*/
|
||||
static bool EncodeAudioData(FDecodedAudioStruct&& DecodedAudioInfo, FEncodedAudioStruct& EncodedAudioInfo, uint8 Quality);
|
||||
|
||||
/**
|
||||
* Import audio from 32-bit float PCM data
|
||||
*
|
||||
* @param PCMData PCM data
|
||||
* @param SampleRate The number of samples per second
|
||||
* @param NumOfChannels The number of channels (1 for mono, 2 for stereo, etc)
|
||||
*/
|
||||
void ImportAudioFromFloat32Buffer(FRuntimeBulkDataBuffer<float>&& PCMData, int32 SampleRate = 44100, int32 NumOfChannels = 1);
|
||||
|
||||
/**
|
||||
* Create Imported Sound Wave and finish importing.
|
||||
*
|
||||
* @param DecodedAudioInfo Decoded audio data
|
||||
*/
|
||||
void ImportAudioFromDecodedInfo(FDecodedAudioStruct&& DecodedAudioInfo);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Audio transcoding progress callback
|
||||
*
|
||||
* @param Percentage Percentage of importing completion (0-100%)
|
||||
*/
|
||||
void OnProgress_Internal(int32 Percentage);
|
||||
|
||||
/**
|
||||
* Audio importing finished callback
|
||||
*
|
||||
* @param ImportedSoundWave Reference to the imported sound wave
|
||||
* @param Status Importing status
|
||||
*/
|
||||
void OnResult_Internal(UImportedSoundWave* ImportedSoundWave, ERuntimeImportStatus Status);
|
||||
};
|
@ -1,514 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
#include "AudioCaptureDeviceInterface.h"
|
||||
#endif
|
||||
#include "Engine/EngineBaseTypes.h"
|
||||
#include "Sound/SoundGroups.h"
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
|
||||
#if UE_VERSION_OLDER_THAN(4, 26, 0)
|
||||
#include "DSP/BufferVectorOperations.h"
|
||||
#endif
|
||||
|
||||
#include "RuntimeAudioImporterTypes.generated.h"
|
||||
|
||||
#if UE_VERSION_OLDER_THAN(4, 26, 0)
|
||||
namespace Audio
|
||||
{
|
||||
using FAlignedFloatBuffer = Audio::AlignedFloatBuffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Possible audio importing results */
|
||||
UENUM(BlueprintType, Category = "Runtime Audio Importer")
|
||||
enum class ERuntimeImportStatus : uint8
|
||||
{
|
||||
/** Successful import */
|
||||
SuccessfulImport UMETA(DisplayName = "Success"),
|
||||
|
||||
/** Failed to read Audio Data Array */
|
||||
FailedToReadAudioDataArray UMETA(DisplayName = "Failed to read Audio Data Array"),
|
||||
|
||||
/** SoundWave declaration error */
|
||||
SoundWaveDeclarationError UMETA(DisplayName = "SoundWave declaration error"),
|
||||
|
||||
/** Invalid audio format (Can't determine the format of the audio file) */
|
||||
InvalidAudioFormat UMETA(DisplayName = "Invalid audio format"),
|
||||
|
||||
/** The audio file does not exist */
|
||||
AudioDoesNotExist UMETA(DisplayName = "Audio does not exist"),
|
||||
|
||||
/** Load file to array error */
|
||||
LoadFileToArrayError UMETA(DisplayName = "Load file to array error")
|
||||
};
|
||||
|
||||
/** Possible audio formats (extensions) */
|
||||
UENUM(BlueprintType, Category = "Runtime Audio Importer")
|
||||
enum class ERuntimeAudioFormat : uint8
|
||||
{
|
||||
Auto UMETA(DisplayName = "Determine format automatically"),
|
||||
Mp3 UMETA(DisplayName = "mp3"),
|
||||
Wav UMETA(DisplayName = "wav"),
|
||||
Flac UMETA(DisplayName = "flac"),
|
||||
OggVorbis UMETA(DisplayName = "ogg vorbis"),
|
||||
Bink UMETA(DisplayName = "bink"),
|
||||
Invalid UMETA(DisplayName = "invalid (not defined format, internal use only)", Hidden)
|
||||
};
|
||||
|
||||
/** Possible RAW (uncompressed, PCM) audio formats */
|
||||
UENUM(BlueprintType, Category = "Runtime Audio Importer")
|
||||
enum class ERuntimeRAWAudioFormat : uint8
|
||||
{
|
||||
Int8 UMETA(DisplayName = "Signed 8-bit integer"),
|
||||
UInt8 UMETA(DisplayName = "Unsigned 8-bit integer"),
|
||||
Int16 UMETA(DisplayName = "Signed 16-bit integer"),
|
||||
UInt16 UMETA(DisplayName = "Unsigned 16-bit integer"),
|
||||
Int32 UMETA(DisplayName = "Signed 32-bit integer"),
|
||||
UInt32 UMETA(DisplayName = "Unsigned 32-bit integer"),
|
||||
Float32 UMETA(DisplayName = "Floating point 32-bit")
|
||||
};
|
||||
|
||||
/**
|
||||
* An alternative to FBulkDataBuffer with consistent data types
|
||||
*/
|
||||
template <typename DataType>
|
||||
class FRuntimeBulkDataBuffer
|
||||
{
|
||||
public:
|
||||
#if UE_VERSION_OLDER_THAN(4, 27, 0)
|
||||
using ViewType = TArrayView<DataType>;
|
||||
#else
|
||||
using ViewType = TArrayView64<DataType>;
|
||||
#endif
|
||||
|
||||
FRuntimeBulkDataBuffer() = default;
|
||||
|
||||
FRuntimeBulkDataBuffer(const FRuntimeBulkDataBuffer& Other)
|
||||
{
|
||||
*this = Other;
|
||||
}
|
||||
|
||||
FRuntimeBulkDataBuffer(FRuntimeBulkDataBuffer&& Other) noexcept
|
||||
{
|
||||
View = MoveTemp(Other.View);
|
||||
Other.View = ViewType();
|
||||
}
|
||||
|
||||
FRuntimeBulkDataBuffer(DataType* InBuffer, int64 InNumberOfElements)
|
||||
: View(InBuffer, InNumberOfElements)
|
||||
{
|
||||
#if UE_VERSION_OLDER_THAN(4, 27, 0)
|
||||
check(InNumberOfElements <= TNumericLimits<int32>::Max())
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
explicit FRuntimeBulkDataBuffer(const TArray<DataType, Allocator>& Other)
|
||||
{
|
||||
const int64 BulkDataSize = Other.Num();
|
||||
|
||||
DataType* BulkData = static_cast<DataType*>(FMemory::Malloc(BulkDataSize * sizeof(DataType)));
|
||||
if (!BulkData)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FMemory::Memcpy(BulkData, Other.GetData(), BulkDataSize * sizeof(DataType));
|
||||
View = ViewType(BulkData, BulkDataSize);
|
||||
}
|
||||
|
||||
~FRuntimeBulkDataBuffer()
|
||||
{
|
||||
FreeBuffer();
|
||||
}
|
||||
|
||||
FRuntimeBulkDataBuffer& operator=(const FRuntimeBulkDataBuffer& Other)
|
||||
{
|
||||
FreeBuffer();
|
||||
|
||||
if (this != &Other)
|
||||
{
|
||||
const int64 BufferSize = Other.View.Num();
|
||||
|
||||
DataType* BufferCopy = static_cast<DataType*>(FMemory::Malloc(BufferSize * sizeof(DataType)));
|
||||
FMemory::Memcpy(BufferCopy, Other.View.GetData(), BufferSize * sizeof(DataType));
|
||||
|
||||
View = ViewType(BufferCopy, BufferSize);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
FRuntimeBulkDataBuffer& operator=(FRuntimeBulkDataBuffer&& Other) noexcept
|
||||
{
|
||||
if (this != &Other)
|
||||
{
|
||||
FreeBuffer();
|
||||
|
||||
View = Other.View;
|
||||
Other.View = ViewType();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Empty()
|
||||
{
|
||||
FreeBuffer();
|
||||
View = ViewType();
|
||||
}
|
||||
|
||||
void Reset(DataType* InBuffer, int64 InNumberOfElements)
|
||||
{
|
||||
FreeBuffer();
|
||||
|
||||
#if UE_VERSION_OLDER_THAN(4, 27, 0)
|
||||
check(InNumberOfElements <= TNumericLimits<int32>::Max())
|
||||
#endif
|
||||
|
||||
View = ViewType(InBuffer, InNumberOfElements);
|
||||
}
|
||||
|
||||
const ViewType& GetView() const
|
||||
{
|
||||
return View;
|
||||
}
|
||||
|
||||
private:
|
||||
void FreeBuffer()
|
||||
{
|
||||
if (View.GetData() != nullptr)
|
||||
{
|
||||
FMemory::Free(View.GetData());
|
||||
View = ViewType();
|
||||
}
|
||||
}
|
||||
|
||||
ViewType View;
|
||||
};
|
||||
|
||||
/** Basic sound wave data */
|
||||
struct FSoundWaveBasicStruct
|
||||
{
|
||||
FSoundWaveBasicStruct()
|
||||
: NumOfChannels(0)
|
||||
, SampleRate(0)
|
||||
, Duration(0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Number of channels */
|
||||
uint32 NumOfChannels;
|
||||
|
||||
/** Sample rate (samples per second, sampling frequency) */
|
||||
uint32 SampleRate;
|
||||
|
||||
/** Sound wave duration, sec */
|
||||
float Duration;
|
||||
|
||||
/**
|
||||
* Whether the sound wave data appear to be valid or not
|
||||
*/
|
||||
bool IsValid() const
|
||||
{
|
||||
return NumOfChannels > 0 && Duration > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the basic sound wave struct to a readable format
|
||||
*
|
||||
* @return String representation of the basic sound wave struct
|
||||
*/
|
||||
FString ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("Number of channels: %d, sample rate: %d, duration: %f"), NumOfChannels, SampleRate, Duration);
|
||||
}
|
||||
};
|
||||
|
||||
/** PCM data buffer structure */
|
||||
struct FPCMStruct
|
||||
{
|
||||
FPCMStruct()
|
||||
: PCMNumOfFrames(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the PCM data appear to be valid or not
|
||||
*/
|
||||
bool IsValid() const
|
||||
{
|
||||
return PCMData.GetView().GetData() && PCMNumOfFrames > 0 && PCMData.GetView().Num() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts PCM struct to a readable format
|
||||
*
|
||||
* @return String representation of the PCM Struct
|
||||
*/
|
||||
FString ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("Validity of PCM data in memory: %s, number of PCM frames: %d, PCM data size: %lld"),
|
||||
PCMData.GetView().IsValidIndex(0) ? TEXT("Valid") : TEXT("Invalid"), PCMNumOfFrames, static_cast<int64>(PCMData.GetView().Num()));
|
||||
}
|
||||
|
||||
/** 32-bit float PCM data */
|
||||
FRuntimeBulkDataBuffer<float> PCMData;
|
||||
|
||||
/** Number of PCM frames */
|
||||
uint32 PCMNumOfFrames;
|
||||
};
|
||||
|
||||
/** Decoded audio information */
|
||||
struct FDecodedAudioStruct
|
||||
{
|
||||
/**
|
||||
* Whether the decoded audio data appear to be valid or not
|
||||
*/
|
||||
bool IsValid() const
|
||||
{
|
||||
return SoundWaveBasicInfo.IsValid() && PCMInfo.IsValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Decoded Audio Struct to a readable format
|
||||
*
|
||||
* @return String representation of the Decoded Audio Struct
|
||||
*/
|
||||
FString ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("SoundWave Basic Info:\n%s\n\nPCM Info:\n%s"), *SoundWaveBasicInfo.ToString(), *PCMInfo.ToString());
|
||||
}
|
||||
|
||||
/** SoundWave basic info (e.g. duration, number of channels, etc) */
|
||||
FSoundWaveBasicStruct SoundWaveBasicInfo;
|
||||
|
||||
/** PCM data buffer */
|
||||
FPCMStruct PCMInfo;
|
||||
};
|
||||
|
||||
/** Encoded audio information */
|
||||
struct FEncodedAudioStruct
|
||||
{
|
||||
FEncodedAudioStruct()
|
||||
: AudioFormat(ERuntimeAudioFormat::Invalid)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
FEncodedAudioStruct(const TArray<uint8, Allocator>& AudioDataArray, ERuntimeAudioFormat AudioFormat)
|
||||
: AudioData(AudioDataArray)
|
||||
, AudioFormat(AudioFormat)
|
||||
{
|
||||
}
|
||||
|
||||
FEncodedAudioStruct(FRuntimeBulkDataBuffer<uint8> AudioDataBulk, ERuntimeAudioFormat AudioFormat)
|
||||
: AudioData(MoveTemp(AudioDataBulk))
|
||||
, AudioFormat(AudioFormat)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Encoded Audio Struct to a readable format
|
||||
*
|
||||
* @return String representation of the Encoded Audio Struct
|
||||
*/
|
||||
FString ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("Validity of audio data in memory: %s, audio data size: %lld, audio format: %s"),
|
||||
AudioData.GetView().IsValidIndex(0) ? TEXT("Valid") : TEXT("Invalid"), static_cast<int64>(AudioData.GetView().Num()),
|
||||
*UEnum::GetValueAsName(AudioFormat).ToString());
|
||||
}
|
||||
|
||||
/** Audio data */
|
||||
FRuntimeBulkDataBuffer<uint8> AudioData;
|
||||
|
||||
/** Format of the audio data (e.g. mp3, flac, etc) */
|
||||
ERuntimeAudioFormat AudioFormat;
|
||||
};
|
||||
|
||||
/** Compressed sound wave information */
|
||||
USTRUCT(BlueprintType, Category = "Runtime Audio Importer")
|
||||
struct FCompressedSoundWaveInfo
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FCompressedSoundWaveInfo()
|
||||
: SoundGroup(ESoundGroup::SOUNDGROUP_Default)
|
||||
, bLooping(false)
|
||||
, Volume(1.f)
|
||||
, Pitch(1.f)
|
||||
{
|
||||
}
|
||||
|
||||
/** Sound group */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
TEnumAsByte<ESoundGroup> SoundGroup;
|
||||
|
||||
/** If set, when played directly (not through a sound cue) the wave will be played looping */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
bool bLooping;
|
||||
|
||||
/** Playback volume of sound 0 to 1 - Default is 1.0 */
|
||||
UPROPERTY(BlueprintReadWrite, meta = (ClampMin = "0.0"), Category = "Runtime Audio Importer")
|
||||
float Volume;
|
||||
|
||||
/** Playback pitch for sound. */
|
||||
UPROPERTY(BlueprintReadWrite, meta = (ClampMin = "0.125", ClampMax = "4.0"), Category = "Runtime Audio Importer")
|
||||
float Pitch;
|
||||
};
|
||||
|
||||
/** A line of subtitle text and the time at which it should be displayed. This is the same as FSubtitleCue but editable in Blueprints */
|
||||
USTRUCT(BlueprintType, Category = "Runtime Audio Importer")
|
||||
struct FEditableSubtitleCue
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FEditableSubtitleCue()
|
||||
: Time(0)
|
||||
{
|
||||
}
|
||||
|
||||
/** The text to appear in the subtitle */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
FText Text;
|
||||
|
||||
/** The time at which the subtitle is to be displayed, in seconds relative to the beginning of the line */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
float Time;
|
||||
};
|
||||
|
||||
/** Platform audio input device info */
|
||||
USTRUCT(BlueprintType, Category = "Runtime Audio Importer")
|
||||
struct FRuntimeAudioInputDeviceInfo
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FRuntimeAudioInputDeviceInfo()
|
||||
: DeviceName("")
|
||||
, DeviceId("")
|
||||
, InputChannels(0)
|
||||
, PreferredSampleRate(0)
|
||||
, bSupportsHardwareAEC(true)
|
||||
{
|
||||
}
|
||||
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
FRuntimeAudioInputDeviceInfo(const Audio::FCaptureDeviceInfo& DeviceInfo)
|
||||
: DeviceName(DeviceInfo.DeviceName)
|
||||
#if UE_VERSION_NEWER_THAN(4, 25, 0)
|
||||
, DeviceId(DeviceInfo.DeviceId)
|
||||
#endif
|
||||
, InputChannels(DeviceInfo.InputChannels)
|
||||
, PreferredSampleRate(DeviceInfo.PreferredSampleRate)
|
||||
, bSupportsHardwareAEC(DeviceInfo.bSupportsHardwareAEC)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/** The name of the audio device */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
FString DeviceName;
|
||||
|
||||
/** ID of the device */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
FString DeviceId;
|
||||
|
||||
/** The number of channels supported by the audio device */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
int32 InputChannels;
|
||||
|
||||
/** The preferred sample rate of the audio device */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
int32 PreferredSampleRate;
|
||||
|
||||
/** Whether or not the device supports Acoustic Echo Canceling */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
bool bSupportsHardwareAEC;
|
||||
};
|
||||
|
||||
/** Audio header information */
|
||||
USTRUCT(BlueprintType, Category = "Runtime Audio Importer")
|
||||
struct FRuntimeAudioHeaderInfo
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FRuntimeAudioHeaderInfo()
|
||||
: Duration(0.f)
|
||||
, NumOfChannels(0)
|
||||
, SampleRate(0)
|
||||
, PCMDataSize(0)
|
||||
, AudioFormat(ERuntimeAudioFormat::Invalid)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Audio Header Info to a readable format
|
||||
*
|
||||
* @return String representation of the Encoded Audio Struct
|
||||
*/
|
||||
FString ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("Duration: %f, number of channels: %d, sample rate: %d, PCM data size: %lld, audio format: %s"),
|
||||
Duration, NumOfChannels, SampleRate, PCMDataSize, *UEnum::GetValueAsName(AudioFormat).ToString());
|
||||
}
|
||||
|
||||
/** Audio duration, sec */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Runtime Audio Importer")
|
||||
float Duration;
|
||||
|
||||
/** Number of channels */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Runtime Audio Importer")
|
||||
int32 NumOfChannels;
|
||||
|
||||
/** Sample rate (samples per second, sampling frequency) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Runtime Audio Importer")
|
||||
int32 SampleRate;
|
||||
|
||||
/** PCM data size in 32-bit float format */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "PCM Data Size", Category = "Runtime Audio Importer")
|
||||
int64 PCMDataSize;
|
||||
|
||||
/** Format of the source audio data (e.g. mp3, flac, etc) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Runtime Audio Importer")
|
||||
ERuntimeAudioFormat AudioFormat;
|
||||
};
|
||||
|
||||
/** Audio export override options */
|
||||
USTRUCT(BlueprintType, Category = "Runtime Audio Importer")
|
||||
struct FRuntimeAudioExportOverrideOptions
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FRuntimeAudioExportOverrideOptions()
|
||||
: NumOfChannels(-1)
|
||||
, SampleRate(-1)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsOverriden() const
|
||||
{
|
||||
return IsNumOfChannelsOverriden() || IsSampleRateOverriden();
|
||||
}
|
||||
|
||||
bool IsSampleRateOverriden() const
|
||||
{
|
||||
return SampleRate != -1;
|
||||
}
|
||||
|
||||
bool IsNumOfChannelsOverriden() const
|
||||
{
|
||||
return NumOfChannels != -1;
|
||||
}
|
||||
|
||||
/** Number of channels. Set to -1 to retrieve from source. Mixing if count differs from source */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
int32 NumOfChannels;
|
||||
|
||||
/** Audio sampling rate (samples per second, sampling frequency). Set to -1 to retrieve from source. Resampling if count differs from source */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Runtime Audio Importer")
|
||||
int32 SampleRate;
|
||||
};
|
@ -1,90 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
#include "AudioCaptureCore.h"
|
||||
#endif
|
||||
#include "StreamingSoundWave.h"
|
||||
#include "CapturableSoundWave.generated.h"
|
||||
|
||||
/** Static delegate broadcasting available audio input devices */
|
||||
DECLARE_DELEGATE_OneParam(FOnGetAvailableAudioInputDevicesResultNative, const TArray<FRuntimeAudioInputDeviceInfo>&);
|
||||
|
||||
/** Dynamic delegate broadcasting available audio input devices */
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnGetAvailableAudioInputDevicesResult, const TArray<FRuntimeAudioInputDeviceInfo>&, AvailableDevices);
|
||||
|
||||
/**
|
||||
* Sound wave that can capture audio data from input devices (eg. microphone)
|
||||
*/
|
||||
UCLASS(BlueprintType, Category = "Capturable Sound Wave")
|
||||
class RUNTIMEAUDIOIMPORTER_API UCapturableSoundWave : public UStreamingSoundWave
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UCapturableSoundWave(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
//~ Begin UImportedSoundWave Interface
|
||||
virtual void BeginDestroy() override;
|
||||
//~ End UImportedSoundWave Interface
|
||||
|
||||
/**
|
||||
* Create a new instance of the capturable sound wave
|
||||
*
|
||||
* @return Created capturable sound wave
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Capturable Sound Wave|Main")
|
||||
static UCapturableSoundWave* CreateCapturableSoundWave();
|
||||
|
||||
/**
|
||||
* Get information about all available audio input devices
|
||||
*
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Capturable Sound Wave|Info")
|
||||
static void GetAvailableAudioInputDevices(const FOnGetAvailableAudioInputDevicesResult& Result);
|
||||
|
||||
/**
|
||||
* Gets information about all audio output devices available in the system. Suitable for use in C++
|
||||
*
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
static void GetAvailableAudioInputDevices(const FOnGetAvailableAudioInputDevicesResultNative& Result);
|
||||
|
||||
/**
|
||||
* Start the capture process
|
||||
*
|
||||
* @param DeviceId Required device index (order as from GetAvailableAudioInputDevices)
|
||||
* @return Whether the capture was started or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Capturable Sound Wave|Capture")
|
||||
bool StartCapture(int32 DeviceId);
|
||||
|
||||
/**
|
||||
* Stop the capture process
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Capturable Sound Wave|Capture")
|
||||
void StopCapture();
|
||||
|
||||
/**
|
||||
* Toggles the mute state of audio capture, pausing the accumulation of audio data without closing the stream
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Capturable Sound Wave|Capture")
|
||||
bool ToggleMute(bool bMute);
|
||||
|
||||
/**
|
||||
* Get whether the capture is processing or not
|
||||
*
|
||||
* @return Whether the capture is processing or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Capturable Sound Wave|Info")
|
||||
bool IsCapturing() const;
|
||||
|
||||
private:
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT
|
||||
/** Audio capture instance */
|
||||
Audio::FAudioCapture AudioCapture;
|
||||
#endif
|
||||
};
|
@ -1,378 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
#include "Sound/SoundWaveProcedural.h"
|
||||
#include "ImportedSoundWave.generated.h"
|
||||
|
||||
/** Static delegate broadcast to track the end of audio playback */
|
||||
DECLARE_MULTICAST_DELEGATE(FOnAudioPlaybackFinishedNative);
|
||||
|
||||
/** Dynamic delegate broadcast to track the end of audio playback */
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnAudioPlaybackFinished);
|
||||
|
||||
|
||||
/** Static delegate broadcast PCM data during a generation request */
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FOnGeneratePCMDataNative, const TArray<float>&);
|
||||
|
||||
/** Dynamic delegate broadcast PCM data during a generation request */
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGeneratePCMData, const TArray<float>&, PCMData);
|
||||
|
||||
|
||||
/** Static delegate broadcasting the result of preparing a sound wave for MetaSounds */
|
||||
DECLARE_DELEGATE_OneParam(FOnPrepareSoundWaveForMetaSoundsResultNative, bool);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of preparing a sound wave for MetaSounds */
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnPrepareSoundWaveForMetaSoundsResult, bool, bSucceeded);
|
||||
|
||||
|
||||
/** Static delegate broadcasting the result of releasing the played audio data */
|
||||
DECLARE_DELEGATE_OneParam(FOnPlayedAudioDataReleaseResultNative, bool);
|
||||
|
||||
/** Dynamic delegate broadcasting the result of releasing the played audio data */
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnPlayedAudioDataReleaseResult, bool, bSucceeded);
|
||||
|
||||
|
||||
/** Static delegate broadcast newly populated PCM data */
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FOnPopulateAudioDataNative, const TArray<float>&);
|
||||
|
||||
/** Dynamic delegate broadcast newly populated PCM data */
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPopulateAudioData, const TArray<float>&, PopulatedAudioData);
|
||||
|
||||
|
||||
/**
|
||||
* Imported sound wave. Assumed to be dynamically populated once from the decoded audio data.
|
||||
* Audio data preparation takes place in the Runtime Audio Importer library
|
||||
*/
|
||||
UCLASS(BlueprintType, Category = "Imported Sound Wave")
|
||||
class RUNTIMEAUDIOIMPORTER_API UImportedSoundWave : public USoundWaveProcedural
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UImportedSoundWave(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
/**
|
||||
* Create a new instance of the imported sound wave
|
||||
*
|
||||
* @return Created imported sound wave
|
||||
*/
|
||||
static UImportedSoundWave* CreateImportedSoundWave();
|
||||
|
||||
//~ Begin USoundWave Interface
|
||||
virtual void BeginDestroy() override;
|
||||
virtual void Parse(class FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances) override;
|
||||
virtual Audio::EAudioMixerStreamDataFormat::Type GetGeneratedPCMDataFormat() const override;
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
virtual TSharedPtr<Audio::IProxyData> CreateProxyData(const Audio::FProxyDataInitParams& InitParams) override;
|
||||
virtual bool InitAudioResource(FName Format) override;
|
||||
virtual bool IsSeekable() const override;
|
||||
#endif
|
||||
//~ End USoundWave Interface
|
||||
|
||||
//~ Begin USoundWaveProcedural Interface
|
||||
virtual int32 OnGeneratePCMAudio(TArray<uint8>& OutAudio, int32 NumSamples) override;
|
||||
//~ End USoundWaveProcedural Interface
|
||||
|
||||
/**
|
||||
* Populate audio data from decoded info
|
||||
*
|
||||
* @param DecodedAudioInfo Decoded audio data
|
||||
*/
|
||||
virtual void PopulateAudioDataFromDecodedInfo(FDecodedAudioStruct&& DecodedAudioInfo);
|
||||
|
||||
/**
|
||||
* Prepare this sound wave to be able to set wave parameter for MetaSounds
|
||||
*
|
||||
* @param Result Delegate broadcasting the result. Set the wave parameter only after it has been broadcast
|
||||
* @warning This works if bEnableMetaSoundSupport is enabled in RuntimeAudioImporter.Build.cs/RuntimeAudioImporterEditor.Build.cs and only on Unreal Engine version >= 5.2
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|MetaSounds")
|
||||
void PrepareSoundWaveForMetaSounds(const FOnPrepareSoundWaveForMetaSoundsResult& Result);
|
||||
|
||||
/**
|
||||
* Prepare this sound wave to be able to set wave parameter for MetaSounds. Suitable for use in C++
|
||||
*
|
||||
* @param Result Delegate broadcasting the result. Set the wave parameter only after it has been broadcast
|
||||
* @warning This works if bEnableMetaSoundSupport is enabled in RuntimeAudioImporter.Build.cs/RuntimeAudioImporterEditor.Build.cs and only on Unreal Engine version >= 5.2
|
||||
*/
|
||||
void PrepareSoundWaveForMetaSounds(const FOnPrepareSoundWaveForMetaSoundsResultNative& Result);
|
||||
|
||||
/**
|
||||
* Release sound wave data. Call it manually only if you are sure of it
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Miscellaneous")
|
||||
virtual void ReleaseMemory();
|
||||
|
||||
/**
|
||||
* Remove previously played audio data. Adds a duration offset from the removed audio data
|
||||
* This re-allocates all audio data memory, so should not be called too frequently
|
||||
*
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Miscellaneous")
|
||||
void ReleasePlayedAudioData(const FOnPlayedAudioDataReleaseResult& Result);
|
||||
|
||||
/**
|
||||
* Remove previously played audio data. Adds a duration offset from the removed audio data
|
||||
* This re-allocates all audio data memory, so should not be called too frequently
|
||||
* Suitable for use in C++
|
||||
*
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
virtual void ReleasePlayedAudioData(const FOnPlayedAudioDataReleaseResultNative& Result);
|
||||
|
||||
/**
|
||||
* Set whether the sound should loop or not
|
||||
*
|
||||
* @param bLoop Whether the sound should loop or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Properties")
|
||||
void SetLooping(bool bLoop);
|
||||
|
||||
/**
|
||||
* Set subtitle cues
|
||||
*
|
||||
* @param InSubtitles Subtitles cues
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Properties")
|
||||
void SetSubtitles(UPARAM(DisplayName = "Subtitles") const TArray<FEditableSubtitleCue>& InSubtitles);
|
||||
|
||||
/**
|
||||
* Set sound playback volume
|
||||
*
|
||||
* @param InVolume Volume
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Properties")
|
||||
void SetVolume(UPARAM(DisplayName = "Volume") float InVolume = 1);
|
||||
|
||||
/**
|
||||
* Set sound playback pitch
|
||||
*
|
||||
* @param InPitch Pitch
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Properties")
|
||||
void SetPitch(UPARAM(DisplayName = "Pitch") float InPitch = 1);
|
||||
|
||||
/**
|
||||
* Rewind the sound for the specified time
|
||||
*
|
||||
* @note This adds a duration offset (relevant if ReleasePlayedAudioData was used)
|
||||
* @param PlaybackTime How long to rewind the sound
|
||||
* @return Whether the sound was rewound or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Main")
|
||||
bool RewindPlaybackTime(float PlaybackTime);
|
||||
|
||||
/**
|
||||
* Thread-unsafe equivalent of RewindPlaybackTime
|
||||
* Should only be used if DataGuard is locked
|
||||
* @note This does not add a duration offset
|
||||
*/
|
||||
bool RewindPlaybackTime_Internal(float PlaybackTime);
|
||||
|
||||
// TODO: Make this async
|
||||
/**
|
||||
* Resample the sound wave to the specified sample rate
|
||||
*
|
||||
* @note This is not thread-safe at the moment
|
||||
* @param NewSampleRate The new sample rate
|
||||
* @return Whether the sound wave was resampled or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Main")
|
||||
bool ResampleSoundWave(int32 NewSampleRate);
|
||||
|
||||
// TODO: Make this async
|
||||
/**
|
||||
* Change the number of channels of the sound wave
|
||||
*
|
||||
* @note This is not thread-safe at the moment
|
||||
* @param NewNumOfChannels The new number of channels
|
||||
* @return Whether the sound wave was mixed or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Main")
|
||||
bool MixSoundWaveChannels(int32 NewNumOfChannels);
|
||||
|
||||
/**
|
||||
* Change the number of frames played back. Used to rewind the sound
|
||||
*
|
||||
* @param NumOfFrames The new number of frames from which to continue playing sound
|
||||
* @return Whether the frames were changed or not
|
||||
*/
|
||||
bool SetNumOfPlayedFrames(uint32 NumOfFrames);
|
||||
|
||||
/**
|
||||
* Thread-unsafe equivalent of SetNumOfPlayedFrames
|
||||
* Should only be used if DataGuard is locked
|
||||
*/
|
||||
bool SetNumOfPlayedFrames_Internal(uint32 NumOfFrames);
|
||||
|
||||
/**
|
||||
* Get the number of frames played back
|
||||
*
|
||||
* @return The number of frames played back
|
||||
*/
|
||||
uint32 GetNumOfPlayedFrames() const;
|
||||
|
||||
/**
|
||||
* Thread-unsafe equivalent of GetNumOfPlayedFrames
|
||||
* Should only be used if DataGuard is locked
|
||||
*/
|
||||
uint32 GetNumOfPlayedFrames_Internal() const;
|
||||
|
||||
/**
|
||||
* Get the current sound wave playback time, in seconds
|
||||
* @note This adds a duration offset (relevant if ReleasePlayedAudioData was used)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
float GetPlaybackTime() const;
|
||||
|
||||
/**
|
||||
* Thread-unsafe equivalent of GetPlaybackTime
|
||||
* Should only be used if DataGuard is locked
|
||||
* @note This does not add a duration offset
|
||||
*/
|
||||
float GetPlaybackTime_Internal() const;
|
||||
|
||||
/**
|
||||
* Constant alternative for getting the length of the sound wave, in seconds
|
||||
* @note This adds a duration offset (relevant if ReleasePlayedAudioData was used)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info", meta = (DisplayName = "Get Duration"))
|
||||
float GetDurationConst() const;
|
||||
|
||||
/**
|
||||
* Thread-unsafe equivalent of GetDurationConst
|
||||
* Should only be used if DataGuard is locked
|
||||
* @note This does not add a duration offset
|
||||
*/
|
||||
float GetDurationConst_Internal() const;
|
||||
|
||||
/**
|
||||
* Get the length of the sound wave, in seconds
|
||||
* @note This adds a duration offset (relevant if ReleasePlayedAudioData was used)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
virtual float GetDuration()
|
||||
#if UE_VERSION_OLDER_THAN(5, 0, 0)
|
||||
override;
|
||||
#else
|
||||
const override;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get sample rate
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
int32 GetSampleRate() const;
|
||||
|
||||
/**
|
||||
* Get number of channels
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
int32 GetNumOfChannels() const;
|
||||
|
||||
/**
|
||||
* Get the current sound playback percentage, 0-100%
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
float GetPlaybackPercentage() const;
|
||||
|
||||
/**
|
||||
* Check if audio playback has finished or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
bool IsPlaybackFinished() const;
|
||||
|
||||
/**
|
||||
* Get the duration offset if some played back audio data was removed during playback (eg in ReleasePlayedAudioData)
|
||||
* The sound wave starts playing from this time as from the very beginning
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
float GetDurationOffset() const;
|
||||
|
||||
/**
|
||||
* Thread-unsafe equivalent of GetDurationOffset
|
||||
* Should only be used if DataGuard is locked
|
||||
*/
|
||||
float GetDurationOffset_Internal() const;
|
||||
|
||||
/**
|
||||
* Thread-unsafe equivalent of IsPlaybackFinished
|
||||
* Should only be used if DataGuard is locked
|
||||
*/
|
||||
bool IsPlaybackFinished_Internal() const;
|
||||
|
||||
/**
|
||||
* Retrieve audio header (metadata) information. Needed primarily for consistency with the RuntimeAudioImporterLibrary
|
||||
*
|
||||
* @param HeaderInfo Header info, valid only if the return is true
|
||||
* @return Whether the retrieval was successful or not
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info")
|
||||
bool GetAudioHeaderInfo(FRuntimeAudioHeaderInfo& HeaderInfo) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Makes it possible to broadcast OnAudioPlaybackFinished again
|
||||
*/
|
||||
void ResetPlaybackFinish();
|
||||
|
||||
public:
|
||||
/** Bind to this delegate to know when the audio playback is finished. Suitable for use in C++ */
|
||||
FOnAudioPlaybackFinishedNative OnAudioPlaybackFinishedNative;
|
||||
|
||||
/** Bind to this delegate to know when the audio playback is finished */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Imported Sound Wave|Delegates")
|
||||
FOnAudioPlaybackFinished OnAudioPlaybackFinished;
|
||||
|
||||
/** Bind to this delegate to receive PCM data during playback (may be useful for analyzing audio data). Suitable for use in C++ */
|
||||
FOnGeneratePCMDataNative OnGeneratePCMDataNative;
|
||||
|
||||
/** Bind to this delegate to receive PCM data during playback (may be useful for analyzing audio data) */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Imported Sound Wave|Delegates")
|
||||
FOnGeneratePCMData OnGeneratePCMData;
|
||||
|
||||
/** Bind to this delegate to obtain audio data every time it is populated. Suitable for use in C++ */
|
||||
FOnPopulateAudioDataNative OnPopulateAudioDataNative;
|
||||
|
||||
/** Bind to this delegate to obtain audio data every time it is populated */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Imported Sound Wave|Delegates")
|
||||
FOnPopulateAudioData OnPopulateAudioData;
|
||||
|
||||
/**
|
||||
* Retrieve the PCM buffer, completely thread-safe. Suitable for use in Blueprints
|
||||
*
|
||||
* @return PCM buffer in 32-bit float format
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Sound Wave|Info", meta = (DisplayName = "Get PCM Buffer"))
|
||||
TArray<float> GetPCMBufferCopy();
|
||||
|
||||
/**
|
||||
* Get immutable PCM buffer. Use DataGuard to make it thread safe
|
||||
* Use PopulateAudioDataFromDecodedInfo to populate it
|
||||
*
|
||||
* @return PCM buffer in 32-bit float format
|
||||
*/
|
||||
const FPCMStruct& GetPCMBuffer() const;
|
||||
|
||||
/** Data guard (mutex) for thread safety */
|
||||
mutable FCriticalSection DataGuard;
|
||||
|
||||
protected:
|
||||
/** Duration offset, needed to track the clearing of part of the audio data of the sound wave during playback (see ReleasePlayedAudioData) */
|
||||
float DurationOffset;
|
||||
|
||||
/** Bool to control the behaviour of the OnAudioPlaybackFinished delegate */
|
||||
bool PlaybackFinishedBroadcast;
|
||||
|
||||
/** The number of frames played. Increments during playback, should not be > PCMBufferInfo.PCMNumOfFrames */
|
||||
uint32 PlayedNumOfFrames;
|
||||
|
||||
/** Contains PCM data for sound wave playback */
|
||||
TUniquePtr<FPCMStruct> PCMBufferInfo;
|
||||
|
||||
/** Whether to stop the sound at the end of playback or not. Sound wave will not be garbage collected if playback was completed while this parameter is set to false */
|
||||
bool bStopSoundOnPlaybackFinish;
|
||||
};
|
@ -1,92 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "ImportedSoundWave.h"
|
||||
#include "StreamingSoundWave.generated.h"
|
||||
|
||||
/** Static delegate broadcast the result of audio data pre-allocation */
|
||||
DECLARE_DELEGATE_OneParam(FOnPreAllocateAudioDataResultNative, bool);
|
||||
|
||||
/** Dynamic delegate broadcast the result of audio data pre-allocation */
|
||||
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnPreAllocateAudioDataResult, bool, bSucceeded);
|
||||
|
||||
/**
|
||||
* Streaming sound wave. Can append audio data dynamically, including during playback
|
||||
* It will live indefinitely, even if the sound wave has finished playing, until SetStopSoundOnPlaybackFinish is called.
|
||||
* Audio data is always accumulated, clear memory manually via ReleaseMemory or ReleasePlayedAudioData if necessary.
|
||||
*/
|
||||
UCLASS(BlueprintType, Category = "Streaming Sound Wave")
|
||||
class RUNTIMEAUDIOIMPORTER_API UStreamingSoundWave : public UImportedSoundWave
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UStreamingSoundWave(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
/**
|
||||
* Create a new instance of the streaming sound wave
|
||||
*
|
||||
* @return Created streaming sound wave
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Streaming Sound Wave|Main")
|
||||
static UStreamingSoundWave* CreateStreamingSoundWave();
|
||||
|
||||
/**
|
||||
* Pre-allocate PCM data, to avoid reallocating memory each time audio data is appended
|
||||
*
|
||||
* @param NumOfBytesToPreAllocate Number of bytes to pre-allocate
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Streaming Sound Wave|Allocation")
|
||||
void PreAllocateAudioData(int64 NumOfBytesToPreAllocate, const FOnPreAllocateAudioDataResult& Result);
|
||||
|
||||
/**
|
||||
* Pre-allocate PCM data, to avoid reallocating memory each time audio data is appended. Suitable for use in C++
|
||||
*
|
||||
* @param NumOfBytesToPreAllocate Number of bytes to pre-allocate
|
||||
* @param Result Delegate broadcasting the result
|
||||
*/
|
||||
void PreAllocateAudioData(int64 NumOfBytesToPreAllocate, const FOnPreAllocateAudioDataResultNative& Result);
|
||||
|
||||
/**
|
||||
* Append audio data to the end of existing data from encoded audio data
|
||||
*
|
||||
* @param AudioData Audio data array
|
||||
* @param AudioFormat Audio format
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Streaming Sound Wave|Append")
|
||||
void AppendAudioDataFromEncoded(TArray<uint8> AudioData, ERuntimeAudioFormat AudioFormat);
|
||||
|
||||
/**
|
||||
* Append audio data to the end of existing data from RAW audio data
|
||||
*
|
||||
* @param RAWData RAW audio buffer
|
||||
* @param RAWFormat RAW audio format
|
||||
* @param InSampleRate The number of samples per second
|
||||
* @param NumOfChannels The number of channels (1 for mono, 2 for stereo, etc)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Append Audio Data From RAW"), Category = "Streaming Sound Wave|Append")
|
||||
void AppendAudioDataFromRAW(UPARAM(DisplayName = "RAW Data") TArray<uint8> RAWData, UPARAM(DisplayName = "RAW Format") ERuntimeRAWAudioFormat RAWFormat, UPARAM(DisplayName = "Sample Rate") int32 InSampleRate = 44100, int32 NumOfChannels = 1);
|
||||
|
||||
/**
|
||||
* Set whether the sound should stop after playback is complete or not (play "blank sound"). False by default
|
||||
* Setting it to True also makes the sound wave eligible for garbage collection after it has finished playing
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Imported Streaming Sound Wave|Import")
|
||||
void SetStopSoundOnPlaybackFinish(bool bStop);
|
||||
|
||||
//~ Begin UImportedSoundWave Interface
|
||||
virtual void PopulateAudioDataFromDecodedInfo(FDecodedAudioStruct&& DecodedAudioInfo) override;
|
||||
virtual void ReleaseMemory() override;
|
||||
virtual void ReleasePlayedAudioData(const FOnPlayedAudioDataReleaseResultNative& Result) override;
|
||||
//~ End UImportedSoundWave Interface
|
||||
|
||||
private:
|
||||
/** Whether the initial audio data is filled in or not */
|
||||
bool bFilledInitialAudioData;
|
||||
|
||||
/** Number of pre-allocated byte data for PCM */
|
||||
int64 NumOfPreAllocatedByteData;
|
||||
};
|
@ -1,144 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
using UnrealBuildTool;
|
||||
using System.IO;
|
||||
|
||||
public class RuntimeAudioImporter : ModuleRules
|
||||
{
|
||||
public RuntimeAudioImporter(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
// Change to toggle MetaSounds support
|
||||
bool bEnableMetaSoundSupport = false;
|
||||
|
||||
// MetaSound is only supported in Unreal Engine version >= 5.3
|
||||
bEnableMetaSoundSupport &= (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion >= 3) || Target.Version.MajorVersion > 5;
|
||||
|
||||
// Disable if you are not using audio input capture
|
||||
bool bEnableCaptureInputSupport = true;
|
||||
|
||||
// Bink format is only supported in Unreal Engine version >= 5
|
||||
bool bEnableBinkSupport = Target.Version.MajorVersion >= 5;
|
||||
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
AddEngineThirdPartyPrivateStaticDependencies(Target,
|
||||
"UEOgg",
|
||||
"Vorbis"
|
||||
);
|
||||
|
||||
// This is necessary because the Vorbis module does not include the Unix-specific libvorbis encoder library
|
||||
if (Target.Platform != UnrealTargetPlatform.IOS && !Target.IsInPlatformGroup(UnrealPlatformGroup.Android) && Target.Platform != UnrealTargetPlatform.Mac && Target.IsInPlatformGroup(UnrealPlatformGroup.Unix))
|
||||
{
|
||||
string VorbisLibPath = Path.Combine(Target.UEThirdPartySourceDirectory, "Vorbis", "libvorbis-1.3.2", "lib");
|
||||
PublicAdditionalLibraries.Add(Path.Combine(VorbisLibPath, "Unix",
|
||||
#if UE_5_2_OR_LATER
|
||||
Target.Architecture.LinuxName,
|
||||
#else
|
||||
Target.Architecture,
|
||||
#endif
|
||||
"libvorbisenc.a"));
|
||||
}
|
||||
|
||||
PublicDefinitions.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"DR_WAV_IMPLEMENTATION=1",
|
||||
"DR_MP3_IMPLEMENTATION=1",
|
||||
"DR_FLAC_IMPLEMENTATION=1"
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Core",
|
||||
"AudioPlatformConfiguration"
|
||||
}
|
||||
);
|
||||
|
||||
if (Target.Version.MajorVersion >= 5 && Target.Version.MinorVersion >= 2)
|
||||
{
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"AudioExtensions"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (bEnableMetaSoundSupport)
|
||||
{
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"MetasoundEngine",
|
||||
"MetasoundFrontend",
|
||||
"MetasoundGraphCore"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
PublicDefinitions.Add(string.Format("WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT={0}", (bEnableMetaSoundSupport ? "1" : "0")));
|
||||
|
||||
if (bEnableCaptureInputSupport)
|
||||
{
|
||||
if (Target.Platform.IsInGroup(UnrealPlatformGroup.Windows) ||
|
||||
Target.Platform == UnrealTargetPlatform.Mac)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("AudioCaptureRtAudio");
|
||||
}
|
||||
else if (Target.Platform == UnrealTargetPlatform.IOS)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("AudioCaptureAudioUnit");
|
||||
}
|
||||
else if (Target.Platform == UnrealTargetPlatform.Android)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("AudioCaptureAndroid");
|
||||
}
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"AudioMixer",
|
||||
"AudioCaptureCore"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
PublicDefinitions.Add(string.Format("WITH_RUNTIMEAUDIOIMPORTER_CAPTURE_SUPPORT={0}", (bEnableCaptureInputSupport ? "1" : "0")));
|
||||
|
||||
if (bEnableBinkSupport)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("BinkAudioDecoder");
|
||||
|
||||
PublicSystemIncludePaths.Add(Path.Combine(EngineDirectory, "Source", "Runtime", "BinkAudioDecoder", "SDK", "BinkAudio", "Include"));
|
||||
|
||||
if (Target.Platform == UnrealTargetPlatform.Win64)
|
||||
{
|
||||
PublicAdditionalLibraries.Add(Path.Combine(EngineDirectory, "Source", "Runtime", "BinkAudioDecoder", "SDK", "BinkAudio", "Lib", "binka_ue_encode_win64_static.lib"));
|
||||
}
|
||||
|
||||
if (Target.Platform == UnrealTargetPlatform.Linux)
|
||||
{
|
||||
PublicAdditionalLibraries.Add(Path.Combine(EngineDirectory, "Source", "Runtime", "BinkAudioDecoder", "SDK", "BinkAudio", "Lib", "libbinka_ue_encode_lnx64_static.a"));
|
||||
}
|
||||
|
||||
if (Target.Platform == UnrealTargetPlatform.Mac)
|
||||
{
|
||||
if (Target.Version.MajorVersion >= 5 && Target.Version.MinorVersion >= 1)
|
||||
{
|
||||
PublicAdditionalLibraries.Add(Path.Combine(EngineDirectory, "Source", "Runtime", "BinkAudioDecoder", "SDK", "BinkAudio", "Lib", "libbinka_ue_encode_osx_static.a"));
|
||||
}
|
||||
else
|
||||
{
|
||||
PublicAdditionalLibraries.Add(Path.Combine(EngineDirectory, "Source", "Runtime", "BinkAudioDecoder", "SDK", "BinkAudio", "Lib", "libbinka_ue_encode_osx64_static.a"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PublicDefinitions.Add(string.Format("WITH_RUNTIMEAUDIOIMPORTER_BINK_DECODE_SUPPORT={0}", (bEnableBinkSupport ? "1" : "0")));
|
||||
PublicDefinitions.Add(string.Format("WITH_RUNTIMEAUDIOIMPORTER_BINK_ENCODE_SUPPORT={0}", (bEnableBinkSupport && (Target.Platform == UnrealTargetPlatform.Win64 || Target.Platform == UnrealTargetPlatform.Linux || Target.Platform == UnrealTargetPlatform.Mac) ? "1" : "0")));
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "PreImportedSoundFactory.h"
|
||||
#include "PreImportedSoundAsset.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "RuntimeAudioImporterLibrary.h"
|
||||
#include "Logging/MessageLog.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "PreImportedSoundFactory"
|
||||
DEFINE_LOG_CATEGORY(LogPreImportedSoundFactory);
|
||||
|
||||
UPreImportedSoundFactory::UPreImportedSoundFactory()
|
||||
{
|
||||
Formats.Add(TEXT("imp;Runtime Audio Importer any supported format (mp3, wav, flac and ogg)"));
|
||||
|
||||
// Removed for consistency with non-RuntimeAudioImporter modules
|
||||
/*
|
||||
Formats.Add(TEXT("mp3;MPEG-2 Audio"));
|
||||
Formats.Add(TEXT("wav;Wave Audio File"));
|
||||
Formats.Add(TEXT("flac;Free Lossless Audio Codec"));
|
||||
Formats.Add(TEXT("ogg;OGG Vorbis bitstream format"));
|
||||
*/
|
||||
|
||||
SupportedClass = StaticClass();
|
||||
bCreateNew = false; // turned off for import
|
||||
bEditAfterNew = false; // turned off for import
|
||||
bEditorImport = true;
|
||||
bText = false;
|
||||
}
|
||||
|
||||
bool UPreImportedSoundFactory::FactoryCanImport(const FString& Filename)
|
||||
{
|
||||
const FString FileExtension{FPaths::GetExtension(Filename).ToLower()};
|
||||
return FileExtension == TEXT("imp") || URuntimeAudioImporterLibrary::GetAudioFormat(Filename) != ERuntimeAudioFormat::Invalid;
|
||||
}
|
||||
|
||||
UObject* UPreImportedSoundFactory::FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Params, FFeedbackContext* Warn, bool& bOutOperationCanceled)
|
||||
{
|
||||
TArray<uint8> AudioData;
|
||||
|
||||
if (!FFileHelper::LoadFileToArray(AudioData, *Filename))
|
||||
{
|
||||
FMessageLog("Import").Error(FText::Format(LOCTEXT("PreImportedSoundFactory_ReadError", "Unable to read the audio file '{0}'. Check file permissions'"), FText::FromString(Filename)));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Removing unused two uninitialized bytes
|
||||
AudioData.RemoveAt(AudioData.Num() - 2, 2);
|
||||
|
||||
FDecodedAudioStruct DecodedAudioInfo;
|
||||
FEncodedAudioStruct EncodedAudioInfo = FEncodedAudioStruct(AudioData, ERuntimeAudioFormat::Auto);
|
||||
|
||||
if (!URuntimeAudioImporterLibrary::DecodeAudioData(MoveTemp(EncodedAudioInfo), DecodedAudioInfo))
|
||||
{
|
||||
FMessageLog("Import").Error(FText::Format(LOCTEXT("PreImportedSoundFactory_DecodeError", "Unable to decode the audio file '{0}'. Make sure the file is not corrupted'"), FText::FromString(Filename)));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UPreImportedSoundAsset* PreImportedSoundAsset = NewObject<UPreImportedSoundAsset>(InParent, UPreImportedSoundAsset::StaticClass(), InName, Flags);
|
||||
PreImportedSoundAsset->AudioDataArray = AudioData;
|
||||
PreImportedSoundAsset->AudioFormat = EncodedAudioInfo.AudioFormat;
|
||||
PreImportedSoundAsset->SourceFilePath = Filename;
|
||||
|
||||
PreImportedSoundAsset->SoundDuration = URuntimeAudioImporterLibrary::ConvertSecondsToString(DecodedAudioInfo.SoundWaveBasicInfo.Duration);
|
||||
PreImportedSoundAsset->NumberOfChannels = DecodedAudioInfo.SoundWaveBasicInfo.NumOfChannels;
|
||||
PreImportedSoundAsset->SampleRate = DecodedAudioInfo.SoundWaveBasicInfo.SampleRate;
|
||||
|
||||
bOutOperationCanceled = false;
|
||||
|
||||
UE_LOG(LogPreImportedSoundFactory, Log, TEXT("Successfully imported sound asset '%s'"), *Filename);
|
||||
|
||||
return PreImportedSoundAsset;
|
||||
}
|
||||
|
||||
bool UPreImportedSoundFactory::CanReimport(UObject* Obj, TArray<FString>& OutFilenames)
|
||||
{
|
||||
if (const UPreImportedSoundAsset* PreImportedSoundAsset = Cast<UPreImportedSoundAsset>(Obj))
|
||||
{
|
||||
OutFilenames.Add(PreImportedSoundAsset->SourceFilePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UPreImportedSoundFactory::SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths)
|
||||
{
|
||||
UPreImportedSoundAsset* PreImportedSoundAsset = Cast<UPreImportedSoundAsset>(Obj);
|
||||
|
||||
if (PreImportedSoundAsset && ensure(NewReimportPaths.Num() == 1))
|
||||
{
|
||||
PreImportedSoundAsset->SourceFilePath = NewReimportPaths[0];
|
||||
}
|
||||
}
|
||||
|
||||
EReimportResult::Type UPreImportedSoundFactory::Reimport(UObject* Obj)
|
||||
{
|
||||
const UPreImportedSoundAsset* PreImportedSoundAsset = Cast<UPreImportedSoundAsset>(Obj);
|
||||
|
||||
if (!PreImportedSoundAsset)
|
||||
{
|
||||
UE_LOG(LogPreImportedSoundFactory, Log, TEXT("The sound asset '%s' cannot be re-imported because the object is corrupted"), *PreImportedSoundAsset->SourceFilePath);
|
||||
return EReimportResult::Failed;
|
||||
}
|
||||
|
||||
if (PreImportedSoundAsset->SourceFilePath.IsEmpty() || !FPaths::FileExists(PreImportedSoundAsset->SourceFilePath))
|
||||
{
|
||||
UE_LOG(LogPreImportedSoundFactory, Log, TEXT("The sound asset '%s' cannot be re-imported because the path to the source file cannot be found"), *PreImportedSoundAsset->SourceFilePath);
|
||||
return EReimportResult::Failed;
|
||||
}
|
||||
|
||||
bool OutCanceled = false;
|
||||
if (ImportObject(Obj->GetClass(), Obj->GetOuter(), *Obj->GetName(), RF_Public | RF_Standalone, PreImportedSoundAsset->SourceFilePath, nullptr, OutCanceled))
|
||||
{
|
||||
UE_LOG(LogPreImportedSoundFactory, Log, TEXT("Successfully re-imported sound asset '%s'"), *PreImportedSoundAsset->SourceFilePath);
|
||||
return EReimportResult::Succeeded;
|
||||
}
|
||||
|
||||
return OutCanceled ? EReimportResult::Cancelled : EReimportResult::Failed;
|
||||
}
|
||||
|
||||
int32 UPreImportedSoundFactory::GetPriority() const
|
||||
{
|
||||
return ImportPriority;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
@ -1,28 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#include "RuntimeAudioImporterEditor.h"
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
#include "MetasoundDataReference.h"
|
||||
#include "MetasoundEditorModule.h"
|
||||
#endif
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FRuntimeAudioImporterEditorModule"
|
||||
|
||||
void FRuntimeAudioImporterEditorModule::StartupModule()
|
||||
{
|
||||
#if WITH_RUNTIMEAUDIOIMPORTER_METASOUND_SUPPORT
|
||||
using namespace Metasound;
|
||||
using namespace Metasound::Editor;
|
||||
IMetasoundEditorModule& MetaSoundEditorModule = FModuleManager::GetModuleChecked<IMetasoundEditorModule>("MetaSoundEditor");
|
||||
MetaSoundEditorModule.RegisterPinType("ImportedWave");
|
||||
MetaSoundEditorModule.RegisterPinType(CreateArrayTypeNameFromElementTypeName("ImportedWave"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void FRuntimeAudioImporterEditorModule::ShutdownModule()
|
||||
{
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FRuntimeAudioImporterEditorModule, RuntimeAudioImporterEditor)
|
@ -1,41 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EditorReimportHandler.h"
|
||||
|
||||
#include "Logging/LogCategory.h"
|
||||
#include "Logging/LogMacros.h"
|
||||
#include "Logging/LogVerbosity.h"
|
||||
|
||||
#include "Factories/Factory.h"
|
||||
#include "PreImportedSoundFactory.generated.h"
|
||||
|
||||
/** Declaring custom logging */
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogPreImportedSoundFactory, Log, All);
|
||||
|
||||
/**
|
||||
* Factory for pre-importing audio files. Supports all formats from EAudioFormat, but OGG Vorbis is recommended due to its smaller size and better quality
|
||||
*/
|
||||
UCLASS()
|
||||
class RUNTIMEAUDIOIMPORTEREDITOR_API UPreImportedSoundFactory : public UFactory, public FReimportHandler
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Default constructor */
|
||||
UPreImportedSoundFactory();
|
||||
|
||||
//~ Begin UFactory Interface.
|
||||
virtual bool FactoryCanImport(const FString& Filename) override;
|
||||
virtual UObject* FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Params, FFeedbackContext* Warn, bool& bOutOperationCanceled) override;
|
||||
//~ end UFactory Interface.
|
||||
|
||||
//~ Begin FReimportHandler Interface.
|
||||
virtual bool CanReimport(UObject* Obj, TArray<FString>& OutFilenames) override;
|
||||
virtual void SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths) override;
|
||||
virtual EReimportResult::Type Reimport(UObject* Obj) override;
|
||||
virtual int32 GetPriority() const override;
|
||||
//~ End FReimportHandler Interface.
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
class FRuntimeAudioImporterEditorModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
// Georgy Treshchev 2023.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class RuntimeAudioImporterEditor : ModuleRules
|
||||
{
|
||||
public RuntimeAudioImporterEditor(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
// Change to toggle MetaSounds support
|
||||
bool bEnableMetaSoundSupport = false;
|
||||
|
||||
// MetaSound is only supported in Unreal Engine version >= 5.3
|
||||
bEnableMetaSoundSupport &= (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion >= 3) || Target.Version.MajorVersion > 5;
|
||||
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
"RuntimeAudioImporter"
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"UnrealEd"
|
||||
}
|
||||
);
|
||||
|
||||
if (bEnableMetaSoundSupport)
|
||||
{
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"MetasoundGraphCore",
|
||||
"MetasoundFrontend",
|
||||
"MetasoundEditor"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
12532
Plugins/RuntimeAudioImporter/Source/ThirdParty/dr_flac.h
vendored
12532
Plugins/RuntimeAudioImporter/Source/ThirdParty/dr_flac.h
vendored
File diff suppressed because it is too large
Load Diff
4823
Plugins/RuntimeAudioImporter/Source/ThirdParty/dr_mp3.h
vendored
4823
Plugins/RuntimeAudioImporter/Source/ThirdParty/dr_mp3.h
vendored
File diff suppressed because it is too large
Load Diff
8668
Plugins/RuntimeAudioImporter/Source/ThirdParty/dr_wav.h
vendored
8668
Plugins/RuntimeAudioImporter/Source/ThirdParty/dr_wav.h
vendored
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ public class Cut5 : ModuleRules
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" , "FFMPEGMedia", "FFMPEGMediaFactory"});
|
||||
PrivateDependencyModuleNames.AddRange(new string[] {"RuntimeAudioImporter", "FFMPEGMedia", "FFMPEGMediaFactory", "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform", "PortAudioPlugin", "EditorStyle"});
|
||||
PrivateDependencyModuleNames.AddRange(new string[] {"FFMPEGMedia", "FFMPEGMediaFactory", "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform", "PortAudioPlugin"});
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
virtual void OpenProject(const FString& Project) {};
|
||||
virtual void ExportProject(const FString& ExportPath) {};
|
||||
virtual void ImportProject(const FString& ImportPath) {};
|
||||
virtual void NewProject(const FString& NewPath){};
|
||||
virtual FString GetGroupName(TSharedPtr<class IWidgetInterface> WidgetInterface) { return FString(); };
|
||||
virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) { return nullptr; };
|
||||
|
||||
|
@ -183,11 +183,9 @@ bool FFFMPEGUtils::ExportImage(UTexture2D* Texture2D, const FString& Path)
|
||||
{
|
||||
// setup required parameters
|
||||
TextureCompressionSettings OldCompressionSettings = Texture2D->CompressionSettings;
|
||||
TextureMipGenSettings OldMipGenSettings = Texture2D->MipGenSettings;
|
||||
bool OldSRGB = Texture2D->SRGB;
|
||||
|
||||
Texture2D->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
|
||||
Texture2D->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
|
||||
Texture2D->SRGB = false;
|
||||
Texture2D->UpdateResource();
|
||||
|
||||
@ -221,7 +219,6 @@ bool FFFMPEGUtils::ExportImage(UTexture2D* Texture2D, const FString& Path)
|
||||
|
||||
// return old parameters
|
||||
Texture2D->CompressionSettings = OldCompressionSettings;
|
||||
Texture2D->MipGenSettings = OldMipGenSettings;
|
||||
Texture2D->SRGB = OldSRGB;
|
||||
|
||||
Texture2D->UpdateResource();
|
||||
|
@ -25,15 +25,15 @@ public:
|
||||
|
||||
static FString GroupFullPath(const FString& GroupName)
|
||||
{
|
||||
return FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, TEXT("FX"), GroupName + TEXT(".bin"));
|
||||
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), GroupName + TEXT(".bin"));
|
||||
};
|
||||
static FString SingleCardFullPath(const FString& CardName)
|
||||
{
|
||||
return FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, TEXT("FX"), TEXT("SingleCard"), CardName + TEXT(".bin"));
|
||||
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), TEXT("SingleCard"), CardName + TEXT(".bin"));
|
||||
};
|
||||
static FString MainSaveFullPath()
|
||||
{
|
||||
return FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, FGlobalData::CurrentProjectName + TEXT(".bin"));
|
||||
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, FGlobalData::CurrentProjectName + TEXT(".bin"));
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -62,6 +62,26 @@ void SCurtainPanel::Construct(const FArguments& InArgs)
|
||||
]
|
||||
+ SVerticalBox::Slot()
|
||||
.SizeParam(FAuto())
|
||||
[
|
||||
SNew(SBox)
|
||||
.WidthOverride(100)
|
||||
.HeightOverride(50)
|
||||
[
|
||||
SNew(SButton)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
FString String;
|
||||
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
||||
DesktopPlatform->OpenDirectoryDialog(nullptr, TEXT("选择新建路径"), String, String);
|
||||
MainWidgetInterface->NewProject(String);
|
||||
return FReply::Handled();
|
||||
})
|
||||
.Text(FText::FromString(TEXT("新建")))
|
||||
]
|
||||
|
||||
]
|
||||
+ SVerticalBox::Slot()
|
||||
.SizeParam(FAuto())
|
||||
[
|
||||
SNew(SBox)
|
||||
.WidthOverride(100)
|
||||
|
@ -6,7 +6,7 @@ extern "C"{
|
||||
}
|
||||
|
||||
|
||||
#include "DragAndDrop/DecoratedDragDropOp.h"
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/videoio.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
@ -24,7 +24,7 @@ public:
|
||||
inline static float CurrentTimeScroll = 0.0f;
|
||||
inline static float GlobalFPS = 30.0f;
|
||||
inline static FString CurrentProjectName = "DefaultProject";
|
||||
inline static FString BasePath = "";
|
||||
inline static FString BasePath = FPaths::ProjectDir();
|
||||
static int32 GetAlignOfTickSpace(double Align, bool bCeil = false)
|
||||
{
|
||||
return bCeil ? FMath::CeilToInt(Align / FGlobalData::DefaultTimeTickSpace) * FGlobalData::DefaultTimeTickSpace :
|
||||
@ -213,11 +213,11 @@ struct CUT5_API FTimelinePropertyData
|
||||
}
|
||||
};
|
||||
|
||||
class CUT5_API FCutDragDropBase : public FDecoratedDragDropOp
|
||||
class CUT5_API FCutDragDropBase : public FDragDropOperation
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
DRAG_DROP_OPERATOR_TYPE(FStatIDDragDropOp, FDragDropOperation)
|
||||
// TODO: I Decide to use type to Main Widget to handle all drag over event
|
||||
enum class EType
|
||||
{
|
||||
@ -228,13 +228,13 @@ public:
|
||||
FCutDragDropBase() {};
|
||||
FCutDragDropBase(EType InType)
|
||||
{
|
||||
Type = InType;
|
||||
DragDropType = InType;
|
||||
}
|
||||
TSharedPtr<SWidget> DraggingWidget;
|
||||
TSharedPtr<IWidgetInterface> OverrideWidget;
|
||||
TSharedPtr<IWidgetInterface> MoveAboutWidget;
|
||||
float DragOffset = 0.0f;
|
||||
EType Type = EType::TrackClip;
|
||||
EType DragDropType = EType::TrackClip;
|
||||
|
||||
};
|
||||
|
||||
|
@ -20,9 +20,9 @@ DragDropOperator* DragDropOperator::GetDragDropOperator()
|
||||
void DragDropOperator::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
|
||||
{
|
||||
const auto& DragDropOperation = static_cast<FClip2ClipDragDropOperation&>(DragDropEvent.GetOperation().ToSharedRef().Get());
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Green, FString::Printf(TEXT("%f"), DragDropEvent.GetScreenSpacePosition().X));
|
||||
// GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Green, FString::Printf(TEXT("%f"), DragDropEvent.GetScreenSpacePosition().X));
|
||||
TSharedPtr<STrackBody> Body = StaticCastSharedPtr<STrackBody>(DragDropOperation.OverrideWidget);
|
||||
if (DragDropOperation.Type == FCutDragDropBase::EType::Clip2Clip)
|
||||
if (DragDropOperation.DragDropType == FCutDragDropBase::EType::Clip2Clip)
|
||||
{
|
||||
if (DragDropOperation.DragType == FClip2ClipDragDropOperation::EDragType::DragLeft)
|
||||
{
|
||||
@ -40,7 +40,7 @@ void DragDropOperator::OnDragOver(const FGeometry& MyGeometry, const FDragDropEv
|
||||
TimelineClip->UpdateMove(Body->GetCachedGeometry().AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).X / FGlobalData::DefaultTimeTickSpace , DragDropOperation.DragOffset / FGlobalData::DefaultTimeTickSpace);
|
||||
}
|
||||
}
|
||||
else if (DragDropOperation.Type == FCutDragDropBase::EType::TrackClip)
|
||||
else if (DragDropOperation.DragDropType == FCutDragDropBase::EType::TrackClip)
|
||||
{
|
||||
|
||||
}
|
||||
@ -49,7 +49,7 @@ void DragDropOperator::OnDragOver(const FGeometry& MyGeometry, const FDragDropEv
|
||||
void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent, TSharedPtr<SWidget> DropWidget)
|
||||
{
|
||||
const auto& DragDropOperation = static_cast<FTrackClipDragOperation&>(DragDropEvent.GetOperation().ToSharedRef().Get());
|
||||
if (DragDropOperation.Type == FCutDragDropBase::EType::TrackClip)
|
||||
if (DragDropOperation.DragDropType == FCutDragDropBase::EType::TrackClip)
|
||||
{
|
||||
|
||||
|
||||
@ -107,7 +107,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
}
|
||||
else if (ClipDragOperation.TimelinePropertyData->Type == ETrackType::LightArrayTrack)
|
||||
{
|
||||
NewClipData.ClipEndTime = NewClipData.ClipStartTime + 200;
|
||||
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + 200;
|
||||
}
|
||||
// 如果拖拽物是音频
|
||||
else if (ClipDragOperation.TimelinePropertyData->Type == ETrackType::AudioTrack)
|
||||
@ -123,10 +123,10 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
//Overwrite the clip if it is in the same position
|
||||
for (int32 i = TrackHead->TrackData.ClipData.Num() - 1; i >= 0; i--)
|
||||
{
|
||||
const double ClipStartTime = TrackHead->TrackData.ClipData[i].ClipStartTime;
|
||||
const double ClipEndTime = TrackHead->TrackData.ClipData[i].ClipEndTime;
|
||||
const int32 ClipStartFrame = TrackHead->TrackData.ClipData[i].ClipStartFrame;
|
||||
const int32 ClipEndFrame = TrackHead->TrackData.ClipData[i].ClipEndFrame;
|
||||
|
||||
if (NewClipData.ClipStartTime >= ClipStartTime && NewClipData.ClipEndTime <= ClipEndTime)
|
||||
if (NewClipData.ClipStartFrame >= ClipStartFrame && NewClipData.ClipEndFrame <= ClipEndFrame)
|
||||
{
|
||||
// It mean the new clip is in the old clip
|
||||
FClipData SaveClipData = TrackHead->TrackData.ClipData[i];
|
||||
@ -134,29 +134,29 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
|
||||
// Left
|
||||
FClipData LeftClipData = SaveClipData;
|
||||
LeftClipData.ClipEndTime = NewClipData.ClipStartTime;
|
||||
LeftClipData.ClipEndFrame = NewClipData.ClipStartFrame;
|
||||
TrackHead->TrackData.ClipData.Add(LeftClipData);
|
||||
|
||||
FClipData RightClipData = SaveClipData;
|
||||
RightClipData.ClipStartTime = NewClipData.ClipEndTime;
|
||||
RightClipData.ClipStartFrame = NewClipData.ClipEndFrame;
|
||||
TrackHead->TrackData.ClipData.Add(RightClipData);
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
if (NewClipData.ClipStartTime <= ClipEndTime && NewClipData.ClipEndTime >= ClipEndTime)
|
||||
if (NewClipData.ClipStartFrame <= ClipEndFrame && NewClipData.ClipEndFrame >= ClipEndFrame)
|
||||
{
|
||||
// It mean the new clip start point is in the old clip
|
||||
TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromBack, (ClipEndTime - NewClipData.ClipStartTime) / FGlobalData::DefaultTimeTickSpace);
|
||||
TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromBack, (ClipEndFrame - NewClipData.ClipStartFrame));
|
||||
continue;
|
||||
}
|
||||
if (NewClipData.ClipEndTime > ClipStartTime && NewClipData.ClipStartTime < ClipStartTime)
|
||||
if (NewClipData.ClipEndFrame > ClipStartFrame && NewClipData.ClipStartFrame < ClipStartFrame)
|
||||
{
|
||||
// It mean the new clip end point is in the old clip
|
||||
TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromFront, (NewClipData.ClipEndTime - ClipStartTime) / FGlobalData::DefaultTimeTickSpace);
|
||||
TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromFront, (NewClipData.ClipEndFrame - ClipStartFrame));
|
||||
continue;
|
||||
}
|
||||
if (NewClipData.ClipStartTime <= ClipStartTime && NewClipData.ClipEndTime >= ClipEndTime)
|
||||
if (NewClipData.ClipStartFrame <= ClipStartFrame && NewClipData.ClipEndFrame >= ClipEndFrame)
|
||||
{
|
||||
// It mean the new clip is out of the old clip
|
||||
TrackHead->TrackData.ClipData.RemoveAt(i);
|
||||
@ -167,7 +167,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
TrackHead->TrackData.ClipData.Add(NewClipData);
|
||||
// GEngine->AddOnScreenDebugMessage(-1, 10.0, FColor::Green, FString::Printf(TEXT("Track %d"), TrackHead->TrackData.ClipData.Num()));
|
||||
}
|
||||
if (DragDropOperation.Type == FCutDragDropBase::EType::Clip2Clip)
|
||||
if (DragDropOperation.DragDropType == FCutDragDropBase::EType::Clip2Clip)
|
||||
{
|
||||
// OnDrop We Calculate Overwrite of all
|
||||
const auto& ClipDragOperation = static_cast<FClip2ClipDragDropOperation&>(DragDropEvent.GetOperation().ToSharedRef().Get());
|
||||
@ -175,14 +175,14 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
TSharedPtr<STrackHead> TrackHead = StaticCastSharedPtr<STrackBody>(ClipDragOperation.OverrideWidget)->TrackHead;
|
||||
for (int32 i = TrackHead->TrackData.ClipData.Num() - 1; i >= 0; i--)
|
||||
{
|
||||
if (TimelineClip->ClipData->ClipStartTime == TrackHead->TrackData.ClipData[i].ClipStartTime || TimelineClip->ClipData->ClipEndTime == TrackHead->TrackData.ClipData[i].ClipEndTime)
|
||||
if (TimelineClip->ClipData->ClipStartFrame == TrackHead->TrackData.ClipData[i].ClipStartFrame || TimelineClip->ClipData->ClipEndFrame == TrackHead->TrackData.ClipData[i].ClipEndFrame)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const double ClipStartTime = TrackHead->TrackData.ClipData[i].ClipStartTime;
|
||||
const double ClipEndTime = TrackHead->TrackData.ClipData[i].ClipEndTime;
|
||||
const double ClipStartFrame = TrackHead->TrackData.ClipData[i].ClipStartFrame;
|
||||
const double ClipEndFrame = TrackHead->TrackData.ClipData[i].ClipEndFrame;
|
||||
|
||||
if (TimelineClip->ClipData->ClipStartTime >= ClipStartTime && TimelineClip->ClipData->ClipEndTime <= ClipEndTime)
|
||||
if (TimelineClip->ClipData->ClipStartFrame >= ClipStartFrame && TimelineClip->ClipData->ClipEndFrame <= ClipEndFrame)
|
||||
{
|
||||
// It mean the new clip is in the old clip
|
||||
FClipData SaveClipData = TrackHead->TrackData.ClipData[i];
|
||||
@ -190,32 +190,31 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
|
||||
// Left
|
||||
FClipData LeftClipData = SaveClipData;
|
||||
LeftClipData.ClipEndTime = TimelineClip->ClipData->ClipStartTime;
|
||||
LeftClipData.ClipEndFrame = TimelineClip->ClipData->ClipStartFrame;
|
||||
TrackHead->TrackData.ClipData.Add(LeftClipData);
|
||||
|
||||
FClipData RightClipData = SaveClipData;
|
||||
RightClipData.ClipStartTime = TimelineClip->ClipData->ClipEndTime;
|
||||
RightClipData.ClipStartFrame = TimelineClip->ClipData->ClipEndFrame;
|
||||
TrackHead->TrackData.ClipData.Add(RightClipData);
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
if (TimelineClip->ClipData->ClipStartTime <= ClipEndTime && TimelineClip->ClipData->ClipEndTime >= ClipEndTime)
|
||||
if (TimelineClip->ClipData->ClipStartFrame <= ClipEndFrame && TimelineClip->ClipData->ClipEndFrame >= ClipEndFrame)
|
||||
{
|
||||
// It mean the new clip start point is in the old clip
|
||||
int32 NewStartFrame = FGlobalData::GetAlignOfTickSpace(TimelineClip->ClipData->ClipStartTime, true) / FGlobalData::DefaultTimeTickSpace;
|
||||
int32 LeftCropFrame = FGlobalData::GetAlignOfTickSpace(TrackHead->TrackData.ClipData[i].ClipEndTime, true) / FGlobalData::DefaultTimeTickSpace - NewStartFrame;
|
||||
LeftCropFrame++;
|
||||
int32 NewStartFrame = TimelineClip->ClipData->ClipStartFrame;
|
||||
int32 LeftCropFrame = TrackHead->TrackData.ClipData[i].ClipEndFrame - NewStartFrame;
|
||||
TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromBack, LeftCropFrame);
|
||||
continue;
|
||||
}
|
||||
if (TimelineClip->ClipData->ClipEndTime > ClipStartTime && TimelineClip->ClipData->ClipStartTime < ClipStartTime)
|
||||
if (TimelineClip->ClipData->ClipEndFrame > ClipStartFrame && TimelineClip->ClipData->ClipStartFrame < ClipStartFrame)
|
||||
{
|
||||
// It mean the new clip end point is in the old clip
|
||||
TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromFront, (TimelineClip->ClipData->ClipEndTime - ClipStartTime) / FGlobalData::DefaultTimeTickSpace);
|
||||
TrackHead->TrackData.ClipData[i].CropClip(FClipData::ECropMethod::FromFront, (TimelineClip->ClipData->ClipEndFrame - ClipStartFrame));
|
||||
continue;
|
||||
}
|
||||
if (TimelineClip->ClipData->ClipStartTime <= ClipStartTime && TimelineClip->ClipData->ClipEndTime >= ClipEndTime)
|
||||
if (TimelineClip->ClipData->ClipStartFrame <= ClipStartFrame && TimelineClip->ClipData->ClipEndFrame >= ClipEndFrame)
|
||||
{
|
||||
// It mean the new clip is out of the old clip
|
||||
TrackHead->TrackData.ClipData.RemoveAt(i);
|
||||
@ -236,7 +235,7 @@ void DragDropOperator::OnDropAddNewTrack(const FGeometry& MyGeometry, const FDra
|
||||
TSharedPtr<SCutTimeline> Timeline = StaticCastSharedPtr<SCutTimeline>(DropWidget);
|
||||
if (Timeline)
|
||||
{
|
||||
if (ClipDragOperation.Type == FTrackClipDragOperation::EType::TrackClip)
|
||||
if (ClipDragOperation.DragDropType == FTrackClipDragOperation::EType::TrackClip)
|
||||
{
|
||||
FTrackData TrackData;
|
||||
TrackData.TrackName = ClipDragOperation.TimelinePropertyData->Name;
|
||||
|
@ -122,6 +122,7 @@ void SEffectCardGroup::CallRender()
|
||||
// 新建卡牌后 对卡牌进行个体保存。
|
||||
FEffectCardProperty NewCard;
|
||||
NewCard.Name = TEXT("未命名") + NewCard.Guid.ToString();
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Cyan, *FUtils::SingleCardFullPath(NewCard.Name));
|
||||
FUtils::CreateDefaultTimelineSave(FUtils::SingleCardFullPath(NewCard.Name), FTimelineInfo::ETimelineType::FX);
|
||||
{
|
||||
FSaveModifier SaveModifier(FUtils::SingleCardFullPath(NewCard.Name));
|
||||
|
@ -255,8 +255,7 @@ void SEffectCardsPanel::SavePanel(const FString& Path)
|
||||
{
|
||||
FString Target = Property.TimelineInfo.CurrentOpenFullPath;
|
||||
FPaths::CollapseRelativeDirectories(Target);
|
||||
IFileManager::Get().Move(*FPaths::Combine(Path, Target), *Property.TimelineInfo.CurrentOpenFullPath);
|
||||
|
||||
IFileManager::Get().Move(*FPaths::Combine(Path, "FX", "Cards"), *Property.TimelineInfo.CurrentOpenFullPath);
|
||||
}
|
||||
MemoryWriter << Group;
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <opencv2/videoio.hpp>
|
||||
#include "AudioDevice.h"
|
||||
|
||||
#include "RuntimeAudioImporterLibrary.h"
|
||||
#include "Cut5/Interface/SoundInterface.h"
|
||||
#include "Cut5/Utils/FFMPEGUtils.h"
|
||||
#include "Engine/Engine.h"
|
||||
|
@ -49,7 +49,7 @@ FReply SCustomInputResource::OnDragDetected(const FGeometry& MyGeometry, const F
|
||||
const TSharedPtr<FTrackClipDragOperation> Operation = MakeShared<FTrackClipDragOperation>();
|
||||
Operation->TimelinePropertyData = &PropertyData;
|
||||
Operation->DraggingWidget = SharedThis(this);
|
||||
Operation->Type = FCutDragDropBase::EType::TrackClip;
|
||||
Operation->DragDropType = FCutDragDropBase::EType::TrackClip;
|
||||
Operation->VideoCapture = &VideoCapture;
|
||||
return FReply::Handled().BeginDragDrop(Operation.ToSharedRef());
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
|
||||
SoundThread = new FSoundThread();
|
||||
FRunnableThread* Thread = FRunnableThread::Create(SoundThread, TEXT("SoundThread"));
|
||||
// OpenProject(FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("DefaultProject")));
|
||||
ImportProject("");
|
||||
// ImportProject("");
|
||||
|
||||
}
|
||||
|
||||
@ -200,13 +200,13 @@ FReply SCutMainWindow::OnDragOver(const FGeometry& MyGeometry, const FDragDropEv
|
||||
FReply SCutMainWindow::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
|
||||
{
|
||||
TSharedPtr<FCutDragDropBase> DragDropOperation = DragDropEvent.GetOperationAs<FCutDragDropBase>();
|
||||
if (DragDropOperation->Type == FCutDragDropBase::EType::Clip2Clip)
|
||||
if (DragDropOperation->DragDropType == FCutDragDropBase::EType::Clip2Clip)
|
||||
{
|
||||
TSharedPtr<STrackBody> Body = StaticCastSharedPtr<STrackBody>(DragDropOperation->OverrideWidget);
|
||||
DragDropOperator::GetDragDropOperator()->OnDrop(MyGeometry, DragDropEvent, Body);
|
||||
Body->CallRender();
|
||||
}
|
||||
else if (DragDropOperation->Type == FCutDragDropBase::EType::TrackClip)
|
||||
else if (DragDropOperation->DragDropType == FCutDragDropBase::EType::TrackClip)
|
||||
{
|
||||
TSharedPtr<STrackBody> Body = StaticCastSharedPtr<STrackBody>(DragDropOperation->MoveAboutWidget);
|
||||
if (Body.IsValid())
|
||||
@ -507,6 +507,12 @@ void SCutMainWindow::ImportProject(const FString& ImportPath)
|
||||
|
||||
}
|
||||
|
||||
void SCutMainWindow::NewProject(const FString& NewPath)
|
||||
{
|
||||
FGlobalData::BasePath = NewPath;
|
||||
|
||||
}
|
||||
|
||||
void SCutMainWindow::OnSelectCard(const FGuid& SelectedCard)
|
||||
{
|
||||
if (SelectedCard.IsValid())
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
virtual void OpenProject(const FString& Project) override;
|
||||
virtual void ExportProject(const FString& ExportPath) override;
|
||||
virtual void ImportProject(const FString& ImportPath) override;
|
||||
|
||||
virtual void NewProject(const FString& NewPath) override;
|
||||
virtual void OnSelectCard(const FGuid& SelectedCard) override;
|
||||
|
||||
virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) override;
|
||||
|
@ -237,7 +237,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
|
||||
|
||||
];
|
||||
TrackHeadScrollBox->SetScrollBarVisibility(EVisibility::Hidden);
|
||||
|
||||
TimelineInfo.CurrentOpenFullPath = FUtils::MainSaveFullPath();
|
||||
FTrackData AudioDataL(TEXT("音频L"), ETrackType::AudioTrack);
|
||||
AddNewTrackToGroup(TEXT("固定轨道"), AudioDataL);
|
||||
FTrackData AudioDataR(TEXT("音频R"), ETrackType::AudioTrackR);
|
||||
@ -416,14 +416,8 @@ void SCutTimeline::SaveTimeline(const FString& SavedPath, FTimelineInfo Info)
|
||||
bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
|
||||
{
|
||||
TArray<uint8> LoadData;
|
||||
if (!FPaths::IsDrive(LoadPath))
|
||||
{
|
||||
FFileHelper::LoadFileToArray(LoadData, *FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, LoadPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
FFileHelper::LoadFileToArray(LoadData, *LoadPath);
|
||||
}
|
||||
FPaths::ConvertRelativePathToFull(LoadPath);
|
||||
FFileHelper::LoadFileToArray(LoadData, *LoadPath);
|
||||
if (LoadData.Num() == 0)
|
||||
{
|
||||
return false;
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
|
||||
#include "AudioDevice.h"
|
||||
#include "RuntimeAudioImporterLibrary.h"
|
||||
#include "SlateOptMacros.h"
|
||||
#include "Commands/TimelineClipCommands.h"
|
||||
#include "Cut5/WidgetInterface.h"
|
||||
@ -50,7 +49,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
|
||||
{
|
||||
const TSharedPtr<FClip2ClipDragDropOperation> Clip2ClipDragDropOperation = MakeShared<FClip2ClipDragDropOperation>();
|
||||
Clip2ClipDragDropOperation->DraggingWidget = SharedThis(this);
|
||||
Clip2ClipDragDropOperation->Type = FCutDragDropBase::EType::Clip2Clip;
|
||||
Clip2ClipDragDropOperation->DragDropType = FCutDragDropBase::EType::Clip2Clip;
|
||||
Clip2ClipDragDropOperation->DragType = FClip2ClipDragDropOperation::EDragType::DragLeft;
|
||||
Clip2ClipDragDropOperation->OverrideWidget = Body;
|
||||
Clip2ClipDragDropOperation->DragOffset = LocalPos.X;
|
||||
@ -60,7 +59,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
|
||||
{
|
||||
const TSharedPtr<FClip2ClipDragDropOperation> Clip2ClipDragDropOperation = MakeShared<FClip2ClipDragDropOperation>();
|
||||
Clip2ClipDragDropOperation->DraggingWidget = SharedThis(this);
|
||||
Clip2ClipDragDropOperation->Type = FCutDragDropBase::EType::Clip2Clip;
|
||||
Clip2ClipDragDropOperation->DragDropType = FCutDragDropBase::EType::Clip2Clip;
|
||||
Clip2ClipDragDropOperation->DragType = FClip2ClipDragDropOperation::EDragType::DragRight;
|
||||
Clip2ClipDragDropOperation->OverrideWidget = Body;
|
||||
Clip2ClipDragDropOperation->DragOffset = LocalPos.X;
|
||||
@ -70,7 +69,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
|
||||
{
|
||||
const TSharedPtr<FClip2ClipDragDropOperation> Clip2ClipDragDropOperation = MakeShared<FClip2ClipDragDropOperation>();
|
||||
Clip2ClipDragDropOperation->DraggingWidget = SharedThis(this);
|
||||
Clip2ClipDragDropOperation->Type = FCutDragDropBase::EType::Clip2Clip;
|
||||
Clip2ClipDragDropOperation->DragDropType = FCutDragDropBase::EType::Clip2Clip;
|
||||
Clip2ClipDragDropOperation->DragType = FClip2ClipDragDropOperation::EDragType::Move;
|
||||
Clip2ClipDragDropOperation->OverrideWidget = Body;
|
||||
Clip2ClipDragDropOperation->DragOffset = LocalPos.X;
|
||||
@ -127,7 +126,7 @@ void STimelineClip::Seek(int32 Frame)
|
||||
AVRational frame_rate = ClipData->ResourcePropertyDataPtr->Context->streams[ClipData->ResourcePropertyDataPtr->VideoStream]->avg_frame_rate;
|
||||
if (av_seek_frame(ClipData->ResourcePropertyDataPtr->Context, ClipData->ResourcePropertyDataPtr->VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD) < 0)
|
||||
{
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Blue, TEXT("Seek Failed"));
|
||||
// GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Blue, TEXT("Seek Failed"));
|
||||
};
|
||||
}
|
||||
LastSeekFrame = SeekMovieFrame;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/core/mat.hpp>
|
||||
|
||||
#include "RuntimeAudioImporterTypes.h"
|
||||
|
||||
#include "Widgets/Layout/SBox.h"
|
||||
extern "C"
|
||||
{
|
||||
@ -50,7 +50,6 @@ public:
|
||||
int32 LastSeekFrame = 0;
|
||||
int64 LastTimeStamp = 0;
|
||||
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
|
||||
FDecodedAudioStruct DecodedAudioStruct;
|
||||
PaStream* Stream = nullptr;
|
||||
|
||||
|
||||
|
@ -48,7 +48,7 @@ FReply STimelineProperty::OnDragDetected(const FGeometry& MyGeometry, const FPoi
|
||||
const TSharedPtr<FTrackClipDragOperation> Operation = MakeShared<FTrackClipDragOperation>();
|
||||
Operation->TimelinePropertyData = &TimelinePropertyData;
|
||||
Operation->DraggingWidget = SharedThis(this);
|
||||
Operation->Type = FCutDragDropBase::EType::TrackClip;
|
||||
Operation->DragDropType = FCutDragDropBase::EType::TrackClip;
|
||||
return FReply::Handled().BeginDragDrop(Operation.ToSharedRef());
|
||||
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ void STrackBody::BreakClip(const FGuid& Guid)
|
||||
NewClipData.CropClip(FClipData::ECropMethod::FromFront, SelectedClipFrame + 1);
|
||||
TrackHead->TrackData.ClipData.Add(NewClipData);
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Emerald, FString::Printf(TEXT("CropFrameLeft %d CropFrameRight %d"), SelectedClipFrame, CropFrameRight));
|
||||
// GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Emerald, FString::Printf(TEXT("CropFrameLeft %d CropFrameRight %d"), SelectedClipFrame, CropFrameRight));
|
||||
}
|
||||
}
|
||||
CallRender();
|
||||
|
Loading…
Reference in New Issue
Block a user