(caf7e6a2e) Replaced Concentus NuGet package with csproj (ensures correct System.Runtime references)
This commit is contained in:
@@ -60,9 +60,6 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Concentus, Version=1.1.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\Concentus.1.1.7\lib\portable-net45+win+wpa81+wp80\Concentus.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="GameAnalytics.Mono, Version=1.0.6710.29255, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -132,6 +129,10 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.csproj">
|
||||
<Project>{0e7fee6a-15e5-4a4e-943c-80276003478c}</Project>
|
||||
<Name>Concentus</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.csproj">
|
||||
<Project>{3af0347c-5a9b-4421-868c-8ee3dbfaebc6}</Project>
|
||||
<Name>Facepunch.Steamworks</Name>
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Concentus, Version=1.1.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\Concentus.1.1.7\lib\portable-net45+win+wpa81+wp80\Concentus.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="GameAnalytics.Mono, Version=1.0.6710.29255, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -131,6 +128,10 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.csproj">
|
||||
<Project>{0e7fee6a-15e5-4a4e-943c-80276003478c}</Project>
|
||||
<Name>Concentus</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.csproj">
|
||||
<Project>{3af0347c-5a9b-4421-868c-8ee3dbfaebc6}</Project>
|
||||
<Name>Facepunch.Steamworks</Name>
|
||||
|
||||
@@ -108,6 +108,61 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//unconscious/dead characters can't correct their position using AnimController movement
|
||||
// -> we need to correct it manually
|
||||
if (!character.AllowInput)
|
||||
{
|
||||
float mainLimbDistSqrd = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition);
|
||||
float mainLimbErrorTolerance = 0.1f;
|
||||
//if the main limb is roughly at the correct position and the collider isn't moving (much at least),
|
||||
//don't attempt to correct the position.
|
||||
if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f)
|
||||
{
|
||||
MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
|
||||
MainLimb.PullJointEnabled = true;
|
||||
}
|
||||
character.SelectedConstruction = character.MemState[0].SelectedItem;
|
||||
}
|
||||
|
||||
if (character.MemState[0].Animation == AnimController.Animation.CPR)
|
||||
{
|
||||
character.AnimController.Anim = AnimController.Animation.CPR;
|
||||
}
|
||||
else if (character.AnimController.Anim == AnimController.Animation.CPR)
|
||||
{
|
||||
character.AnimController.Anim = AnimController.Animation.None;
|
||||
}
|
||||
|
||||
Vector2 newVelocity = Collider.LinearVelocity;
|
||||
Vector2 newPosition = Collider.SimPosition;
|
||||
float newRotation = Collider.Rotation;
|
||||
float newAngularVelocity = Collider.AngularVelocity;
|
||||
Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity);
|
||||
|
||||
newVelocity = newVelocity.ClampLength(100.0f);
|
||||
if (!MathUtils.IsValid(newVelocity)) { newVelocity = Vector2.Zero; }
|
||||
overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero;
|
||||
|
||||
Collider.LinearVelocity = newVelocity;
|
||||
Collider.AngularVelocity = newAngularVelocity;
|
||||
|
||||
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
|
||||
float errorTolerance = character.AllowInput ? 0.01f : 0.2f;
|
||||
if (distSqrd > errorTolerance)
|
||||
{
|
||||
if (distSqrd > 10.0f || !character.AllowInput)
|
||||
{
|
||||
Collider.TargetRotation = newRotation;
|
||||
SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Collider.TargetRotation = newRotation;
|
||||
Collider.TargetPosition = newPosition;
|
||||
Collider.MoveToTargetPosition(true);
|
||||
}
|
||||
}
|
||||
|
||||
//unconscious/dead characters can't correct their position using AnimController movement
|
||||
// -> we need to correct it manually
|
||||
if (!character.AllowInput)
|
||||
@@ -151,32 +206,34 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120);
|
||||
character.MemState.Clear();
|
||||
character.MemLocalState.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
partial void ImpactProjSpecific(float impact, Body body)
|
||||
{
|
||||
float volume = MathHelper.Clamp(impact - 3.0f, 0.5f, 1.0f);
|
||||
|
||||
if (body.UserData is Limb limb && character.Stun <= 0f)
|
||||
else
|
||||
{
|
||||
if (impact > 3.0f) { PlayImpactSound(limb); }
|
||||
}
|
||||
else if (body.UserData is Limb || body == Collider.FarseerBody)
|
||||
{
|
||||
if (!character.IsRemotePlayer && impact > ImpactTolerance)
|
||||
//remove states with a timestamp (there may still timestamp-based states
|
||||
//in the list if the controlled character switches from timestamp-based interpolation to ID-based)
|
||||
character.MemState.RemoveAll(m => m.Timestamp > 0.0f);
|
||||
|
||||
for (int i = 0; i < character.MemLocalState.Count; i++)
|
||||
{
|
||||
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
|
||||
if (character.Submarine == null)
|
||||
{
|
||||
//transform in-sub coordinates to outside coordinates
|
||||
if (character.MemLocalState[i].Position.Y > lowestSubPos)
|
||||
{
|
||||
character.MemLocalState[i].TransformInToOutside();
|
||||
}
|
||||
}
|
||||
else if (currentHull?.Submarine != null)
|
||||
{
|
||||
//transform outside coordinates to in-sub coordinates
|
||||
if (character.MemLocalState[i].Position.Y < lowestSubPos)
|
||||
{
|
||||
character.MemLocalState[i].TransformOutToInside(currentHull.Submarine);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (Character.Controlled == character)
|
||||
{
|
||||
GameMain.GameScreen.Cam.Shake = Math.Min(Math.Max(strongestImpact, GameMain.GameScreen.Cam.Shake), 3.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (character.MemState.Count < 1) return;
|
||||
|
||||
|
||||
@@ -58,9 +58,6 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Concentus, Version=1.1.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\Concentus.1.1.7\lib\portable-net45+win+wpa81+wp80\Concentus.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="GameAnalytics.Mono, Version=1.0.6710.29255, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -215,6 +212,10 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.csproj">
|
||||
<Project>{0e7fee6a-15e5-4a4e-943c-80276003478c}</Project>
|
||||
<Name>Concentus</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.csproj">
|
||||
<Project>{3af0347c-5a9b-4421-868c-8ee3dbfaebc6}</Project>
|
||||
<Name>Facepunch.Steamworks</Name>
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.MediaFoundation" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.XAudio2" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.Direct3D11" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.Direct2D1" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.XInput" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.MediaFoundation" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.XAudio2" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.Direct3D11" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.Direct2D1" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpDX.XInput" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Concentus" version="1.1.7" targetFramework="net45" />
|
||||
<package id="GameAnalytics.Mono.SDK" version="1.1.12" targetFramework="net45" />
|
||||
<package id="Microsoft.NETCore.Platforms" version="3.0.0-preview.19073.11" targetFramework="net45" />
|
||||
<package id="MonoGame.Framework.DesktopGL" version="3.7.1.189" targetFramework="net45" />
|
||||
|
||||
@@ -1149,10 +1149,6 @@ namespace Barotrauma
|
||||
{
|
||||
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub != null && Submarine != prevSub)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
|
||||
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
|
||||
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
|
||||
|
||||
@@ -61,6 +61,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MacClient", "Barotrauma\Bar
|
||||
{85232B20-074D-4723-B0C6-91495391E448} = {85232B20-074D-4723-B0C6-91495391E448}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Concentus", "Libraries\Concentus\CSharp\Concentus\Concentus.csproj", "{777A5414-CAE5-4011-96DF-C9661985917E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
Barotrauma\BarotraumaClient\ClientCode.projitems*{008c0f83-e914-4966-9135-ea885059edd8}*SharedItemsImports = 4
|
||||
@@ -81,12 +83,16 @@ Global
|
||||
Barotrauma\BarotraumaShared\SharedContent.projitems*{d7f9fdd3-af03-46ad-a2c2-f590899712b7}*SharedItemsImports = 4
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
DebugLinux|Any CPU = DebugLinux|Any CPU
|
||||
DebugLinux|x64 = DebugLinux|x64
|
||||
DebugMac|Any CPU = DebugMac|Any CPU
|
||||
DebugMac|x64 = DebugMac|x64
|
||||
DebugWindows|Any CPU = DebugWindows|Any CPU
|
||||
DebugWindows|x64 = DebugWindows|x64
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
ReleaseLinux|Any CPU = ReleaseLinux|Any CPU
|
||||
ReleaseLinux|x64 = ReleaseLinux|x64
|
||||
ReleaseMac|Any CPU = ReleaseMac|Any CPU
|
||||
@@ -95,6 +101,10 @@ Global
|
||||
ReleaseWindows|x64 = ReleaseWindows|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Debug|Any CPU.ActiveCfg = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Debug|Any CPU.Build.0 = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Debug|x64.ActiveCfg = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Debug|x64.Build.0 = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.DebugLinux|Any CPU.ActiveCfg = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.DebugLinux|Any CPU.Build.0 = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.DebugLinux|x64.ActiveCfg = DebugWindows|x64
|
||||
@@ -104,6 +114,10 @@ Global
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.DebugWindows|Any CPU.ActiveCfg = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.DebugWindows|x64.ActiveCfg = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.DebugWindows|x64.Build.0 = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Release|Any CPU.ActiveCfg = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Release|Any CPU.Build.0 = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Release|x64.ActiveCfg = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.Release|x64.Build.0 = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.ReleaseLinux|Any CPU.ActiveCfg = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.ReleaseLinux|Any CPU.Build.0 = DebugWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.ReleaseLinux|x64.ActiveCfg = ReleaseWindows|x64
|
||||
@@ -113,6 +127,10 @@ Global
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.ReleaseWindows|x64.ActiveCfg = ReleaseWindows|x64
|
||||
{008C0F83-E914-4966-9135-EA885059EDD8}.ReleaseWindows|x64.Build.0 = ReleaseWindows|x64
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.DebugLinux|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.DebugLinux|Any CPU.Build.0 = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -125,6 +143,10 @@ Global
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.DebugWindows|Any CPU.Build.0 = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.DebugWindows|x64.ActiveCfg = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.DebugWindows|x64.Build.0 = Debug|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.ReleaseLinux|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.ReleaseLinux|Any CPU.Build.0 = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
|
||||
@@ -137,6 +159,10 @@ Global
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.ReleaseWindows|x64.ActiveCfg = Release|Any CPU
|
||||
{49BA1C69-6104-41AC-A5D8-B54FA9F696E8}.ReleaseWindows|x64.Build.0 = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.DebugLinux|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.DebugLinux|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -149,6 +175,10 @@ Global
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.DebugWindows|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.DebugWindows|x64.ActiveCfg = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.DebugWindows|x64.Build.0 = Debug|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.ReleaseLinux|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.ReleaseLinux|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
|
||||
@@ -161,6 +191,10 @@ Global
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.ReleaseWindows|x64.ActiveCfg = Release|Any CPU
|
||||
{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.ReleaseWindows|x64.Build.0 = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.DebugLinux|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.DebugLinux|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -173,6 +207,10 @@ Global
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.DebugWindows|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.DebugWindows|x64.ActiveCfg = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.DebugWindows|x64.Build.0 = Debug|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.ReleaseLinux|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.ReleaseLinux|Any CPU.Build.0 = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
|
||||
@@ -185,6 +223,10 @@ Global
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.ReleaseWindows|x64.ActiveCfg = Release|Any CPU
|
||||
{C293DB32-FA42-486D-B128-5A12522FAE4E}.ReleaseWindows|x64.Build.0 = Release|Any CPU
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Debug|Any CPU.ActiveCfg = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Debug|Any CPU.Build.0 = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Debug|x64.ActiveCfg = DebugWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Debug|x64.Build.0 = DebugWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.DebugLinux|Any CPU.ActiveCfg = DebugLinux|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.DebugLinux|Any CPU.Build.0 = DebugLinux|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.DebugLinux|x64.ActiveCfg = DebugLinux|x64
|
||||
@@ -195,6 +237,10 @@ Global
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.DebugWindows|Any CPU.ActiveCfg = DebugWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.DebugWindows|x64.ActiveCfg = DebugWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.DebugWindows|x64.Build.0 = DebugWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Release|Any CPU.ActiveCfg = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Release|Any CPU.Build.0 = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Release|x64.ActiveCfg = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.Release|x64.Build.0 = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.ReleaseLinux|Any CPU.ActiveCfg = ReleaseLinux|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.ReleaseLinux|x64.Build.0 = ReleaseLinux|x64
|
||||
@@ -204,6 +250,10 @@ Global
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.ReleaseWindows|x64.ActiveCfg = ReleaseWindows|x64
|
||||
{85232B20-074D-4723-B0C6-91495391E448}.ReleaseWindows|x64.Build.0 = ReleaseWindows|x64
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.DebugLinux|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.DebugLinux|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -216,6 +266,10 @@ Global
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.DebugWindows|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.DebugWindows|x64.ActiveCfg = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.DebugWindows|x64.Build.0 = Debug|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.ReleaseLinux|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.ReleaseLinux|Any CPU.Build.0 = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
|
||||
@@ -228,6 +282,10 @@ Global
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.ReleaseWindows|x64.ActiveCfg = Release|Any CPU
|
||||
{A4610E4C-DD34-428B-BABB-779CA0B5993A}.ReleaseWindows|x64.Build.0 = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.DebugLinux|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.DebugLinux|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -240,6 +298,10 @@ Global
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.DebugWindows|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.DebugWindows|x64.ActiveCfg = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.DebugWindows|x64.Build.0 = Debug|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.ReleaseLinux|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.ReleaseLinux|Any CPU.Build.0 = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
|
||||
@@ -252,6 +314,10 @@ Global
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.ReleaseWindows|x64.ActiveCfg = Release|Any CPU
|
||||
{3AF0347C-5A9B-4421-868C-8EE3DBFAEBC6}.ReleaseWindows|x64.Build.0 = Release|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|Any CPU.ActiveCfg = DebugWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|Any CPU.Build.0 = DebugWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|x64.ActiveCfg = DebugWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Debug|x64.Build.0 = DebugWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.DebugLinux|Any CPU.ActiveCfg = DebugLinux|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.DebugLinux|Any CPU.Build.0 = DebugLinux|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU
|
||||
@@ -263,6 +329,10 @@ Global
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.DebugWindows|Any CPU.ActiveCfg = DebugWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.DebugWindows|Any CPU.Build.0 = DebugWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.DebugWindows|x64.ActiveCfg = DebugWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|Any CPU.ActiveCfg = ReleaseWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|Any CPU.Build.0 = ReleaseWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|x64.ActiveCfg = ReleaseWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.Release|x64.Build.0 = ReleaseWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.ReleaseLinux|Any CPU.ActiveCfg = ReleaseLinux|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.ReleaseLinux|Any CPU.Build.0 = ReleaseLinux|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU
|
||||
@@ -274,6 +344,10 @@ Global
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.ReleaseWindows|Any CPU.ActiveCfg = ReleaseWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.ReleaseWindows|Any CPU.Build.0 = ReleaseWindows|Any CPU
|
||||
{0AAD36E3-51A5-4A07-AB60-5C8A66BD38B7}.ReleaseWindows|x64.ActiveCfg = ReleaseWindows|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.DebugLinux|Any CPU.ActiveCfg = DebugLinux|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.DebugLinux|Any CPU.Build.0 = DebugLinux|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU
|
||||
@@ -284,6 +358,10 @@ Global
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.DebugWindows|Any CPU.Build.0 = DebugWindows|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.DebugWindows|x64.ActiveCfg = DebugWindows|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.DebugWindows|x64.Build.0 = DebugWindows|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.Release|x64.Build.0 = Release|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.ReleaseLinux|Any CPU.ActiveCfg = ReleaseLinux|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.ReleaseLinux|Any CPU.Build.0 = ReleaseLinux|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU
|
||||
@@ -294,6 +372,10 @@ Global
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.ReleaseWindows|Any CPU.Build.0 = ReleaseWindows|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.ReleaseWindows|x64.ActiveCfg = ReleaseWindows|Any CPU
|
||||
{830461AA-3E2E-4BDE-9B27-1B3280836521}.ReleaseWindows|x64.Build.0 = ReleaseWindows|Any CPU
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Debug|Any CPU.ActiveCfg = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Debug|Any CPU.Build.0 = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Debug|x64.ActiveCfg = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Debug|x64.Build.0 = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.DebugLinux|Any CPU.ActiveCfg = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.DebugLinux|x64.ActiveCfg = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.DebugLinux|x64.Build.0 = DebugLinux|x64
|
||||
@@ -303,6 +385,10 @@ Global
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.DebugWindows|Any CPU.ActiveCfg = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.DebugWindows|Any CPU.Build.0 = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.DebugWindows|x64.ActiveCfg = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Release|Any CPU.ActiveCfg = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Release|Any CPU.Build.0 = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Release|x64.ActiveCfg = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.Release|x64.Build.0 = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.ReleaseLinux|Any CPU.ActiveCfg = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.ReleaseLinux|x64.Build.0 = ReleaseLinux|x64
|
||||
@@ -312,6 +398,10 @@ Global
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.ReleaseWindows|Any CPU.ActiveCfg = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.ReleaseWindows|Any CPU.Build.0 = DebugLinux|x64
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7}.ReleaseWindows|x64.ActiveCfg = ReleaseLinux|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Debug|Any CPU.ActiveCfg = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Debug|Any CPU.Build.0 = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Debug|x64.ActiveCfg = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Debug|x64.Build.0 = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.DebugLinux|Any CPU.ActiveCfg = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.DebugLinux|x64.ActiveCfg = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.DebugMac|Any CPU.ActiveCfg = DebugMac|x64
|
||||
@@ -321,6 +411,10 @@ Global
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.DebugWindows|Any CPU.ActiveCfg = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.DebugWindows|Any CPU.Build.0 = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.DebugWindows|x64.ActiveCfg = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Release|Any CPU.ActiveCfg = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Release|Any CPU.Build.0 = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Release|x64.ActiveCfg = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.Release|x64.Build.0 = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.ReleaseLinux|Any CPU.ActiveCfg = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.ReleaseLinux|x64.ActiveCfg = ReleaseMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.ReleaseMac|Any CPU.ActiveCfg = DebugMac|x64
|
||||
@@ -330,6 +424,38 @@ Global
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.ReleaseWindows|Any CPU.ActiveCfg = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.ReleaseWindows|Any CPU.Build.0 = DebugMac|x64
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED}.ReleaseWindows|x64.ActiveCfg = ReleaseMac|x64
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugLinux|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugLinux|Any CPU.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugLinux|x64.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugMac|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugMac|Any CPU.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugMac|x64.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugMac|x64.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugWindows|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugWindows|Any CPU.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugWindows|x64.ActiveCfg = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.DebugWindows|x64.Build.0 = Debug|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseLinux|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseLinux|Any CPU.Build.0 = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseLinux|x64.Build.0 = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseMac|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseMac|x64.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseMac|x64.Build.0 = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseWindows|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseWindows|Any CPU.Build.0 = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseWindows|x64.ActiveCfg = Release|Any CPU
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E}.ReleaseWindows|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -355,6 +481,7 @@ Global
|
||||
{D7F9FDD3-AF03-46AD-A2C2-F590899712B7} = {B2C129F2-8E5C-419A-98EB-161AA5B5FC71}
|
||||
{DBCF6FF0-3DE9-11E9-B3EF-63280FDBDA4A} = {F35DF9BF-0BED-4FEF-A51C-DD83C531882F}
|
||||
{CC996BB6-3781-4868-B996-07F9CDC936ED} = {DBCF6FF0-3DE9-11E9-B3EF-63280FDBDA4A}
|
||||
{777A5414-CAE5-4011-96DF-C9661985917E} = {DE36F45F-F09E-4719-B953-00D148F7722A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {17032EAB-554B-4B44-A4F6-EFB177ACAB7A}
|
||||
|
||||
240
Libraries/Concentus/.gitignore
vendored
Normal file
240
Libraries/Concentus/.gitignore
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Microsoft Azure ApplicationInsights config file
|
||||
ApplicationInsights.config
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
/Java/Concentus/target/
|
||||
/Java/ContentusTestConsole/ContentusTestConsole/target/
|
||||
/Java/ContentusTestConsole/ConcentusTestConsole/target/
|
||||
/Java/ConcentusTestConsole/target/
|
||||
36
Libraries/Concentus/CSharp/Concentus.sln
Normal file
36
Libraries/Concentus/CSharp/Concentus.sln
Normal file
@@ -0,0 +1,36 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2009
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Concentus", "Concentus\Concentus.csproj", "{0E7FEE6A-15E5-4A4E-943C-80276003478C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0E7FEE6A-15E5-4A4E-943C-80276003478C}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {4EE53631-CA03-4D29-A3A0-D17B4E57A175}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
6
Libraries/Concentus/CSharp/Concentus/App.config
Normal file
6
Libraries/Concentus/CSharp/Concentus/App.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -0,0 +1,300 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if UNSAFE
|
||||
|
||||
namespace Concentus.Common
|
||||
{
|
||||
using Concentus.Celt;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
|
||||
internal static class Autocorrelation
|
||||
{
|
||||
/* Compute autocorrelation */
|
||||
internal static void silk_autocorr(
|
||||
int[] results, /* O Result (length correlationCount) */
|
||||
BoxedValueInt scale, /* O Scaling of the correlation vector */
|
||||
short[] inputData, /* I Input data to correlate */
|
||||
int inputDataSize, /* I Length of input */
|
||||
int correlationCount /* I Number of correlation taps to compute */
|
||||
)
|
||||
{
|
||||
int corrCount = Inlines.silk_min_int(inputDataSize, correlationCount);
|
||||
scale.Val = Autocorrelation._celt_autocorr(inputData, results, corrCount - 1, inputDataSize);
|
||||
}
|
||||
|
||||
internal static unsafe int _celt_autocorr(
|
||||
short[] x, /* in: [0...n-1] samples x */
|
||||
int[] ac, /* out: [0...lag-1] ac values */
|
||||
int lag,
|
||||
int n
|
||||
)
|
||||
{
|
||||
int d;
|
||||
int i, k;
|
||||
int fastN = n - lag;
|
||||
int shift;
|
||||
short[] xx = new short[n];
|
||||
Inlines.OpusAssert(n > 0);
|
||||
fixed (short* xptr_base = x, pxx = xx)
|
||||
{
|
||||
short* xptr = xptr_base;
|
||||
shift = 0;
|
||||
{
|
||||
int ac0;
|
||||
ac0 = 1 + (n << 7);
|
||||
if ((n & 1) != 0)
|
||||
{
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9);
|
||||
}
|
||||
for (i = (n & 1); i < n; i += 2)
|
||||
{
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9);
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9);
|
||||
}
|
||||
shift = Inlines.celt_ilog2(ac0) - 30 + 10;
|
||||
shift = (shift) / 2;
|
||||
if (shift > 0)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
xx[i] = (short)(Inlines.PSHR32(xptr[i], shift));
|
||||
}
|
||||
xptr = pxx;
|
||||
}
|
||||
else
|
||||
shift = 0;
|
||||
}
|
||||
CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1);
|
||||
for (k = 0; k <= lag; k++)
|
||||
{
|
||||
for (i = k + fastN, d = 0; i < n; i++)
|
||||
d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]);
|
||||
ac[k] += d;
|
||||
}
|
||||
shift = 2 * shift;
|
||||
if (shift <= 0)
|
||||
ac[0] += Inlines.SHL32((int)1, -shift);
|
||||
if (ac[0] < 268435456)
|
||||
{
|
||||
int shift2 = 29 - Inlines.EC_ILOG((uint)ac[0]);
|
||||
for (i = 0; i <= lag; i++)
|
||||
{
|
||||
ac[i] = Inlines.SHL32(ac[i], shift2);
|
||||
}
|
||||
shift -= shift2;
|
||||
}
|
||||
else if (ac[0] >= 536870912)
|
||||
{
|
||||
int shift2 = 1;
|
||||
if (ac[0] >= 1073741824)
|
||||
shift2++;
|
||||
for (i = 0; i <= lag; i++)
|
||||
{
|
||||
ac[i] = Inlines.SHR32(ac[i], shift2);
|
||||
}
|
||||
shift += shift2;
|
||||
}
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
internal static unsafe int _celt_autocorr(
|
||||
int[] x, /* in: [0...n-1] samples x */
|
||||
int[] ac, /* out: [0...lag-1] ac values */
|
||||
int[] window,
|
||||
int overlap,
|
||||
int lag,
|
||||
int n)
|
||||
{
|
||||
int d;
|
||||
int i, k;
|
||||
int fastN = n - lag;
|
||||
int shift;
|
||||
int[] xx = new int[n];
|
||||
|
||||
Inlines.OpusAssert(n > 0);
|
||||
Inlines.OpusAssert(overlap >= 0);
|
||||
|
||||
fixed (int* xptr_base = x, pxx = xx)
|
||||
{
|
||||
int* xptr = xptr_base;
|
||||
|
||||
if (overlap == 0)
|
||||
{
|
||||
xptr = xptr_base;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
xx[i] = x[i];
|
||||
for (i = 0; i < overlap; i++)
|
||||
{
|
||||
xx[i] = Inlines.MULT16_16_Q15(x[i], window[i]);
|
||||
xx[n - i - 1] = Inlines.MULT16_16_Q15(x[n - i - 1], window[i]);
|
||||
}
|
||||
xptr = pxx;
|
||||
}
|
||||
|
||||
shift = 0;
|
||||
|
||||
int ac0;
|
||||
ac0 = 1 + (n << 7);
|
||||
if ((n & 1) != 0)
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9);
|
||||
|
||||
for (i = (n & 1); i < n; i += 2)
|
||||
{
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9);
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9);
|
||||
}
|
||||
|
||||
shift = Inlines.celt_ilog2(ac0) - 30 + 10;
|
||||
shift = (shift) / 2;
|
||||
if (shift > 0)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
xx[i] = (Inlines.PSHR32(xptr[i], shift));
|
||||
xptr = pxx;
|
||||
}
|
||||
else
|
||||
shift = 0;
|
||||
|
||||
CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1);
|
||||
for (k = 0; k <= lag; k++)
|
||||
{
|
||||
for (i = k + fastN, d = 0; i < n; i++)
|
||||
d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]);
|
||||
ac[k] += d;
|
||||
}
|
||||
|
||||
shift = 2 * shift;
|
||||
if (shift <= 0)
|
||||
ac[0] += Inlines.SHL32((int)1, -shift);
|
||||
if (ac[0] < 268435456)
|
||||
{
|
||||
int shift2 = 29 - Inlines.EC_ILOG((uint)ac[0]);
|
||||
for (i = 0; i <= lag; i++)
|
||||
ac[i] = Inlines.SHL32(ac[i], shift2);
|
||||
shift -= shift2;
|
||||
}
|
||||
else if (ac[0] >= 536870912)
|
||||
{
|
||||
int shift2 = 1;
|
||||
if (ac[0] >= 1073741824)
|
||||
shift2++;
|
||||
for (i = 0; i <= lag; i++)
|
||||
ac[i] = Inlines.SHR32(ac[i], shift2);
|
||||
shift += shift2;
|
||||
}
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
private const int QC = 10;
|
||||
private const int QS = 14;
|
||||
|
||||
/* Autocorrelations for a warped frequency axis */
|
||||
internal static unsafe void silk_warped_autocorrelation(
|
||||
int[] corr, /* O Result [order + 1] */
|
||||
BoxedValueInt scale, /* O Scaling of the correlation vector */
|
||||
short[] input, /* I Input data to correlate */
|
||||
int warping_Q16, /* I Warping coefficient */
|
||||
int length, /* I Length of input */
|
||||
int order /* I Correlation order (even) */
|
||||
)
|
||||
{
|
||||
int n, i, lsh;
|
||||
int tmp1_QS, tmp2_QS;
|
||||
int[] state_QS = new int[order + 1];// = { 0 };
|
||||
long[] corr_QC = new long[order + 1];// = { 0 };
|
||||
|
||||
fixed (long* pcorr_QC = corr_QC)
|
||||
{
|
||||
fixed (int* pstate_QS = state_QS)
|
||||
{
|
||||
fixed (short* pinput = input)
|
||||
{
|
||||
/* Order must be even */
|
||||
Inlines.OpusAssert((order & 1) == 0);
|
||||
Inlines.OpusAssert(2 * QS - QC >= 0);
|
||||
|
||||
/* Loop over samples */
|
||||
for (n = 0; n < length; n++)
|
||||
{
|
||||
tmp1_QS = Inlines.silk_LSHIFT32((int)pinput[n], QS);
|
||||
/* Loop over allpass sections */
|
||||
for (i = 0; i < order; i += 2)
|
||||
{
|
||||
/* Output of allpass section */
|
||||
int* pstate_QSi = pstate_QS + i;
|
||||
tmp2_QS = Inlines.silk_SMLAWB(pstate_QSi[0], pstate_QSi[1] - tmp1_QS, warping_Q16);
|
||||
pstate_QSi[0] = tmp1_QS;
|
||||
pcorr_QC[i] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, *pstate_QS), 2 * QS - QC);
|
||||
/* Output of allpass section */
|
||||
tmp1_QS = Inlines.silk_SMLAWB(pstate_QSi[1], pstate_QSi[2] - tmp2_QS, warping_Q16);
|
||||
pstate_QSi[1] = tmp2_QS;
|
||||
pcorr_QC[i + 1] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp2_QS, *pstate_QS), 2 * QS - QC);
|
||||
}
|
||||
pstate_QS[order] = tmp1_QS;
|
||||
pcorr_QC[order] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, *pstate_QS), 2 * QS - QC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lsh = Inlines.silk_CLZ64(*pcorr_QC) - 35;
|
||||
lsh = Inlines.silk_LIMIT(lsh, -12 - QC, 30 - QC);
|
||||
scale.Val = -(QC + lsh);
|
||||
Inlines.OpusAssert(scale.Val >= -30 && scale.Val <= 12);
|
||||
if (lsh >= 0)
|
||||
{
|
||||
for (i = 0; i < order + 1; i++)
|
||||
{
|
||||
corr[i] = (int)(Inlines.silk_LSHIFT64(pcorr_QC[i], lsh));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < order + 1; i++)
|
||||
{
|
||||
corr[i] = (int)(Inlines.silk_RSHIFT64(corr_QC[i], -lsh));
|
||||
}
|
||||
}
|
||||
Inlines.OpusAssert(*pcorr_QC >= 0); /* If breaking, decrease QC*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
1714
Libraries/Concentus/CSharp/Concentus/Celt/Bands.cs
Normal file
1714
Libraries/Concentus/CSharp/Concentus/Celt/Bands.cs
Normal file
File diff suppressed because it is too large
Load Diff
319
Libraries/Concentus/CSharp/Concentus/Celt/CWRS.cs
Normal file
319
Libraries/Concentus/CSharp/Concentus/Celt/CWRS.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class CWRS
|
||||
{
|
||||
/*Although derived separately, the pulse vector coding scheme is equivalent to
|
||||
a Pyramid Vector Quantizer \cite{Fis86}.
|
||||
Some additional notes about an early version appear at
|
||||
http://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering
|
||||
and the definitions of some terms have evolved since that was written.
|
||||
|
||||
The conversion from a pulse vector to an integer index (encoding) and back
|
||||
(decoding) is governed by two related functions, V(N,K) and U(N,K).
|
||||
|
||||
V(N,K) = the number of combinations, with replacement, of N items, taken K
|
||||
at a time, when a sign bit is added to each item taken at least once (i.e.,
|
||||
the number of N-dimensional unit pulse vectors with K pulses).
|
||||
One way to compute this is via
|
||||
V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1,
|
||||
where choose() is the binomial function.
|
||||
A table of values for N<10 and K<10 looks like:
|
||||
V[10][10] = {
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{1, 2, 2, 2, 2, 2, 2, 2, 2, 2},
|
||||
{1, 4, 8, 12, 16, 20, 24, 28, 32, 36},
|
||||
{1, 6, 18, 38, 66, 102, 146, 198, 258, 326},
|
||||
{1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992},
|
||||
{1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290},
|
||||
{1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436},
|
||||
{1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598},
|
||||
{1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688},
|
||||
{1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146}
|
||||
};
|
||||
|
||||
U(N,K) = the number of such combinations wherein N-1 objects are taken at
|
||||
most K-1 at a time.
|
||||
This is given by
|
||||
U(N,K) = sum(k=0...K-1,V(N-1,k))
|
||||
= K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0.
|
||||
The latter expression also makes clear that U(N,K) is half the number of such
|
||||
combinations wherein the first object is taken at least once.
|
||||
Although it may not be clear from either of these definitions, U(N,K) is the
|
||||
natural function to work with when enumerating the pulse vector codebooks,
|
||||
not V(N,K).
|
||||
U(N,K) is not well-defined for N=0, but with the extension
|
||||
U(0,K) = K>0 ? 0 : 1,
|
||||
the function becomes symmetric: U(N,K) = U(K,N), with a similar table:
|
||||
U[10][10] = {
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{0, 1, 3, 5, 7, 9, 11, 13, 15, 17},
|
||||
{0, 1, 5, 13, 25, 41, 61, 85, 113, 145},
|
||||
{0, 1, 7, 25, 63, 129, 231, 377, 575, 833},
|
||||
{0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649},
|
||||
{0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073},
|
||||
{0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081},
|
||||
{0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545},
|
||||
{0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729}
|
||||
};
|
||||
|
||||
With this extension, V(N,K) may be written in terms of U(N,K):
|
||||
V(N,K) = U(N,K) + U(N,K+1)
|
||||
for all N>=0, K>=0.
|
||||
Thus U(N,K+1) represents the number of combinations where the first element
|
||||
is positive or zero, and U(N,K) represents the number of combinations where
|
||||
it is negative.
|
||||
With a large enough table of U(N,K) values, we could write O(N) encoding
|
||||
and O(min(N*log(K),N+K)) decoding routines, but such a table would be
|
||||
prohibitively large for small embedded devices (K may be as large as 32767
|
||||
for small N, and N may be as large as 200).
|
||||
|
||||
Both functions obey the same recurrence relation:
|
||||
V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1),
|
||||
U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1),
|
||||
for all N>0, K>0, with different initial conditions at N=0 or K=0.
|
||||
This allows us to construct a row of one of the tables above given the
|
||||
previous row or the next row.
|
||||
Thus we can derive O(NK) encoding and decoding routines with O(K) memory
|
||||
using only addition and subtraction.
|
||||
|
||||
When encoding, we build up from the U(2,K) row and work our way forwards.
|
||||
When decoding, we need to start at the U(N,K) row and work our way backwards,
|
||||
which requires a means of computing U(N,K).
|
||||
U(N,K) may be computed from two previous values with the same N:
|
||||
U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2)
|
||||
for all N>1, and since U(N,K) is symmetric, a similar relation holds for two
|
||||
previous values with the same K:
|
||||
U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K)
|
||||
for all K>1.
|
||||
This allows us to construct an arbitrary row of the U(N,K) table by starting
|
||||
with the first two values, which are constants.
|
||||
This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K)
|
||||
multiplications.
|
||||
Similar relations can be derived for V(N,K), but are not used here.
|
||||
|
||||
For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree
|
||||
polynomial for fixed N.
|
||||
The first few are
|
||||
U(1,K) = 1,
|
||||
U(2,K) = 2*K-1,
|
||||
U(3,K) = (2*K-2)*K+1,
|
||||
U(4,K) = (((4*K-6)*K+8)*K-3)/3,
|
||||
U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3,
|
||||
and
|
||||
V(1,K) = 2,
|
||||
V(2,K) = 4*K,
|
||||
V(3,K) = 4*K*K+2,
|
||||
V(4,K) = 8*(K*K+2)*K/3,
|
||||
V(5,K) = ((4*K*K+20)*K*K+6)/3,
|
||||
for all K>0.
|
||||
This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for
|
||||
small N (and indeed decoding is also O(N) for N<3).
|
||||
|
||||
@ARTICLE{Fis86,
|
||||
author="Thomas R. Fischer",
|
||||
title="A Pyramid Vector Quantizer",
|
||||
journal="IEEE Transactions on Information Theory",
|
||||
volume="IT-32",
|
||||
number=4,
|
||||
pages="568--583",
|
||||
month=Jul,
|
||||
year=1986
|
||||
}*/
|
||||
|
||||
internal static readonly uint[] CELT_PVQ_U_ROW =
|
||||
{
|
||||
0,176,351,525,698,870,1041,1131,1178,1207,1226,1240,1248,1254,1257
|
||||
};
|
||||
|
||||
/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/
|
||||
private static uint CELT_PVQ_U(int _n, int _k)
|
||||
{
|
||||
return Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[Inlines.IMIN(_n, _k)] + Inlines.IMAX(_n, _k)];
|
||||
}
|
||||
|
||||
|
||||
/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N
|
||||
with K pulses allocated to it.*/
|
||||
private static uint CELT_PVQ_V(int _n, int _k)
|
||||
{
|
||||
return (CELT_PVQ_U(_n, _k) + CELT_PVQ_U(_n, (_k) + 1));
|
||||
}
|
||||
|
||||
internal static uint icwrs(int _n, int[] _y)
|
||||
{
|
||||
uint i;
|
||||
int j;
|
||||
int k;
|
||||
Inlines.OpusAssert(_n >= 2);
|
||||
j = _n - 1;
|
||||
i = (_y[j] < 0) ? 1U : 0;
|
||||
k = Inlines.abs(_y[j]);
|
||||
do
|
||||
{
|
||||
j--;
|
||||
i += CELT_PVQ_U(_n - j, k);
|
||||
k += Inlines.abs(_y[j]);
|
||||
if (_y[j] < 0) i += CELT_PVQ_U(_n - j, k + 1);
|
||||
}
|
||||
while (j > 0);
|
||||
return i;
|
||||
}
|
||||
|
||||
internal static void encode_pulses(int[] _y, int _n, int _k, EntropyCoder _enc)
|
||||
{
|
||||
Inlines.OpusAssert(_k > 0);
|
||||
_enc.enc_uint(icwrs(_n, _y), CELT_PVQ_V(_n, _k));
|
||||
}
|
||||
|
||||
internal static int cwrsi(int _n, int _k, uint _i, int[] _y)
|
||||
{
|
||||
uint p;
|
||||
int s;
|
||||
int k0;
|
||||
short val;
|
||||
int yy = 0;
|
||||
int y_ptr = 0;
|
||||
Inlines.OpusAssert(_k > 0);
|
||||
Inlines.OpusAssert(_n > 1);
|
||||
|
||||
while (_n > 2)
|
||||
{
|
||||
uint q;
|
||||
/*Lots of pulses case:*/
|
||||
if (_k >= _n)
|
||||
{
|
||||
uint row;
|
||||
row = CELT_PVQ_U_ROW[_n];
|
||||
/*Are the pulses in this dimension negative?*/
|
||||
p = Tables.CELT_PVQ_U_DATA[row + _k + 1];
|
||||
s = 0 - (_i >= p ? 1 : 0);
|
||||
_i -= (p & unchecked((uint)s));
|
||||
/*Count how many pulses were placed in this dimension.*/
|
||||
k0 = _k;
|
||||
q = Tables.CELT_PVQ_U_DATA[row + _n];
|
||||
|
||||
if (q > _i)
|
||||
{
|
||||
Inlines.OpusAssert(p > q);
|
||||
_k = _n;
|
||||
|
||||
do
|
||||
{
|
||||
p = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n];
|
||||
} while (p > _i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (p = Tables.CELT_PVQ_U_DATA[row + _k]; p > _i; p = Tables.CELT_PVQ_U_DATA[row + _k])
|
||||
{
|
||||
_k--;
|
||||
}
|
||||
}
|
||||
|
||||
_i -= p;
|
||||
val = (short)((k0 - _k + s) ^ s);
|
||||
_y[y_ptr++] = val;
|
||||
yy = Inlines.MAC16_16(yy, val, val);
|
||||
}
|
||||
/*Lots of dimensions case:*/
|
||||
else
|
||||
{
|
||||
/*Are there any pulses in this dimension at all?*/
|
||||
p = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k] + _n];
|
||||
q = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k + 1] + _n];
|
||||
if (p <= _i && _i < q)
|
||||
{
|
||||
_i -= p;
|
||||
_y[y_ptr++] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Are the pulses in this dimension negative?*/
|
||||
s = 0 - (_i >= q ? 1 : 0);
|
||||
_i -= (q & unchecked((uint)s));
|
||||
/*Count how many pulses were placed in this dimension.*/
|
||||
k0 = _k;
|
||||
do
|
||||
{
|
||||
p = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n];
|
||||
} while (p > _i);
|
||||
|
||||
_i -= p;
|
||||
val = (short)((k0 - _k + s) ^ s);
|
||||
_y[y_ptr++] = val;
|
||||
yy = Inlines.MAC16_16(yy, val, val);
|
||||
}
|
||||
}
|
||||
_n--;
|
||||
}
|
||||
|
||||
/*_n==2*/
|
||||
p = (uint)(2 * _k + 1);
|
||||
s = 0 - (_i >= p ? 1 : 0);
|
||||
_i -= (p & unchecked((uint)s));
|
||||
k0 = _k;
|
||||
_k = (int)((_i + 1) >> 1);
|
||||
if (_k != 0)
|
||||
{
|
||||
_i -= (2 * (uint)_k - 1);
|
||||
}
|
||||
|
||||
val = (short)((k0 - _k + s) ^ s);
|
||||
_y[y_ptr++] = val;
|
||||
yy = Inlines.MAC16_16(yy, val, val);
|
||||
/*_n==1*/
|
||||
s = -(int)_i;
|
||||
val = (short)((_k + s) ^ s);
|
||||
_y[y_ptr] = val;
|
||||
yy = Inlines.MAC16_16(yy, val, val);
|
||||
return yy;
|
||||
}
|
||||
|
||||
internal static int decode_pulses(int[] _y, int _n, int _k, EntropyCoder _dec)
|
||||
{
|
||||
return cwrsi(_n, _k, _dec.dec_uint(CELT_PVQ_V(_n, _k)), _y);
|
||||
}
|
||||
}
|
||||
}
|
||||
1406
Libraries/Concentus/CSharp/Concentus/Celt/CeltCommon.cs
Normal file
1406
Libraries/Concentus/CSharp/Concentus/Celt/CeltCommon.cs
Normal file
File diff suppressed because it is too large
Load Diff
93
Libraries/Concentus/CSharp/Concentus/Celt/CeltConstants.cs
Normal file
93
Libraries/Concentus/CSharp/Concentus/Celt/CeltConstants.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
internal static class CeltConstants
|
||||
{
|
||||
public const int Q15ONE = 32767;
|
||||
|
||||
public const float CELT_SIG_SCALE = 32768.0f;
|
||||
|
||||
public const int SIG_SHIFT = 12;
|
||||
|
||||
public const int NORM_SCALING = 16384;
|
||||
|
||||
public const int DB_SHIFT = 10;
|
||||
|
||||
public const int EPSILON = 1;
|
||||
public const int VERY_SMALL = 0;
|
||||
public const short VERY_LARGE16 = ((short)32767);
|
||||
public const short Q15_ONE = ((short)32767);
|
||||
|
||||
public const int COMBFILTER_MAXPERIOD = 1024;
|
||||
public const int COMBFILTER_MINPERIOD = 15;
|
||||
|
||||
// from opus_decode.c
|
||||
public const int DECODE_BUFFER_SIZE = 2048;
|
||||
|
||||
// from modes.c
|
||||
/* Alternate tuning (partially derived from Vorbis) */
|
||||
public const int BITALLOC_SIZE = 11;
|
||||
public const int MAX_PERIOD = 1024;
|
||||
|
||||
// from static_modes_float.h
|
||||
public const int TOTAL_MODES = 1;
|
||||
|
||||
|
||||
// from rate.h
|
||||
public const int MAX_PSEUDO = 40;
|
||||
public const int LOG_MAX_PSEUDO = 6;
|
||||
|
||||
public const int CELT_MAX_PULSES = 128;
|
||||
|
||||
public const int MAX_FINE_BITS = 8;
|
||||
|
||||
public const int FINE_OFFSET = 21;
|
||||
public const int QTHETA_OFFSET = 4;
|
||||
public const int QTHETA_OFFSET_TWOPHASE = 16;
|
||||
|
||||
/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save
|
||||
CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The
|
||||
current value corresponds to a pitch of 66.67 Hz. */
|
||||
public const int PLC_PITCH_LAG_MAX = 720;
|
||||
|
||||
/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a
|
||||
pitch of 480 Hz. */
|
||||
public const int PLC_PITCH_LAG_MIN = 100;
|
||||
|
||||
public const int LPC_ORDER = 24;
|
||||
}
|
||||
}
|
||||
159
Libraries/Concentus/CSharp/Concentus/Celt/CeltLPC.cs
Normal file
159
Libraries/Concentus/CSharp/Concentus/Celt/CeltLPC.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class CeltLPC
|
||||
{
|
||||
internal static void celt_lpc(
|
||||
int[] _lpc, /* out: [0...p-1] LPC coefficients */
|
||||
int[] ac, /* in: [0...p] autocorrelation values */
|
||||
int p)
|
||||
{
|
||||
int i, j;
|
||||
int r;
|
||||
int error = ac[0];
|
||||
int[] lpc = new int[p];
|
||||
|
||||
//Arrays.MemSetInt(lpc, 0, p); strictly, this is not necessary since the runtime zeroes memory for us
|
||||
|
||||
if (ac[0] != 0)
|
||||
{
|
||||
for (i = 0; i < p; i++)
|
||||
{
|
||||
/* Sum up this iteration's reflection coefficient */
|
||||
int rr = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
rr += Inlines.MULT32_32_Q31(lpc[j], ac[i - j]);
|
||||
rr += Inlines.SHR32(ac[i + 1], 3);
|
||||
r = 0 - Inlines.frac_div32(Inlines.SHL32(rr, 3), error);
|
||||
/* Update LPC coefficients and total error */
|
||||
lpc[i] = Inlines.SHR32(r, 3);
|
||||
|
||||
for (j = 0; j < (i + 1) >> 1; j++)
|
||||
{
|
||||
int tmp1, tmp2;
|
||||
tmp1 = lpc[j];
|
||||
tmp2 = lpc[i - 1 - j];
|
||||
lpc[j] = tmp1 + Inlines.MULT32_32_Q31(r, tmp2);
|
||||
lpc[i - 1 - j] = tmp2 + Inlines.MULT32_32_Q31(r, tmp1);
|
||||
}
|
||||
|
||||
error = error - Inlines.MULT32_32_Q31(Inlines.MULT32_32_Q31(r, r), error);
|
||||
|
||||
/* Bail out once we get 30 dB gain */
|
||||
if (error < Inlines.SHR32(ac[0], 10))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < p; i++)
|
||||
{
|
||||
_lpc[i] = Inlines.ROUND16((lpc[i]), 16);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void celt_iir(
|
||||
int[] _x,
|
||||
int _x_ptr,
|
||||
int[] den,
|
||||
int[] _y,
|
||||
int _y_ptr,
|
||||
int N,
|
||||
int ord,
|
||||
int[] mem)
|
||||
{
|
||||
int i, j;
|
||||
int[] rden = new int[ord];
|
||||
int[] y = new int[N + ord];
|
||||
Inlines.OpusAssert((ord & 3) == 0);
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
rden[i] = den[ord - i - 1];
|
||||
for (i = 0; i < ord; i++)
|
||||
y[i] = (0 - mem[ord - i - 1]);
|
||||
for (; i < N + ord; i++)
|
||||
y[i] = 0;
|
||||
for (i = 0; i < N - 3; i += 4)
|
||||
{
|
||||
/* Unroll by 4 as if it were an FIR filter */
|
||||
int sum0 = _x[_x_ptr + i];
|
||||
int sum1 = _x[_x_ptr + i + 1];
|
||||
int sum2 = _x[_x_ptr + i + 2];
|
||||
int sum3 = _x[_x_ptr + i + 3];
|
||||
Kernels.xcorr_kernel(rden, y, i, ref sum0, ref sum1, ref sum2, ref sum3, ord);
|
||||
|
||||
/* Patch up the result to compensate for the fact that this is an IIR */
|
||||
y[i + ord] = (0 - Inlines.ROUND16((sum0), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i] = sum0;
|
||||
sum1 = Inlines.MAC16_16(sum1, y[i + ord], den[0]);
|
||||
y[i + ord + 1] = (0 - Inlines.ROUND16((sum1), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i + 1] = sum1;
|
||||
sum2 = Inlines.MAC16_16(sum2, y[i + ord + 1], den[0]);
|
||||
sum2 = Inlines.MAC16_16(sum2, y[i + ord], den[1]);
|
||||
y[i + ord + 2] = (0 - Inlines.ROUND16((sum2), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i + 2] = sum2;
|
||||
|
||||
sum3 = Inlines.MAC16_16(sum3, y[i + ord + 2], den[0]);
|
||||
sum3 = Inlines.MAC16_16(sum3, y[i + ord + 1], den[1]);
|
||||
sum3 = Inlines.MAC16_16(sum3, y[i + ord], den[2]);
|
||||
y[i + ord + 3] = (0 - Inlines.ROUND16((sum3), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i + 3] = sum3;
|
||||
}
|
||||
for (; i < N; i++)
|
||||
{
|
||||
int sum = _x[_x_ptr + i];
|
||||
for (j = 0; j < ord; j++)
|
||||
sum -= Inlines.MULT16_16(rden[j], y[i + j]);
|
||||
y[i + ord] = Inlines.ROUND16((sum), CeltConstants.SIG_SHIFT);
|
||||
_y[_y_ptr + i] = sum;
|
||||
}
|
||||
for (i = 0; i < ord; i++)
|
||||
mem[i] = (_y[_y_ptr + N - i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
163
Libraries/Concentus/CSharp/Concentus/Celt/CeltLPCUnsafe.cs
Normal file
163
Libraries/Concentus/CSharp/Concentus/Celt/CeltLPCUnsafe.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class CeltLPC
|
||||
{
|
||||
internal static void celt_lpc(
|
||||
int[] _lpc, /* out: [0...p-1] LPC coefficients */
|
||||
int[] ac, /* in: [0...p] autocorrelation values */
|
||||
int p)
|
||||
{
|
||||
int i, j;
|
||||
int r;
|
||||
int error = ac[0];
|
||||
int[] lpc = new int[p];
|
||||
|
||||
//Arrays.MemSetInt(lpc, 0, p); strictly, this is not necessary since the runtime zeroes memory for us
|
||||
|
||||
if (ac[0] != 0)
|
||||
{
|
||||
for (i = 0; i < p; i++)
|
||||
{
|
||||
/* Sum up this iteration's reflection coefficient */
|
||||
int rr = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
rr += Inlines.MULT32_32_Q31(lpc[j], ac[i - j]);
|
||||
rr += Inlines.SHR32(ac[i + 1], 3);
|
||||
r = 0 - Inlines.frac_div32(Inlines.SHL32(rr, 3), error);
|
||||
/* Update LPC coefficients and total error */
|
||||
lpc[i] = Inlines.SHR32(r, 3);
|
||||
|
||||
for (j = 0; j < (i + 1) >> 1; j++)
|
||||
{
|
||||
int tmp1, tmp2;
|
||||
tmp1 = lpc[j];
|
||||
tmp2 = lpc[i - 1 - j];
|
||||
lpc[j] = tmp1 + Inlines.MULT32_32_Q31(r, tmp2);
|
||||
lpc[i - 1 - j] = tmp2 + Inlines.MULT32_32_Q31(r, tmp1);
|
||||
}
|
||||
|
||||
error = error - Inlines.MULT32_32_Q31(Inlines.MULT32_32_Q31(r, r), error);
|
||||
|
||||
/* Bail out once we get 30 dB gain */
|
||||
if (error < Inlines.SHR32(ac[0], 10))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < p; i++)
|
||||
{
|
||||
_lpc[i] = Inlines.ROUND16((lpc[i]), 16);
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void celt_iir(
|
||||
int[] _x,
|
||||
int _x_ptr,
|
||||
int[] den,
|
||||
int[] _y,
|
||||
int _y_ptr,
|
||||
int N,
|
||||
int ord,
|
||||
int[] mem)
|
||||
{
|
||||
int i, j;
|
||||
int[] rden = new int[ord];
|
||||
int[] y = new int[N + ord];
|
||||
Inlines.OpusAssert((ord & 3) == 0);
|
||||
|
||||
fixed (int* prden = rden, py_base = y)
|
||||
{
|
||||
for (i = 0; i < ord; i++)
|
||||
rden[i] = den[ord - i - 1];
|
||||
for (i = 0; i < ord; i++)
|
||||
y[i] = (0 - mem[ord - i - 1]);
|
||||
for (; i < N + ord; i++)
|
||||
y[i] = 0;
|
||||
for (i = 0; i < N - 3; i += 4)
|
||||
{
|
||||
int* py = py_base + i;
|
||||
/* Unroll by 4 as if it were an FIR filter */
|
||||
int sum0 = _x[_x_ptr + i];
|
||||
int sum1 = _x[_x_ptr + i + 1];
|
||||
int sum2 = _x[_x_ptr + i + 2];
|
||||
int sum3 = _x[_x_ptr + i + 3];
|
||||
Kernels.xcorr_kernel(prden, py, ref sum0, ref sum1, ref sum2, ref sum3, ord);
|
||||
|
||||
/* Patch up the result to compensate for the fact that this is an IIR */
|
||||
y[i + ord] = (0 - Inlines.ROUND16((sum0), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i] = sum0;
|
||||
sum1 = Inlines.MAC16_16(sum1, y[i + ord], den[0]);
|
||||
y[i + ord + 1] = (0 - Inlines.ROUND16((sum1), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i + 1] = sum1;
|
||||
sum2 = Inlines.MAC16_16(sum2, y[i + ord + 1], den[0]);
|
||||
sum2 = Inlines.MAC16_16(sum2, y[i + ord], den[1]);
|
||||
y[i + ord + 2] = (0 - Inlines.ROUND16((sum2), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i + 2] = sum2;
|
||||
|
||||
sum3 = Inlines.MAC16_16(sum3, y[i + ord + 2], den[0]);
|
||||
sum3 = Inlines.MAC16_16(sum3, y[i + ord + 1], den[1]);
|
||||
sum3 = Inlines.MAC16_16(sum3, y[i + ord], den[2]);
|
||||
y[i + ord + 3] = (0 - Inlines.ROUND16((sum3), CeltConstants.SIG_SHIFT));
|
||||
_y[_y_ptr + i + 3] = sum3;
|
||||
}
|
||||
for (; i < N; i++)
|
||||
{
|
||||
int sum = _x[_x_ptr + i];
|
||||
for (j = 0; j < ord; j++)
|
||||
sum -= Inlines.MULT16_16(rden[j], y[i + j]);
|
||||
y[i + ord] = Inlines.ROUND16((sum), CeltConstants.SIG_SHIFT);
|
||||
_y[_y_ptr + i] = sum;
|
||||
}
|
||||
for (i = 0; i < ord; i++)
|
||||
mem[i] = (_y[_y_ptr + N - i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
154
Libraries/Concentus/CSharp/Concentus/Celt/CeltPitchXCorr.cs
Normal file
154
Libraries/Concentus/CSharp/Concentus/Celt/CeltPitchXCorr.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
internal static class CeltPitchXCorr
|
||||
{
|
||||
internal static int pitch_xcorr(
|
||||
int[] _x,
|
||||
int[] _y,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
Kernels.xcorr_kernel(_x, _y, i, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
xcorr[i] = sum0;
|
||||
xcorr[i + 1] = sum1;
|
||||
xcorr[i + 2] = sum2;
|
||||
xcorr[i + 3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
int inner_sum = Kernels.celt_inner_prod(_x, 0, _y, i, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
return maxcorr;
|
||||
}
|
||||
|
||||
internal static int pitch_xcorr(
|
||||
short[] _x,
|
||||
int _x_ptr,
|
||||
short[] _y,
|
||||
int _y_ptr,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
Kernels.xcorr_kernel(_x, _x_ptr, _y, _y_ptr + i, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
|
||||
xcorr[i] = sum0;
|
||||
xcorr[i + 1] = sum1;
|
||||
xcorr[i + 2] = sum2;
|
||||
xcorr[i + 3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
int inner_sum = Kernels.celt_inner_prod(_x, _x_ptr, _y, _y_ptr + i, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
return maxcorr;
|
||||
}
|
||||
|
||||
internal static int pitch_xcorr(
|
||||
short[] _x,
|
||||
short[] _y,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
Kernels.xcorr_kernel(_x, 0, _y, i, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
|
||||
xcorr[i] = sum0;
|
||||
xcorr[i + 1] = sum1;
|
||||
xcorr[i + 2] = sum2;
|
||||
xcorr[i + 3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
int inner_sum = Kernels.celt_inner_prod(_x, _y, i, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
return maxcorr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,255 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
internal static class CeltPitchXCorr
|
||||
{
|
||||
internal static unsafe int pitch_xcorr(
|
||||
int[] _x,
|
||||
int[] _y,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
fixed (int* py_base = _y, px = _x, px_base = _x)
|
||||
{
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
int* py = py_base + i;
|
||||
Kernels.xcorr_kernel(px, py, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
xcorr[i] = sum0;
|
||||
xcorr[i + 1] = sum1;
|
||||
xcorr[i + 2] = sum2;
|
||||
xcorr[i + 3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
int* py = py_base + i;
|
||||
int inner_sum = Kernels.celt_inner_prod(px_base, py, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
}
|
||||
|
||||
return maxcorr;
|
||||
}
|
||||
|
||||
internal static unsafe int pitch_xcorr(
|
||||
int* _x,
|
||||
int* _y,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
int* py = _y + i;
|
||||
Kernels.xcorr_kernel(_x, py, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
xcorr[i] = sum0;
|
||||
xcorr[i + 1] = sum1;
|
||||
xcorr[i + 2] = sum2;
|
||||
xcorr[i + 3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
int* py = _y + i;
|
||||
int inner_sum = Kernels.celt_inner_prod(_x, py, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
|
||||
return maxcorr;
|
||||
}
|
||||
|
||||
internal static unsafe int pitch_xcorr(
|
||||
short[] _x,
|
||||
int _x_ptr,
|
||||
short[] _y,
|
||||
int _y_ptr,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
fixed (int* pxcorr = xcorr)
|
||||
{
|
||||
fixed (short* px_base = _x, py_base = _y)
|
||||
{
|
||||
short* px = px_base + _x_ptr;
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
short* py = py_base + _y_ptr + i;
|
||||
Kernels.xcorr_kernel(px, py, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
|
||||
int* pxcorr2 = pxcorr + i;
|
||||
pxcorr2[0] = sum0;
|
||||
pxcorr2[1] = sum1;
|
||||
pxcorr2[2] = sum2;
|
||||
pxcorr2[3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
short* py = py_base + _y_ptr + i;
|
||||
int inner_sum = Kernels.celt_inner_prod(px, py, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxcorr;
|
||||
}
|
||||
|
||||
internal static unsafe int pitch_xcorr(
|
||||
short[] _x,
|
||||
short[] _y,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
fixed (int* pxcorr_base = xcorr)
|
||||
{
|
||||
fixed (short* px = _x, py_base = _y)
|
||||
{
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
short* py = py_base + i;
|
||||
Kernels.xcorr_kernel(px, py, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
|
||||
int* pxcorr = pxcorr_base + i;
|
||||
pxcorr[0] = sum0;
|
||||
pxcorr[1] = sum1;
|
||||
pxcorr[2] = sum2;
|
||||
pxcorr[3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
short* py = py_base + i;
|
||||
int inner_sum = Kernels.celt_inner_prod(px, py, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
return maxcorr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe int pitch_xcorr(
|
||||
short* px,
|
||||
short* py,
|
||||
int[] xcorr,
|
||||
int len,
|
||||
int max_pitch)
|
||||
{
|
||||
int i;
|
||||
int maxcorr = 1;
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
fixed (int* pxcorr_base = xcorr)
|
||||
{
|
||||
for (i = 0; i < max_pitch - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
short* py2 = py + i;
|
||||
Kernels.xcorr_kernel(px, py2, ref sum0, ref sum1, ref sum2, ref sum3, len);
|
||||
int* pxcorr = pxcorr_base + i;
|
||||
pxcorr[0] = sum0;
|
||||
pxcorr[1] = sum1;
|
||||
pxcorr[2] = sum2;
|
||||
pxcorr[3] = sum3;
|
||||
sum0 = Inlines.MAX32(sum0, sum1);
|
||||
sum2 = Inlines.MAX32(sum2, sum3);
|
||||
sum0 = Inlines.MAX32(sum0, sum2);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum0);
|
||||
}
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++)
|
||||
{
|
||||
short* py2 = py + i;
|
||||
int inner_sum = Kernels.celt_inner_prod(px, py2, len);
|
||||
xcorr[i] = inner_sum;
|
||||
maxcorr = Inlines.MAX32(maxcorr, inner_sum);
|
||||
}
|
||||
return maxcorr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
45
Libraries/Concentus/CSharp/Concentus/Celt/Enums/Spread.cs
Normal file
45
Libraries/Concentus/CSharp/Concentus/Celt/Enums/Spread.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt.Enums
|
||||
{
|
||||
internal static class Spread
|
||||
{
|
||||
public const int SPREAD_NONE = 0;
|
||||
public const int SPREAD_LIGHT = 1;
|
||||
public const int SPREAD_NORMAL = 2;
|
||||
public const int SPREAD_AGGRESSIVE = 3;
|
||||
}
|
||||
}
|
||||
354
Libraries/Concentus/CSharp/Concentus/Celt/Kernels.cs
Normal file
354
Libraries/Concentus/CSharp/Concentus/Celt/Kernels.cs
Normal file
@@ -0,0 +1,354 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Kernels
|
||||
{
|
||||
internal static void celt_fir(
|
||||
short[] x,
|
||||
int x_ptr,
|
||||
short[] num,
|
||||
short[] y,
|
||||
int y_ptr,
|
||||
int N,
|
||||
int ord,
|
||||
short[] mem
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
short[] rnum = new short[ord];
|
||||
short[] local_x = new short[N + ord];
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
rnum[i] = num[ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
local_x[i] = mem[ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
local_x[i + ord] = x[x_ptr + i];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
mem[i] = x[x_ptr + N - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < N - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
xcorr_kernel(rnum, 0, local_x, i, ref sum0, ref sum1, ref sum2, ref sum3, ord);
|
||||
y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum0, CeltConstants.SIG_SHIFT))));
|
||||
y[y_ptr + i + 1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 1]), Inlines.PSHR32(sum1, CeltConstants.SIG_SHIFT))));
|
||||
y[y_ptr + i + 2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 2]), Inlines.PSHR32(sum2, CeltConstants.SIG_SHIFT))));
|
||||
y[y_ptr + i + 3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 3]), Inlines.PSHR32(sum3, CeltConstants.SIG_SHIFT))));
|
||||
}
|
||||
|
||||
for (; i < N; i++)
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
for (j = 0; j < ord; j++)
|
||||
{
|
||||
sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]);
|
||||
}
|
||||
|
||||
y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT))));
|
||||
}
|
||||
}
|
||||
|
||||
internal static void celt_fir(
|
||||
int[] x,
|
||||
int x_ptr,
|
||||
int[] num,
|
||||
int num_ptr,
|
||||
int[] y,
|
||||
int y_ptr,
|
||||
int N,
|
||||
int ord,
|
||||
int[] mem
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
int[] rnum = new int[ord];
|
||||
int[] local_x = new int[N + ord];
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
rnum[i] = num[num_ptr + ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
local_x[i] = mem[ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
local_x[i + ord] = x[x_ptr + i];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
mem[i] = x[x_ptr + N - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < N - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
xcorr_kernel(rnum, local_x, i, ref sum0, ref sum1, ref sum2, ref sum3, ord);
|
||||
y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum0, CeltConstants.SIG_SHIFT))));
|
||||
y[y_ptr + i + 1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 1]), Inlines.PSHR32(sum1, CeltConstants.SIG_SHIFT))));
|
||||
y[y_ptr + i + 2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 2]), Inlines.PSHR32(sum2, CeltConstants.SIG_SHIFT))));
|
||||
y[y_ptr + i + 3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 3]), Inlines.PSHR32(sum3, CeltConstants.SIG_SHIFT))));
|
||||
}
|
||||
|
||||
for (; i < N; i++)
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
for (j = 0; j < ord; j++)
|
||||
{
|
||||
sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]);
|
||||
}
|
||||
|
||||
y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT))));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OPT: This is the kernel you really want to optimize. It gets used a lot by the prefilter and by the PLC.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <param name="sum0"></param>
|
||||
/// <param name="len"></param>
|
||||
internal static void xcorr_kernel(short[] x, int x_ptr, short[] y, int y_ptr, ref int sum0, ref int sum1, ref int sum2, ref int sum3, int len)
|
||||
{
|
||||
int j;
|
||||
short y_0, y_1, y_2, y_3;
|
||||
Inlines.OpusAssert(len >= 3);
|
||||
y_3 = 0; /* gcc doesn't realize that y_3 can't be used uninitialized */
|
||||
y_0 = y[y_ptr++];
|
||||
y_1 = y[y_ptr++];
|
||||
y_2 = y[y_ptr++];
|
||||
for (j = 0; j < len - 3; j += 4)
|
||||
{
|
||||
short tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_3 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
tmp = x[x_ptr++];
|
||||
y_0 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
tmp = x[x_ptr++];
|
||||
y_1 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
tmp = x[x_ptr++];
|
||||
y_2 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_3);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_0);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_1);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_2);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
short tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_3 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
short tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_0 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
}
|
||||
if (j < len)
|
||||
{
|
||||
short tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_1 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void xcorr_kernel(int[] x, int[] y, int y_ptr, ref int sum0, ref int sum1, ref int sum2, ref int sum3, int len)
|
||||
{
|
||||
int j;
|
||||
int y_0, y_1, y_2, y_3;
|
||||
int x_ptr = 0;
|
||||
Inlines.OpusAssert(len >= 3);
|
||||
y_3 = 0; /* gcc doesn't realize that y_3 can't be used uninitialized */
|
||||
y_0 = y[y_ptr++];
|
||||
y_1 = y[y_ptr++];
|
||||
y_2 = y[y_ptr++];
|
||||
for (j = 0; j < len - 3; j += 4)
|
||||
{
|
||||
int tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_3 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
tmp = x[x_ptr++];
|
||||
y_0 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
tmp = x[x_ptr++];
|
||||
y_1 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
tmp = x[x_ptr++];
|
||||
y_2 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_3);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_0);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_1);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_2);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
int tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_3 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
int tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_0 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
}
|
||||
if (j < len)
|
||||
{
|
||||
int tmp;
|
||||
tmp = x[x_ptr++];
|
||||
y_1 = y[y_ptr++];
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
}
|
||||
}
|
||||
|
||||
internal static int celt_inner_prod(short[] x, int x_ptr, short[] y, int y_ptr, int N)
|
||||
{
|
||||
int i;
|
||||
int xy = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
xy = Inlines.MAC16_16(xy, x[x_ptr + i], y[y_ptr + i]);
|
||||
return xy;
|
||||
}
|
||||
|
||||
internal static int celt_inner_prod(short[] x, short[] y, int y_ptr, int N)
|
||||
{
|
||||
int i;
|
||||
int xy = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
xy = Inlines.MAC16_16(xy, x[i], y[y_ptr + i]);
|
||||
return xy;
|
||||
}
|
||||
|
||||
internal static int celt_inner_prod(int[] x, int x_ptr, int[] y, int y_ptr, int N)
|
||||
{
|
||||
int i;
|
||||
int xy = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
xy = Inlines.MAC16_16(xy, x[x_ptr + i], y[y_ptr + i]);
|
||||
return xy;
|
||||
}
|
||||
|
||||
internal static void dual_inner_prod(int[] x, int x_ptr, int[] y01,int y01_ptr, int[] y02, int y02_ptr, int N, out int xy1, out int xy2)
|
||||
{
|
||||
int i;
|
||||
int xy01 = 0;
|
||||
int xy02 = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
xy01 = Inlines.MAC16_16(xy01, x[x_ptr + i], y01[y01_ptr + i]);
|
||||
xy02 = Inlines.MAC16_16(xy02, x[x_ptr + i], y02[y02_ptr + i]);
|
||||
}
|
||||
xy1 = xy01;
|
||||
xy2 = xy02;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
352
Libraries/Concentus/CSharp/Concentus/Celt/KernelsUnsafe.cs
Normal file
352
Libraries/Concentus/CSharp/Concentus/Celt/KernelsUnsafe.cs
Normal file
@@ -0,0 +1,352 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Kernels
|
||||
{
|
||||
internal static unsafe void celt_fir(
|
||||
short* x,
|
||||
short[] num,
|
||||
short* y,
|
||||
int N,
|
||||
int ord,
|
||||
short[] mem
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
short[] rnum = new short[ord];
|
||||
short[] local_x = new short[N + ord];
|
||||
fixed (short* prnum = rnum, plocal_x = local_x)
|
||||
{
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
prnum[i] = num[ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
plocal_x[i] = mem[ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
plocal_x[i + ord] = x[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
mem[i] = x[N - i - 1];
|
||||
}
|
||||
|
||||
short* py = y;
|
||||
for (i = 0; i < N - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
short* local_x2 = plocal_x + i;
|
||||
xcorr_kernel(prnum, local_x2, ref sum0, ref sum1, ref sum2, ref sum3, ord);
|
||||
py[0] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(sum0, CeltConstants.SIG_SHIFT))));
|
||||
py[1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i + 1]), Inlines.PSHR32(sum1, CeltConstants.SIG_SHIFT))));
|
||||
py[2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i + 2]), Inlines.PSHR32(sum2, CeltConstants.SIG_SHIFT))));
|
||||
py[3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i + 3]), Inlines.PSHR32(sum3, CeltConstants.SIG_SHIFT))));
|
||||
py += 4;
|
||||
}
|
||||
|
||||
for (; i < N; i++)
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
for (j = 0; j < ord; j++)
|
||||
{
|
||||
sum = Inlines.MAC16_16(sum, prnum[j], plocal_x[i + j]);
|
||||
}
|
||||
|
||||
*py = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT))));
|
||||
py++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void celt_fir(
|
||||
int* px,
|
||||
int* pnum,
|
||||
int* py,
|
||||
int N,
|
||||
int ord,
|
||||
int[] mem
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
int[] rnum = new int[ord];
|
||||
int[] local_x = new int[N + ord];
|
||||
fixed (int* prnum = rnum, plocal_x_base = local_x)
|
||||
{
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
rnum[i] = pnum[ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
local_x[i] = mem[ord - i - 1];
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
local_x[i + ord] = px[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < ord; i++)
|
||||
{
|
||||
mem[i] = px[N - i - 1];
|
||||
}
|
||||
|
||||
int* px2 = px;
|
||||
for (i = 0; i < N - 3; i += 4)
|
||||
{
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
||||
int* plocal_x = plocal_x_base + i;
|
||||
xcorr_kernel(prnum, plocal_x, ref sum0, ref sum1, ref sum2, ref sum3, ord);
|
||||
py[0] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[0]), Inlines.PSHR32(sum0, CeltConstants.SIG_SHIFT))));
|
||||
py[1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[1]), Inlines.PSHR32(sum1, CeltConstants.SIG_SHIFT))));
|
||||
py[2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[2]), Inlines.PSHR32(sum2, CeltConstants.SIG_SHIFT))));
|
||||
py[3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[3]), Inlines.PSHR32(sum3, CeltConstants.SIG_SHIFT))));
|
||||
py += 4;
|
||||
px2 += 4;
|
||||
}
|
||||
|
||||
for (; i < N; i++)
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
for (j = 0; j < ord; j++)
|
||||
{
|
||||
sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]);
|
||||
}
|
||||
|
||||
*py = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px[i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT))));
|
||||
py++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OPT: This is the kernel you really want to optimize. It gets used a lot by the prefilter and by the PLC.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="py"></param>
|
||||
/// <param name="sum0"></param>
|
||||
/// <param name="len"></param>
|
||||
internal unsafe static void xcorr_kernel(short* x, short* py, ref int sum0, ref int sum1, ref int sum2, ref int sum3, int len)
|
||||
{
|
||||
int j;
|
||||
short y_0, y_1, y_2, y_3;
|
||||
Inlines.OpusAssert(len >= 3);
|
||||
y_3 = 0; /* gcc doesn't realize that y_3 can't be used uninitialized */
|
||||
y_0 = *py++;
|
||||
y_1 = *py++;
|
||||
y_2 = *py++;
|
||||
for (j = 0; j < len - 3; j += 4)
|
||||
{
|
||||
short tmp;
|
||||
tmp = *x++;
|
||||
y_3 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
tmp = *x++;
|
||||
y_0 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
tmp = *x++;
|
||||
y_1 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
tmp = *x++;
|
||||
y_2 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_3);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_0);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_1);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_2);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
short tmp;
|
||||
tmp = *x++;
|
||||
y_3 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
short tmp;
|
||||
tmp = *x++;
|
||||
y_0 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
}
|
||||
if (j < len)
|
||||
{
|
||||
short tmp;
|
||||
tmp = *x++;
|
||||
y_1 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe static void xcorr_kernel(int* px, int* py, ref int sum0, ref int sum1, ref int sum2, ref int sum3, int len)
|
||||
{
|
||||
int j;
|
||||
int y_0, y_1, y_2, y_3;
|
||||
Inlines.OpusAssert(len >= 3);
|
||||
y_3 = 0; /* gcc doesn't realize that y_3 can't be used uninitialized */
|
||||
y_0 = *py++;
|
||||
y_1 = *py++;
|
||||
y_2 = *py++;
|
||||
for (j = 0; j < len - 3; j += 4)
|
||||
{
|
||||
int tmp;
|
||||
tmp = *px++;
|
||||
y_3 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
tmp = *px++;
|
||||
y_0 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
tmp = *px++;
|
||||
y_1 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
tmp = *px++;
|
||||
y_2 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_3);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_0);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_1);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_2);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
int tmp;
|
||||
tmp = *px++;
|
||||
y_3 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_0);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_1);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_2);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_3);
|
||||
}
|
||||
if (j++ < len)
|
||||
{
|
||||
int tmp;
|
||||
tmp = *px++;
|
||||
y_0 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_1);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_2);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_3);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_0);
|
||||
}
|
||||
if (j < len)
|
||||
{
|
||||
int tmp;
|
||||
tmp = *px++;
|
||||
y_1 = *py++;
|
||||
sum0 = Inlines.MAC16_16(sum0, tmp, y_2);
|
||||
sum1 = Inlines.MAC16_16(sum1, tmp, y_3);
|
||||
sum2 = Inlines.MAC16_16(sum2, tmp, y_0);
|
||||
sum3 = Inlines.MAC16_16(sum3, tmp, y_1);
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe int celt_inner_prod(short* x, short* y, int N)
|
||||
{
|
||||
int i;
|
||||
int xy = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
xy = Inlines.MAC16_16(xy, x[i], y[i]);
|
||||
return xy;
|
||||
}
|
||||
|
||||
internal static unsafe int celt_inner_prod(int* x, int* y, int N)
|
||||
{
|
||||
int i;
|
||||
int xy = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
xy = Inlines.MAC16_16(xy, x[i], y[i]);
|
||||
return xy;
|
||||
}
|
||||
|
||||
internal static unsafe void dual_inner_prod(int* x, int* y01, int* y02, int N, out int xy1, out int xy2)
|
||||
{
|
||||
int i;
|
||||
int xy01 = 0;
|
||||
int xy02 = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
xy01 = Inlines.MAC16_16(xy01, x[i], y01[i]);
|
||||
xy02 = Inlines.MAC16_16(xy02, x[i], y02[i]);
|
||||
}
|
||||
xy1 = xy01;
|
||||
xy2 = xy02;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
455
Libraries/Concentus/CSharp/Concentus/Celt/KissFFT.cs
Normal file
455
Libraries/Concentus/CSharp/Concentus/Celt/KissFFT.cs
Normal file
@@ -0,0 +1,455 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Copyright (c) 2003-2004, Mark Borgerding
|
||||
Modified from KISS-FFT by Jean-Marc Valin
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* This code is originally from Mark Borgerding's KISS-FFT but has been
|
||||
heavily modified to better suit Opus */
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
internal static class KissFFT
|
||||
{
|
||||
//public const int SAMP_MAX = 2147483647;
|
||||
//public const int SAMP_MIN = 0 - SAMP_MAX;
|
||||
//public const int TWID_MAX = 32767;
|
||||
//public const int TRIG_UPSCALE = 1;
|
||||
|
||||
internal const int MAXFACTORS = 8;
|
||||
|
||||
internal static int S_MUL(int a, int b)
|
||||
{
|
||||
return Inlines.MULT16_32_Q15(b, a);
|
||||
}
|
||||
|
||||
internal static int S_MUL(int a, short b)
|
||||
{
|
||||
return Inlines.MULT16_32_Q15(b, a);
|
||||
}
|
||||
|
||||
internal static int HALF_OF(int x)
|
||||
{
|
||||
return x >> 1;
|
||||
}
|
||||
|
||||
internal static void kf_bfly2(int[] Fout, int fout_ptr, int m, int N)
|
||||
{
|
||||
int Fout2;
|
||||
int i;
|
||||
{
|
||||
short tw;
|
||||
tw = ((short)(0.5 + (0.7071067812f) * (((int)1) << (15))))/*Inlines.QCONST16(0.7071067812f, 15)*/;
|
||||
/* We know that m==4 here because the radix-2 is just after a radix-4 */
|
||||
Inlines.OpusAssert(m == 4);
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
int t_r, t_i;
|
||||
Fout2 = fout_ptr + 8;
|
||||
t_r = Fout[Fout2 + 0];
|
||||
t_i = Fout[Fout2 + 1];
|
||||
Fout[Fout2 + 0] = Fout[fout_ptr + 0] - t_r;
|
||||
Fout[Fout2 + 1] = Fout[fout_ptr + 1] - t_i;
|
||||
Fout[fout_ptr + 0] += t_r;
|
||||
Fout[fout_ptr + 1] += t_i;
|
||||
|
||||
t_r = S_MUL(Fout[Fout2 + 2] + Fout[Fout2 + 3], tw);
|
||||
t_i = S_MUL(Fout[Fout2 + 3] - Fout[Fout2 + 2], tw);
|
||||
Fout[Fout2 + 2] = Fout[fout_ptr + 2] - t_r;
|
||||
Fout[Fout2 + 3] = Fout[fout_ptr + 3] - t_i;
|
||||
Fout[fout_ptr + 2] += t_r;
|
||||
Fout[fout_ptr + 3] += t_i;
|
||||
|
||||
t_r = Fout[Fout2 + 5];
|
||||
t_i = 0 - Fout[Fout2 + 4];
|
||||
Fout[Fout2 + 4] = Fout[fout_ptr + 4] - t_r;
|
||||
Fout[Fout2 + 5] = Fout[fout_ptr + 5] - t_i;
|
||||
Fout[fout_ptr + 4] += t_r;
|
||||
Fout[fout_ptr + 5] += t_i;
|
||||
|
||||
t_r = S_MUL(Fout[Fout2 + 7] - Fout[Fout2 + 6], tw);
|
||||
t_i = S_MUL(0 - Fout[Fout2 + 7] - Fout[Fout2 + 6], tw);
|
||||
Fout[Fout2 + 6] = Fout[fout_ptr + 6] - t_r;
|
||||
Fout[Fout2 + 7] = Fout[fout_ptr + 7] - t_i;
|
||||
Fout[fout_ptr + 6] += t_r;
|
||||
Fout[fout_ptr + 7] += t_i;
|
||||
|
||||
fout_ptr += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void kf_bfly4(
|
||||
int[] Fout,
|
||||
int fout_ptr,
|
||||
int fstride,
|
||||
FFTState st,
|
||||
int m,
|
||||
int N,
|
||||
int mm)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (m == 1)
|
||||
{
|
||||
/* Degenerate case where all the twiddles are 1. */
|
||||
int scratch0, scratch1, scratch2, scratch3;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
scratch0 = Fout[fout_ptr + 0] - Fout[fout_ptr + 4];
|
||||
scratch1 = Fout[fout_ptr + 1] - Fout[fout_ptr + 5];
|
||||
Fout[fout_ptr + 0] += Fout[fout_ptr + 4];
|
||||
Fout[fout_ptr + 1] += Fout[fout_ptr + 5];
|
||||
scratch2 = Fout[fout_ptr + 2] + Fout[fout_ptr + 6];
|
||||
scratch3 = Fout[fout_ptr + 3] + Fout[fout_ptr + 7];
|
||||
Fout[fout_ptr + 4] = Fout[fout_ptr + 0] - scratch2;
|
||||
Fout[fout_ptr + 5] = Fout[fout_ptr + 1] - scratch3;
|
||||
Fout[fout_ptr + 0] += scratch2;
|
||||
Fout[fout_ptr + 1] += scratch3;
|
||||
scratch2 = Fout[fout_ptr + 2] - Fout[fout_ptr + 6];
|
||||
scratch3 = Fout[fout_ptr + 3] - Fout[fout_ptr + 7];
|
||||
Fout[fout_ptr + 2] = scratch0 + scratch3;
|
||||
Fout[fout_ptr + 3] = scratch1 - scratch2;
|
||||
Fout[fout_ptr + 6] = scratch0 - scratch3;
|
||||
Fout[fout_ptr + 7] = scratch1 + scratch2;
|
||||
fout_ptr += 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int j;
|
||||
int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5, scratch6, scratch7, scratch8, scratch9, scratch10, scratch11;
|
||||
int tw1, tw2, tw3;
|
||||
int Fout_beg = fout_ptr;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
fout_ptr = Fout_beg + 2 * i * mm;
|
||||
int m1 = fout_ptr + (2 * m);
|
||||
int m2 = fout_ptr + (4 * m);
|
||||
int m3 = fout_ptr + (6 * m);
|
||||
tw3 = tw2 = tw1 = 0;
|
||||
/* m is guaranteed to be a multiple of 4. */
|
||||
for (j = 0; j < m; j++)
|
||||
{
|
||||
scratch0 = (S_MUL(Fout[m1], st.twiddles[tw1 ]) - S_MUL(Fout[m1 + 1], st.twiddles[tw1 + 1]));
|
||||
scratch1 = (S_MUL(Fout[m1], st.twiddles[tw1 + 1]) + S_MUL(Fout[m1 + 1], st.twiddles[tw1]));
|
||||
scratch2 = (S_MUL(Fout[m2], st.twiddles[tw2 ]) - S_MUL(Fout[m2 + 1], st.twiddles[tw2 + 1]));
|
||||
scratch3 = (S_MUL(Fout[m2], st.twiddles[tw2 + 1]) + S_MUL(Fout[m2 + 1], st.twiddles[tw2]));
|
||||
scratch4 = (S_MUL(Fout[m3], st.twiddles[tw3 ]) - S_MUL(Fout[m3 + 1], st.twiddles[tw3 + 1]));
|
||||
scratch5 = (S_MUL(Fout[m3], st.twiddles[tw3 + 1]) + S_MUL(Fout[m3 + 1], st.twiddles[tw3]));
|
||||
scratch10 = Fout[fout_ptr] - scratch2;
|
||||
scratch11 = Fout[fout_ptr + 1] - scratch3;
|
||||
Fout[fout_ptr] += scratch2;
|
||||
Fout[fout_ptr + 1] += scratch3;
|
||||
scratch6 = scratch0 + scratch4;
|
||||
scratch7 = scratch1 + scratch5;
|
||||
scratch8 = scratch0 - scratch4;
|
||||
scratch9 = scratch1 - scratch5;
|
||||
Fout[m2] = Fout[fout_ptr] - scratch6;
|
||||
Fout[m2 + 1] = Fout[fout_ptr + 1] - scratch7;
|
||||
tw1 += fstride * 2;
|
||||
tw2 += fstride * 4;
|
||||
tw3 += fstride * 6;
|
||||
Fout[fout_ptr] += scratch6;
|
||||
Fout[fout_ptr + 1] += scratch7;
|
||||
Fout[m1] = scratch10 + scratch9;
|
||||
Fout[m1 + 1] = scratch11 - scratch8;
|
||||
Fout[m3] = scratch10 - scratch9;
|
||||
Fout[m3 + 1] = scratch11 + scratch8;
|
||||
fout_ptr += 2;
|
||||
m1 += 2;
|
||||
m2 += 2;
|
||||
m3 += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void kf_bfly3(
|
||||
int[] Fout,
|
||||
int fout_ptr,
|
||||
int fstride,
|
||||
FFTState st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int k;
|
||||
int m1 = 2 * m;
|
||||
int m2 = 4 * m;
|
||||
int tw1, tw2;
|
||||
int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5, scratch6, scratch7;
|
||||
|
||||
int Fout_beg = fout_ptr;
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
fout_ptr = Fout_beg + 2 * i * mm;
|
||||
tw1 = tw2 = 0;
|
||||
/* For non-custom modes, m is guaranteed to be a multiple of 4. */
|
||||
k = m;
|
||||
do
|
||||
{
|
||||
scratch2 = (S_MUL(Fout[fout_ptr + m1], st.twiddles[tw1]) - S_MUL(Fout[fout_ptr + m1 + 1], st.twiddles[tw1 + 1]));
|
||||
scratch3 = (S_MUL(Fout[fout_ptr + m1], st.twiddles[tw1 + 1]) + S_MUL(Fout[fout_ptr + m1 + 1], st.twiddles[tw1]));
|
||||
scratch4 = (S_MUL(Fout[fout_ptr + m2], st.twiddles[tw2]) - S_MUL(Fout[fout_ptr + m2 + 1], st.twiddles[tw2 + 1]));
|
||||
scratch5 = (S_MUL(Fout[fout_ptr + m2], st.twiddles[tw2 + 1]) + S_MUL(Fout[fout_ptr + m2 + 1], st.twiddles[tw2]));
|
||||
|
||||
scratch6 = scratch2 + scratch4;
|
||||
scratch7 = scratch3 + scratch5;
|
||||
scratch0 = scratch2 - scratch4;
|
||||
scratch1 = scratch3 - scratch5;
|
||||
|
||||
tw1 += fstride * 2;
|
||||
tw2 += fstride * 4;
|
||||
|
||||
Fout[fout_ptr + m1] = Fout[fout_ptr + 0] - HALF_OF(scratch6);
|
||||
Fout[fout_ptr + m1 + 1] = Fout[fout_ptr + 1] - HALF_OF(scratch7);
|
||||
|
||||
scratch0 = S_MUL(scratch0, -28378);
|
||||
scratch1 = S_MUL(scratch1, -28378);
|
||||
|
||||
Fout[fout_ptr + 0] += scratch6;
|
||||
Fout[fout_ptr + 1] += scratch7;
|
||||
|
||||
Fout[fout_ptr + m2] = Fout[fout_ptr + m1] + scratch1;
|
||||
Fout[fout_ptr + m2 + 1] = Fout[fout_ptr + m1 + 1] - scratch0;
|
||||
|
||||
Fout[fout_ptr + m1] -= scratch1;
|
||||
Fout[fout_ptr + m1 + 1] += scratch0;
|
||||
|
||||
fout_ptr += 2;
|
||||
} while ((--k) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void kf_bfly5(
|
||||
int[] Fout,
|
||||
int fout_ptr,
|
||||
int fstride,
|
||||
FFTState st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
int Fout0, Fout1, Fout2, Fout3, Fout4;
|
||||
int i, u;
|
||||
int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5,
|
||||
scratch6, scratch7, scratch8, scratch9, scratch10, scratch11,
|
||||
scratch12,scratch13, scratch14, scratch15, scratch16, scratch17,
|
||||
scratch18, scratch19, scratch20, scratch21, scratch22, scratch23,
|
||||
scratch24, scratch25;
|
||||
|
||||
int Fout_beg = fout_ptr;
|
||||
|
||||
short ya_r = 10126;
|
||||
short ya_i = -31164;
|
||||
short yb_r = -26510;
|
||||
short yb_i = -19261;
|
||||
int tw1, tw2, tw3, tw4;
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
tw1 = tw2 = tw3 = tw4 = 0;
|
||||
fout_ptr = Fout_beg + 2 * i * mm;
|
||||
Fout0 = fout_ptr;
|
||||
Fout1 = fout_ptr + (2 * m);
|
||||
Fout2 = fout_ptr + (4 * m);
|
||||
Fout3 = fout_ptr + (6 * m);
|
||||
Fout4 = fout_ptr + (8 * m);
|
||||
|
||||
/* For non-custom modes, m is guaranteed to be a multiple of 4. */
|
||||
for (u = 0; u < m; ++u)
|
||||
{
|
||||
scratch0 = Fout[Fout0 + 0];
|
||||
scratch1 = Fout[Fout0 + 1];
|
||||
|
||||
scratch2 = (S_MUL(Fout[Fout1 + 0], st.twiddles[tw1]) - S_MUL(Fout[Fout1 + 1], st.twiddles[tw1 + 1]));
|
||||
scratch3 = (S_MUL(Fout[Fout1 + 0], st.twiddles[tw1 + 1]) + S_MUL(Fout[Fout1 + 1], st.twiddles[tw1]));
|
||||
scratch4 = (S_MUL(Fout[Fout2 + 0], st.twiddles[tw2]) - S_MUL(Fout[Fout2 + 1], st.twiddles[tw2 + 1]));
|
||||
scratch5 = (S_MUL(Fout[Fout2 + 0], st.twiddles[tw2 + 1]) + S_MUL(Fout[Fout2 + 1], st.twiddles[tw2]));
|
||||
scratch6 = (S_MUL(Fout[Fout3 + 0], st.twiddles[tw3]) - S_MUL(Fout[Fout3 + 1], st.twiddles[tw3 + 1]));
|
||||
scratch7 = (S_MUL(Fout[Fout3 + 0], st.twiddles[tw3 + 1]) + S_MUL(Fout[Fout3 + 1], st.twiddles[tw3]));
|
||||
scratch8 = (S_MUL(Fout[Fout4 + 0], st.twiddles[tw4]) - S_MUL(Fout[Fout4 + 1], st.twiddles[tw4 + 1]));
|
||||
scratch9 = (S_MUL(Fout[Fout4 + 0], st.twiddles[tw4 + 1]) + S_MUL(Fout[Fout4 + 1], st.twiddles[tw4]));
|
||||
|
||||
tw1 += (2 * fstride);
|
||||
tw2 += (4 * fstride);
|
||||
tw3 += (6 * fstride);
|
||||
tw4 += (8 * fstride);
|
||||
|
||||
scratch14 = scratch2 + scratch8;
|
||||
scratch15 = scratch3 + scratch9;
|
||||
scratch20 = scratch2 - scratch8;
|
||||
scratch21 = scratch3 - scratch9;
|
||||
scratch16 = scratch4 + scratch6;
|
||||
scratch17 = scratch5 + scratch7;
|
||||
scratch18 = scratch4 - scratch6;
|
||||
scratch19 = scratch5 - scratch7;
|
||||
|
||||
Fout[Fout0 + 0] += scratch14 + scratch16;
|
||||
Fout[Fout0 + 1] += scratch15 + scratch17;
|
||||
|
||||
scratch10 = scratch0 + S_MUL(scratch14, ya_r) + S_MUL(scratch16, yb_r);
|
||||
scratch11 = scratch1 + S_MUL(scratch15, ya_r) + S_MUL(scratch17, yb_r);
|
||||
|
||||
scratch12 = S_MUL(scratch21, ya_i) + S_MUL(scratch19, yb_i);
|
||||
scratch13 = 0 - S_MUL(scratch20, ya_i) - S_MUL(scratch18, yb_i);
|
||||
|
||||
Fout[Fout1 + 0] = scratch10 - scratch12;
|
||||
Fout[Fout1 + 1] = scratch11 - scratch13;
|
||||
Fout[Fout4 + 0] = scratch10 + scratch12;
|
||||
Fout[Fout4 + 1] = scratch11 + scratch13;
|
||||
|
||||
scratch22 = scratch0 + S_MUL(scratch14, yb_r) + S_MUL(scratch16, ya_r);
|
||||
scratch23 = scratch1 + S_MUL(scratch15, yb_r) + S_MUL(scratch17, ya_r);
|
||||
scratch24 = 0 - S_MUL(scratch21, yb_i) + S_MUL(scratch19, ya_i);
|
||||
scratch25 = S_MUL(scratch20, yb_i) - S_MUL(scratch18, ya_i);
|
||||
|
||||
Fout[Fout2 + 0] = scratch22 + scratch24;
|
||||
Fout[Fout2 + 1] = scratch23 + scratch25;
|
||||
Fout[Fout3 + 0] = scratch22 - scratch24;
|
||||
Fout[Fout3 + 1] = scratch23 - scratch25;
|
||||
|
||||
Fout0 += 2;
|
||||
Fout1 += 2;
|
||||
Fout2 += 2;
|
||||
Fout3 += 2;
|
||||
Fout4 += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void opus_fft_impl(FFTState st, int[] fout, int fout_ptr)
|
||||
{
|
||||
int m2, m;
|
||||
int p;
|
||||
int L;
|
||||
int[] fstride = new int[MAXFACTORS];
|
||||
int i;
|
||||
int shift;
|
||||
|
||||
/* st.shift can be -1 */
|
||||
shift = st.shift > 0 ? st.shift : 0;
|
||||
|
||||
fstride[0] = 1;
|
||||
L = 0;
|
||||
do
|
||||
{
|
||||
p = st.factors[2 * L];
|
||||
m = st.factors[2 * L + 1];
|
||||
fstride[L + 1] = fstride[L] * p;
|
||||
L++;
|
||||
} while (m != 1);
|
||||
|
||||
m = st.factors[2 * L - 1];
|
||||
for (i = L - 1; i >= 0; i--)
|
||||
{
|
||||
if (i != 0)
|
||||
m2 = st.factors[2 * i - 1];
|
||||
else
|
||||
m2 = 1;
|
||||
switch (st.factors[2 * i])
|
||||
{
|
||||
case 2:
|
||||
kf_bfly2(fout, fout_ptr, m, fstride[i]);
|
||||
break;
|
||||
case 4:
|
||||
kf_bfly4(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2);
|
||||
break;
|
||||
case 3:
|
||||
kf_bfly3(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2);
|
||||
break;
|
||||
case 5:
|
||||
kf_bfly5(fout, fout_ptr, fstride[i] << shift, st, m, fstride[i], m2);
|
||||
break;
|
||||
}
|
||||
m = m2;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void opus_fft(FFTState st, int[] fin, int[] fout)
|
||||
{
|
||||
int i;
|
||||
/* Allows us to scale with MULT16_32_Q16() */
|
||||
int scale_shift = st.scale_shift - 1;
|
||||
short scale = st.scale;
|
||||
|
||||
Inlines.OpusAssert(fin != fout, "In-place FFT not supported");
|
||||
|
||||
/* Bit-reverse the input */
|
||||
for (i = 0; i < st.nfft; i++)
|
||||
{
|
||||
fout[(2 * st.bitrev[i])] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[(2 * i)]), scale_shift);
|
||||
fout[(2 * st.bitrev[i] + 1)] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[(2 * i) + 1]), scale_shift);
|
||||
}
|
||||
|
||||
opus_fft_impl(st, fout, 0);
|
||||
}
|
||||
|
||||
|
||||
//internal static void opus_ifft(FFTState st, Pointer<int> fin, Pointer<int> fout)
|
||||
//{
|
||||
// int i;
|
||||
// Inlines.OpusAssert(fin != fout, "In-place iFFT not supported");
|
||||
|
||||
// /* Bit-reverse the input */
|
||||
// for (i = 0; i < st.nfft * 2; i++)
|
||||
// {
|
||||
// fout[st.bitrev[i]] = fin[i];
|
||||
// }
|
||||
|
||||
// for (i = 1; i < st.nfft * 2; i += 2)
|
||||
// {
|
||||
// fout[i] = -fout[i];
|
||||
// }
|
||||
|
||||
// opus_fft_impl(st, fout.Data, fout.Offset);
|
||||
|
||||
// for (i = 1; i < st.nfft * 2; i += 2)
|
||||
// fout[i] = -fout[i];
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
456
Libraries/Concentus/CSharp/Concentus/Celt/KissFFTUnsafe.cs
Normal file
456
Libraries/Concentus/CSharp/Concentus/Celt/KissFFTUnsafe.cs
Normal file
@@ -0,0 +1,456 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Copyright (c) 2003-2004, Mark Borgerding
|
||||
Modified from KISS-FFT by Jean-Marc Valin
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* This code is originally from Mark Borgerding's KISS-FFT but has been
|
||||
heavily modified to better suit Opus */
|
||||
|
||||
#if UNSAFE
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
internal static class KissFFT
|
||||
{
|
||||
//public const int SAMP_MAX = 2147483647;
|
||||
//public const int SAMP_MIN = 0 - SAMP_MAX;
|
||||
//public const int TWID_MAX = 32767;
|
||||
//public const int TRIG_UPSCALE = 1;
|
||||
|
||||
internal const int MAXFACTORS = 8;
|
||||
|
||||
internal static int S_MUL(int a, int b)
|
||||
{
|
||||
return Inlines.MULT16_32_Q15(b, a);
|
||||
}
|
||||
|
||||
internal static int S_MUL(int a, short b)
|
||||
{
|
||||
return Inlines.MULT16_32_Q15(b, a);
|
||||
}
|
||||
|
||||
internal static int HALF_OF(int x)
|
||||
{
|
||||
return x >> 1;
|
||||
}
|
||||
|
||||
internal static unsafe void kf_bfly2(int* Fout, int m, int N)
|
||||
{
|
||||
int* Fout2;
|
||||
int i;
|
||||
{
|
||||
short tw;
|
||||
tw = ((short)(0.5 + (0.7071067812f) * (((int)1) << (15))))/*Inlines.QCONST16(0.7071067812f, 15)*/;
|
||||
/* We know that m==4 here because the radix-2 is just after a radix-4 */
|
||||
Inlines.OpusAssert(m == 4);
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
int t_r, t_i;
|
||||
Fout2 = Fout + 8;
|
||||
t_r = *(Fout2);
|
||||
t_i = *(Fout2 + 1);
|
||||
*Fout2 = (*Fout) - t_r;
|
||||
*(Fout2 + 1) = *(Fout + 1) - t_i;
|
||||
*Fout += t_r;
|
||||
*(Fout + 1) += t_i;
|
||||
|
||||
t_r = S_MUL(*(Fout2 + 2) + *(Fout2 + 3), tw);
|
||||
t_i = S_MUL(*(Fout2 + 3) - *(Fout2 + 2), tw);
|
||||
*(Fout2 + 2) = *(Fout + 2) - t_r;
|
||||
*(Fout2 + 3) = *(Fout + 3) - t_i;
|
||||
*(Fout + 2) += t_r;
|
||||
*(Fout + 3) += t_i;
|
||||
|
||||
t_r = *(Fout2 + 5);
|
||||
t_i = 0 - *(Fout2 + 4);
|
||||
*(Fout2 + 4) = *(Fout + 4) - t_r;
|
||||
*(Fout2 + 5) = *(Fout + 5) - t_i;
|
||||
*(Fout + 4) += t_r;
|
||||
*(Fout + 5) += t_i;
|
||||
|
||||
t_r = S_MUL(*(Fout2 + 7) - *(Fout2 + 6), tw);
|
||||
t_i = S_MUL(0 - *(Fout2 + 7) - *(Fout2 + 6), tw);
|
||||
*(Fout2 + 6) = *(Fout + 6) - t_r;
|
||||
*(Fout2 + 7) = *(Fout + 7) - t_i;
|
||||
*(Fout + 6) += t_r;
|
||||
*(Fout + 7) += t_i;
|
||||
|
||||
Fout += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void kf_bfly4(
|
||||
int* Fout,
|
||||
int fstride,
|
||||
FFTState st,
|
||||
int m,
|
||||
int N,
|
||||
int mm)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (m == 1)
|
||||
{
|
||||
/* Degenerate case where all the twiddles are 1. */
|
||||
int scratch0, scratch1, scratch2, scratch3;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
scratch0 = *(Fout) - *(Fout + 4);
|
||||
scratch1 = *(Fout + 1) - *(Fout + 5);
|
||||
*(Fout + 0) += *(Fout + 4);
|
||||
*(Fout + 1) += *(Fout + 5);
|
||||
scratch2 = *(Fout + 2) + *(Fout + 6);
|
||||
scratch3 = *(Fout + 3) + *(Fout + 7);
|
||||
*(Fout + 4) = *(Fout + 0) - scratch2;
|
||||
*(Fout + 5) = *(Fout + 1) - scratch3;
|
||||
*(Fout + 0) += scratch2;
|
||||
*(Fout + 1) += scratch3;
|
||||
scratch2 = *(Fout + 2) - *(Fout + 6);
|
||||
scratch3 = *(Fout + 3) - *(Fout + 7);
|
||||
*(Fout + 2) = scratch0 + scratch3;
|
||||
*(Fout + 3) = scratch1 - scratch2;
|
||||
*(Fout + 6) = scratch0 - scratch3;
|
||||
*(Fout + 7) = scratch1 + scratch2;
|
||||
Fout += 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int j;
|
||||
int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5, scratch6, scratch7, scratch8, scratch9, scratch10, scratch11;
|
||||
int tw1, tw2, tw3;
|
||||
int* Fout_beg = Fout;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
Fout = Fout_beg + 2 * i * mm;
|
||||
int* m1 = Fout + (2 * m);
|
||||
int* m2 = Fout + (4 * m);
|
||||
int* m3 = Fout + (6 * m);
|
||||
tw3 = tw2 = tw1 = 0;
|
||||
/* m is guaranteed to be a multiple of 4. */
|
||||
for (j = 0; j < m; j++)
|
||||
{
|
||||
scratch0 = (S_MUL(*m1, st.twiddles[tw1]) - S_MUL(*(m1 + 1), st.twiddles[tw1 + 1]));
|
||||
scratch1 = (S_MUL(*m1, st.twiddles[tw1 + 1]) + S_MUL(*(m1 + 1), st.twiddles[tw1]));
|
||||
scratch2 = (S_MUL(*m2, st.twiddles[tw2]) - S_MUL(*(m2 + 1), st.twiddles[tw2 + 1]));
|
||||
scratch3 = (S_MUL(*m2, st.twiddles[tw2 + 1]) + S_MUL(*(m2 + 1), st.twiddles[tw2]));
|
||||
scratch4 = (S_MUL(*m3, st.twiddles[tw3]) - S_MUL(*(m3 + 1), st.twiddles[tw3 + 1]));
|
||||
scratch5 = (S_MUL(*m3, st.twiddles[tw3 + 1]) + S_MUL(*(m3 + 1), st.twiddles[tw3]));
|
||||
scratch10 = *(Fout) - scratch2;
|
||||
scratch11 = *(Fout + 1) - scratch3;
|
||||
*(Fout) += scratch2;
|
||||
*(Fout + 1) += scratch3;
|
||||
scratch6 = scratch0 + scratch4;
|
||||
scratch7 = scratch1 + scratch5;
|
||||
scratch8 = scratch0 - scratch4;
|
||||
scratch9 = scratch1 - scratch5;
|
||||
*m2 = *(Fout) - scratch6;
|
||||
*(m2 + 1) = *(Fout + 1) - scratch7;
|
||||
tw1 += fstride * 2;
|
||||
tw2 += fstride * 4;
|
||||
tw3 += fstride * 6;
|
||||
*(Fout ) += scratch6;
|
||||
*(Fout + 1) += scratch7;
|
||||
*m1 = scratch10 + scratch9;
|
||||
*(m1 + 1) = scratch11 - scratch8;
|
||||
*m3 = scratch10 - scratch9;
|
||||
*(m3 + 1) = scratch11 + scratch8;
|
||||
Fout += 2;
|
||||
m1 += 2;
|
||||
m2 += 2;
|
||||
m3 += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void kf_bfly3(
|
||||
int* Fout,
|
||||
int fstride,
|
||||
FFTState st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int k;
|
||||
int m1 = 2 * m;
|
||||
int m2 = 4 * m;
|
||||
int tw1, tw2;
|
||||
int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5, scratch6, scratch7;
|
||||
|
||||
int* Fout_beg = Fout;
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
Fout = Fout_beg + 2 * i * mm;
|
||||
tw1 = tw2 = 0;
|
||||
/* For non-custom modes, m is guaranteed to be a multiple of 4. */
|
||||
k = m;
|
||||
do
|
||||
{
|
||||
scratch2 = (S_MUL(*(Fout + m1), st.twiddles[tw1]) - S_MUL(*(Fout + m1 + 1), st.twiddles[tw1 + 1]));
|
||||
scratch3 = (S_MUL(*(Fout + m1), st.twiddles[tw1 + 1]) + S_MUL(*(Fout + m1 + 1), st.twiddles[tw1]));
|
||||
scratch4 = (S_MUL(*(Fout + m2), st.twiddles[tw2]) - S_MUL(*(Fout + m2 + 1), st.twiddles[tw2 + 1]));
|
||||
scratch5 = (S_MUL(*(Fout + m2), st.twiddles[tw2 + 1]) + S_MUL(*(Fout + m2 + 1), st.twiddles[tw2]));
|
||||
|
||||
scratch6 = scratch2 + scratch4;
|
||||
scratch7 = scratch3 + scratch5;
|
||||
scratch0 = scratch2 - scratch4;
|
||||
scratch1 = scratch3 - scratch5;
|
||||
|
||||
tw1 += fstride * 2;
|
||||
tw2 += fstride * 4;
|
||||
|
||||
*(Fout + m1) = *(Fout) - HALF_OF(scratch6);
|
||||
*(Fout + m1 + 1) = *(Fout + 1) - HALF_OF(scratch7);
|
||||
|
||||
scratch0 = S_MUL(scratch0, -28378);
|
||||
scratch1 = S_MUL(scratch1, -28378);
|
||||
|
||||
*(Fout) += scratch6;
|
||||
*(Fout + 1) += scratch7;
|
||||
|
||||
*(Fout + m2) = *(Fout + m1) + scratch1;
|
||||
*(Fout + m2 + 1) = *(Fout + m1 + 1) - scratch0;
|
||||
|
||||
*(Fout + m1) -= scratch1;
|
||||
*(Fout + m1 + 1) += scratch0;
|
||||
|
||||
Fout += 2;
|
||||
} while ((--k) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void kf_bfly5(
|
||||
int* Fout,
|
||||
int fstride,
|
||||
FFTState st,
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
int* Fout0, Fout1, Fout2, Fout3, Fout4;
|
||||
int i, u;
|
||||
int scratch0, scratch1, scratch2, scratch3, scratch4, scratch5,
|
||||
scratch6, scratch7, scratch8, scratch9, scratch10, scratch11,
|
||||
scratch12, scratch13, scratch14, scratch15, scratch16, scratch17,
|
||||
scratch18, scratch19, scratch20, scratch21, scratch22, scratch23,
|
||||
scratch24, scratch25;
|
||||
|
||||
int* Fout_beg = Fout;
|
||||
|
||||
short ya_r = 10126;
|
||||
short ya_i = -31164;
|
||||
short yb_r = -26510;
|
||||
short yb_i = -19261;
|
||||
int tw1, tw2, tw3, tw4;
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
tw1 = tw2 = tw3 = tw4 = 0;
|
||||
Fout = Fout_beg + 2 * i * mm;
|
||||
Fout0 = Fout;
|
||||
Fout1 = Fout + (2 * m);
|
||||
Fout2 = Fout + (4 * m);
|
||||
Fout3 = Fout + (6 * m);
|
||||
Fout4 = Fout + (8 * m);
|
||||
|
||||
/* For non-custom modes, m is guaranteed to be a multiple of 4. */
|
||||
for (u = 0; u < m; ++u)
|
||||
{
|
||||
scratch0 = *(Fout0 + 0);
|
||||
scratch1 = *(Fout0 + 1);
|
||||
|
||||
scratch2 = (S_MUL(*(Fout1 + 0), st.twiddles[tw1]) - S_MUL(*(Fout1 + 1), st.twiddles[tw1 + 1]));
|
||||
scratch3 = (S_MUL(*(Fout1 + 0), st.twiddles[tw1 + 1]) + S_MUL(*(Fout1 + 1), st.twiddles[tw1]));
|
||||
scratch4 = (S_MUL(*(Fout2 + 0), st.twiddles[tw2]) - S_MUL(*(Fout2 + 1), st.twiddles[tw2 + 1]));
|
||||
scratch5 = (S_MUL(*(Fout2 + 0), st.twiddles[tw2 + 1]) + S_MUL(*(Fout2 + 1), st.twiddles[tw2]));
|
||||
scratch6 = (S_MUL(*(Fout3 + 0), st.twiddles[tw3]) - S_MUL(*(Fout3 + 1), st.twiddles[tw3 + 1]));
|
||||
scratch7 = (S_MUL(*(Fout3 + 0), st.twiddles[tw3 + 1]) + S_MUL(*(Fout3 + 1), st.twiddles[tw3]));
|
||||
scratch8 = (S_MUL(*(Fout4 + 0), st.twiddles[tw4]) - S_MUL(*(Fout4 + 1), st.twiddles[tw4 + 1]));
|
||||
scratch9 = (S_MUL(*(Fout4 + 0), st.twiddles[tw4 + 1]) + S_MUL(*(Fout4 + 1), st.twiddles[tw4]));
|
||||
|
||||
tw1 += (2 * fstride);
|
||||
tw2 += (4 * fstride);
|
||||
tw3 += (6 * fstride);
|
||||
tw4 += (8 * fstride);
|
||||
|
||||
scratch14 = scratch2 + scratch8;
|
||||
scratch15 = scratch3 + scratch9;
|
||||
scratch20 = scratch2 - scratch8;
|
||||
scratch21 = scratch3 - scratch9;
|
||||
scratch16 = scratch4 + scratch6;
|
||||
scratch17 = scratch5 + scratch7;
|
||||
scratch18 = scratch4 - scratch6;
|
||||
scratch19 = scratch5 - scratch7;
|
||||
|
||||
*(Fout0 + 0) += scratch14 + scratch16;
|
||||
*(Fout0 + 1) += scratch15 + scratch17;
|
||||
|
||||
scratch10 = scratch0 + S_MUL(scratch14, ya_r) + S_MUL(scratch16, yb_r);
|
||||
scratch11 = scratch1 + S_MUL(scratch15, ya_r) + S_MUL(scratch17, yb_r);
|
||||
|
||||
scratch12 = S_MUL(scratch21, ya_i) + S_MUL(scratch19, yb_i);
|
||||
scratch13 = 0 - S_MUL(scratch20, ya_i) - S_MUL(scratch18, yb_i);
|
||||
|
||||
*(Fout1 + 0) = scratch10 - scratch12;
|
||||
*(Fout1 + 1) = scratch11 - scratch13;
|
||||
*(Fout4 + 0) = scratch10 + scratch12;
|
||||
*(Fout4 + 1) = scratch11 + scratch13;
|
||||
|
||||
scratch22 = scratch0 + S_MUL(scratch14, yb_r) + S_MUL(scratch16, ya_r);
|
||||
scratch23 = scratch1 + S_MUL(scratch15, yb_r) + S_MUL(scratch17, ya_r);
|
||||
scratch24 = 0 - S_MUL(scratch21, yb_i) + S_MUL(scratch19, ya_i);
|
||||
scratch25 = S_MUL(scratch20, yb_i) - S_MUL(scratch18, ya_i);
|
||||
|
||||
*(Fout2 + 0) = scratch22 + scratch24;
|
||||
*(Fout2 + 1) = scratch23 + scratch25;
|
||||
*(Fout3 + 0) = scratch22 - scratch24;
|
||||
*(Fout3 + 1) = scratch23 - scratch25;
|
||||
|
||||
Fout0 += 2;
|
||||
Fout1 += 2;
|
||||
Fout2 += 2;
|
||||
Fout3 += 2;
|
||||
Fout4 += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void opus_fft_impl(FFTState st, int[] fout, int fout_ptr)
|
||||
{
|
||||
int m2, m;
|
||||
int p;
|
||||
int L;
|
||||
int[] fstride = new int[MAXFACTORS];
|
||||
int i;
|
||||
int shift;
|
||||
|
||||
/* st.shift can be -1 */
|
||||
shift = st.shift > 0 ? st.shift : 0;
|
||||
|
||||
fstride[0] = 1;
|
||||
L = 0;
|
||||
do
|
||||
{
|
||||
p = st.factors[2 * L];
|
||||
m = st.factors[2 * L + 1];
|
||||
fstride[L + 1] = fstride[L] * p;
|
||||
L++;
|
||||
} while (m != 1);
|
||||
|
||||
fixed (int* _fixed_fout = fout)
|
||||
{
|
||||
int* pfout = _fixed_fout + fout_ptr;
|
||||
m = st.factors[2 * L - 1];
|
||||
for (i = L - 1; i >= 0; i--)
|
||||
{
|
||||
if (i != 0)
|
||||
m2 = st.factors[2 * i - 1];
|
||||
else
|
||||
m2 = 1;
|
||||
switch (st.factors[2 * i])
|
||||
{
|
||||
case 2:
|
||||
kf_bfly2(pfout, m, fstride[i]);
|
||||
break;
|
||||
case 4:
|
||||
kf_bfly4(pfout, fstride[i] << shift, st, m, fstride[i], m2);
|
||||
break;
|
||||
case 3:
|
||||
kf_bfly3(pfout, fstride[i] << shift, st, m, fstride[i], m2);
|
||||
break;
|
||||
case 5:
|
||||
kf_bfly5(pfout, fstride[i] << shift, st, m, fstride[i], m2);
|
||||
break;
|
||||
}
|
||||
m = m2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void opus_fft(FFTState st, int[] fin, int[] fout)
|
||||
{
|
||||
int i;
|
||||
/* Allows us to scale with MULT16_32_Q16() */
|
||||
int scale_shift = st.scale_shift - 1;
|
||||
short scale = st.scale;
|
||||
|
||||
Inlines.OpusAssert(fin != fout, "In-place FFT not supported");
|
||||
|
||||
/* Bit-reverse the input */
|
||||
for (i = 0; i < st.nfft; i++)
|
||||
{
|
||||
fout[(2 * st.bitrev[i])] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[(2 * i)]), scale_shift);
|
||||
fout[(2 * st.bitrev[i] + 1)] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[(2 * i) + 1]), scale_shift);
|
||||
}
|
||||
|
||||
opus_fft_impl(st, fout, 0);
|
||||
}
|
||||
|
||||
|
||||
//internal static void opus_ifft(FFTState st, Pointer<int> fin, Pointer<int> fout)
|
||||
//{
|
||||
// int i;
|
||||
// Inlines.OpusAssert(fin != fout, "In-place iFFT not supported");
|
||||
|
||||
// /* Bit-reverse the input */
|
||||
// for (i = 0; i < st.nfft * 2; i++)
|
||||
// {
|
||||
// fout[st.bitrev[i]] = fin[i];
|
||||
// }
|
||||
|
||||
// for (i = 1; i < st.nfft * 2; i += 2)
|
||||
// {
|
||||
// fout[i] = -fout[i];
|
||||
// }
|
||||
|
||||
// opus_fft_impl(st, fout.Data, fout.Offset);
|
||||
|
||||
// for (i = 1; i < st.nfft * 2; i += 2)
|
||||
// fout[i] = -fout[i];
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
157
Libraries/Concentus/CSharp/Concentus/Celt/Laplace.cs
Normal file
157
Libraries/Concentus/CSharp/Concentus/Celt/Laplace.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
internal static class Laplace
|
||||
{
|
||||
/* The minimum probability of an energy delta (out of 32768). */
|
||||
private const int LAPLACE_LOG_MINP = 0;
|
||||
private const uint LAPLACE_MINP = (1 << LAPLACE_LOG_MINP);
|
||||
/* The minimum number of guaranteed representable energy deltas (in one
|
||||
direction). */
|
||||
private const int LAPLACE_NMIN = 16;
|
||||
|
||||
/* When called, decay is positive and at most 11456. */
|
||||
internal static uint ec_laplace_get_freq1(uint fs0, int decay)
|
||||
{
|
||||
uint ft;
|
||||
ft = 32768 - LAPLACE_MINP * (2 * LAPLACE_NMIN) - fs0;
|
||||
return (uint)((ft * (int)(16384 - decay)) >> 15);
|
||||
}
|
||||
|
||||
internal static void ec_laplace_encode(EntropyCoder enc, ref int value, uint fs, int decay)
|
||||
{
|
||||
uint fl;
|
||||
int val = value;
|
||||
fl = 0;
|
||||
if (val != 0)
|
||||
{
|
||||
int s;
|
||||
int i;
|
||||
s = 0 - (val < 0 ? 1 : 0);
|
||||
val = (val + s) ^ s;
|
||||
fl = fs;
|
||||
fs = ec_laplace_get_freq1(fs, decay);
|
||||
|
||||
/* Search the decaying part of the PDF.*/
|
||||
for (i = 1; fs > 0 && i < val; i++)
|
||||
{
|
||||
fs *= 2;
|
||||
fl += fs + 2 * LAPLACE_MINP;
|
||||
fs = (uint)((fs * (int)decay) >> 15);
|
||||
}
|
||||
|
||||
/* Everything beyond that has probability LAPLACE_MINP. */
|
||||
if (fs == 0)
|
||||
{
|
||||
int di;
|
||||
int ndi_max;
|
||||
ndi_max = (int)(32768 - fl + LAPLACE_MINP - 1) >> LAPLACE_LOG_MINP;
|
||||
ndi_max = (ndi_max - s) >> 1;
|
||||
di = Inlines.IMIN(val - i, ndi_max - 1);
|
||||
fl += (uint)(2 * di + 1 + s) * LAPLACE_MINP;
|
||||
fs = Inlines.IMIN(LAPLACE_MINP, 32768 - fl);
|
||||
value = (i + di + s) ^ s;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs += LAPLACE_MINP;
|
||||
fl += (uint)(fs & ~s);
|
||||
}
|
||||
Inlines.OpusAssert(fl + fs <= 32768);
|
||||
Inlines.OpusAssert(fs > 0);
|
||||
}
|
||||
|
||||
enc.encode_bin(fl, fl + fs, 15);
|
||||
}
|
||||
|
||||
internal static int ec_laplace_decode(EntropyCoder dec, uint fs, int decay)
|
||||
{
|
||||
int val = 0;
|
||||
uint fl;
|
||||
uint fm;
|
||||
fm = dec.decode_bin(15);
|
||||
fl = 0;
|
||||
|
||||
if (fm >= fs)
|
||||
{
|
||||
val++;
|
||||
fl = fs;
|
||||
fs = ec_laplace_get_freq1(fs, decay) + LAPLACE_MINP;
|
||||
/* Search the decaying part of the PDF.*/
|
||||
while (fs > LAPLACE_MINP && fm >= fl + 2 * fs)
|
||||
{
|
||||
fs *= 2;
|
||||
fl += fs;
|
||||
fs = (uint)(((fs - 2 * LAPLACE_MINP) * (int)decay) >> 15);
|
||||
fs += LAPLACE_MINP;
|
||||
val++;
|
||||
}
|
||||
/* Everything beyond that has probability LAPLACE_MINP. */
|
||||
if (fs <= LAPLACE_MINP)
|
||||
{
|
||||
int di;
|
||||
di = (int)(fm - fl) >> (LAPLACE_LOG_MINP + 1);
|
||||
val += di;
|
||||
fl += (uint)(2 * di * LAPLACE_MINP);
|
||||
}
|
||||
if (fm < fl + fs)
|
||||
val = -val;
|
||||
else
|
||||
fl += fs;
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(fl < 32768);
|
||||
Inlines.OpusAssert(fs > 0);
|
||||
Inlines.OpusAssert(fl <= fm);
|
||||
Inlines.OpusAssert(fm < Inlines.IMIN(fl + fs, 32768));
|
||||
|
||||
dec.dec_update(fl, Inlines.IMIN(fl + fs, 32768), 32768);
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
370
Libraries/Concentus/CSharp/Concentus/Celt/MDCT.cs
Normal file
370
Libraries/Concentus/CSharp/Concentus/Celt/MDCT.cs
Normal file
@@ -0,0 +1,370 @@
|
||||
/* Copyright (c) 2003-2004, Mark Borgerding
|
||||
Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Modified from KISS-FFT by Jean-Marc Valin
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class MDCT
|
||||
{
|
||||
|
||||
#if !UNSAFE
|
||||
/* Forward MDCT trashes the input array */
|
||||
internal static void clt_mdct_forward(MDCTLookup l, int[] input, int input_ptr, int[] output, int output_ptr,
|
||||
int[] window, int overlap, int shift, int stride)
|
||||
{
|
||||
int i;
|
||||
int N, N2, N4;
|
||||
int[] f;
|
||||
int[] f2;
|
||||
FFTState st = l.kfft[shift];
|
||||
short[] trig;
|
||||
int trig_ptr = 0;
|
||||
int scale;
|
||||
|
||||
int scale_shift = st.scale_shift - 1;
|
||||
scale = st.scale;
|
||||
|
||||
N = l.n;
|
||||
trig = l.trig;
|
||||
for (i = 0; i < shift; i++)
|
||||
{
|
||||
N = N >> 1;
|
||||
trig_ptr += N;
|
||||
}
|
||||
N2 = N >> 1;
|
||||
N4 = N >> 2;
|
||||
|
||||
f = new int[N2];
|
||||
f2 = new int[N4 * 2];
|
||||
|
||||
/* Consider the input to be composed of four blocks: [a, b, c, d] */
|
||||
/* Window, shuffle, fold */
|
||||
{
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
int xp1 = input_ptr + (overlap >> 1);
|
||||
int xp2 = input_ptr + N2 - 1 + (overlap >> 1);
|
||||
int yp = 0;
|
||||
int wp1 = (overlap >> 1);
|
||||
int wp2 = ((overlap >> 1) - 1);
|
||||
for (i = 0; i < ((overlap + 3) >> 2); i++)
|
||||
{
|
||||
/* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
|
||||
f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp1 + N2]) + Inlines.MULT16_32_Q15(window[wp1], input[xp2]);
|
||||
f[yp++] = Inlines.MULT16_32_Q15(window[wp1], input[xp1]) - Inlines.MULT16_32_Q15(window[wp2], input[xp2 - N2]);
|
||||
xp1 += 2;
|
||||
xp2 -= 2;
|
||||
wp1 += 2;
|
||||
wp2 -= 2;
|
||||
}
|
||||
wp1 = 0;
|
||||
wp2 = (overlap - 1);
|
||||
for (; i < N4 - ((overlap + 3) >> 2); i++)
|
||||
{
|
||||
/* Real part arranged as a-bR, Imag part arranged as -c-dR */
|
||||
f[yp++] = input[xp2];
|
||||
f[yp++] = input[xp1];
|
||||
xp1 += 2;
|
||||
xp2 -= 2;
|
||||
}
|
||||
for (; i < N4; i++)
|
||||
{
|
||||
/* Real part arranged as a-bR, Imag part arranged as -c-dR */
|
||||
f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp2]) - Inlines.MULT16_32_Q15(window[wp1], input[xp1 - N2]);
|
||||
f[yp++] = Inlines.MULT16_32_Q15(window[wp2], input[xp1]) + Inlines.MULT16_32_Q15(window[wp1], input[xp2 + N2]);
|
||||
xp1 += 2;
|
||||
xp2 -= 2;
|
||||
wp1 += 2;
|
||||
wp2 -= 2;
|
||||
}
|
||||
}
|
||||
/* Pre-rotation */
|
||||
{
|
||||
int yp = 0;
|
||||
int t = trig_ptr;
|
||||
for (i = 0; i < N4; i++)
|
||||
{
|
||||
short t0, t1;
|
||||
int re, im, yr, yi;
|
||||
t0 = trig[t + i];
|
||||
t1 = trig[t + N4 + i];
|
||||
re = f[yp++];
|
||||
im = f[yp++];
|
||||
yr = KissFFT.S_MUL(re, t0) - KissFFT.S_MUL(im, t1);
|
||||
yi = KissFFT.S_MUL(im, t0) + KissFFT.S_MUL(re, t1);
|
||||
f2[2 * st.bitrev[i]] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, yr), scale_shift);
|
||||
f2[2 * st.bitrev[i] + 1] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, yi), scale_shift);
|
||||
}
|
||||
}
|
||||
|
||||
/* N/4 complex FFT, does not downscale anymore */
|
||||
KissFFT.opus_fft_impl(st, f2, 0);
|
||||
|
||||
/* Post-rotate */
|
||||
{
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
int fp = 0;
|
||||
int yp1 = output_ptr;
|
||||
int yp2 = output_ptr + (stride * (N2 - 1));
|
||||
int t = trig_ptr;
|
||||
for (i = 0; i < N4; i++)
|
||||
{
|
||||
int yr, yi;
|
||||
yr = KissFFT.S_MUL(f2[fp + 1], trig[t + N4 + i]) - KissFFT.S_MUL(f2[fp], trig[t + i]);
|
||||
yi = KissFFT.S_MUL(f2[fp], trig[t + N4 + i]) + KissFFT.S_MUL(f2[fp + 1], trig[t + i]);
|
||||
output[yp1] = yr;
|
||||
output[yp2] = yi;
|
||||
fp += 2;
|
||||
yp1 += (2 * stride);
|
||||
yp2 -= (2 * stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Forward MDCT trashes the input array */
|
||||
internal static unsafe void clt_mdct_forward(MDCTLookup l, int[] input, int input_ptr, int[] output, int output_ptr,
|
||||
int[] window, int overlap, int shift, int stride)
|
||||
{
|
||||
int i;
|
||||
int N, N2, N4;
|
||||
int[] f;
|
||||
int[] f2;
|
||||
FFTState st = l.kfft[shift];
|
||||
int scale;
|
||||
|
||||
int scale_shift = st.scale_shift - 1;
|
||||
scale = st.scale;
|
||||
|
||||
N = l.n;
|
||||
fixed (short* ptrig_base = l.trig)
|
||||
{
|
||||
short* trig = ptrig_base;
|
||||
for (i = 0; i < shift; i++)
|
||||
{
|
||||
N = N >> 1;
|
||||
trig += N;
|
||||
}
|
||||
N2 = N >> 1;
|
||||
N4 = N >> 2;
|
||||
|
||||
f = new int[N2];
|
||||
f2 = new int[N4 * 2];
|
||||
fixed (int* pinput_base = input, pwindow = window, pf = f, pf2 = f2)
|
||||
{
|
||||
int* pinput = pinput_base + input_ptr;
|
||||
/* Consider the input to be composed of four blocks: [a, b, c, d] */
|
||||
/* Window, shuffle, fold */
|
||||
{
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
int* xp1 = pinput + (overlap >> 1);
|
||||
int* xp2 = pinput + N2 - 1 + (overlap >> 1);
|
||||
int* yp = pf;
|
||||
int* wp1 = pwindow + (overlap >> 1);
|
||||
int* wp2 = pwindow + ((overlap >> 1) - 1);
|
||||
for (i = 0; i < ((overlap + 3) >> 2); i++)
|
||||
{
|
||||
/* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
|
||||
*yp++ = Inlines.MULT16_32_Q15(*wp2, xp1[N2]) + Inlines.MULT16_32_Q15(*wp1, *xp2);
|
||||
*yp++ = Inlines.MULT16_32_Q15(*wp1, *xp1) - Inlines.MULT16_32_Q15(*wp2, xp2[0 - N2]);
|
||||
xp1 += 2;
|
||||
xp2 -= 2;
|
||||
wp1 += 2;
|
||||
wp2 -= 2;
|
||||
}
|
||||
wp1 = pwindow;
|
||||
wp2 = pwindow + (overlap - 1);
|
||||
for (; i < N4 - ((overlap + 3) >> 2); i++)
|
||||
{
|
||||
/* Real part arranged as a-bR, Imag part arranged as -c-dR */
|
||||
*yp++ = *xp2;
|
||||
*yp++ = *xp1;
|
||||
xp1 += 2;
|
||||
xp2 -= 2;
|
||||
}
|
||||
for (; i < N4; i++)
|
||||
{
|
||||
/* Real part arranged as a-bR, Imag part arranged as -c-dR */
|
||||
*yp++ = Inlines.MULT16_32_Q15(*wp2, *xp2) - Inlines.MULT16_32_Q15(*wp1, xp1[0 - N2]);
|
||||
*yp++ = Inlines.MULT16_32_Q15(*wp2, *xp1) + Inlines.MULT16_32_Q15(*wp1, xp2[N2]);
|
||||
xp1 += 2;
|
||||
xp2 -= 2;
|
||||
wp1 += 2;
|
||||
wp2 -= 2;
|
||||
}
|
||||
}
|
||||
/* Pre-rotation */
|
||||
{
|
||||
int* yp = pf;
|
||||
short* t = trig;
|
||||
for (i = 0; i < N4; i++)
|
||||
{
|
||||
short t0, t1;
|
||||
int re, im, yr, yi;
|
||||
t0 = t[i];
|
||||
t1 = t[N4 + i];
|
||||
re = *yp++;
|
||||
im = *yp++;
|
||||
yr = KissFFT.S_MUL(re, t0) - KissFFT.S_MUL(im, t1);
|
||||
yi = KissFFT.S_MUL(im, t0) + KissFFT.S_MUL(re, t1);
|
||||
pf2[2 * st.bitrev[i]] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, yr), scale_shift);
|
||||
pf2[2 * st.bitrev[i] + 1] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, yi), scale_shift);
|
||||
}
|
||||
}
|
||||
|
||||
/* N/4 complex FFT, does not downscale anymore */
|
||||
KissFFT.opus_fft_impl(st, f2, 0);
|
||||
|
||||
/* Post-rotate */
|
||||
fixed (int* poutput_base = output)
|
||||
{
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
int* fp = pf2;
|
||||
int* yp1 = poutput_base + output_ptr;
|
||||
int* yp2 = poutput_base + output_ptr + (stride * (N2 - 1));
|
||||
short* t = trig;
|
||||
for (i = 0; i < N4; i++)
|
||||
{
|
||||
int yr, yi;
|
||||
yr = KissFFT.S_MUL(fp[1], t[N4 + i]) - KissFFT.S_MUL(fp[0], t[i]);
|
||||
yi = KissFFT.S_MUL(fp[0], t[N4 + i]) + KissFFT.S_MUL(fp[1], t[i]);
|
||||
*yp1 = yr;
|
||||
*yp2 = yi;
|
||||
fp += 2;
|
||||
yp1 += (2 * stride);
|
||||
yp2 -= (2 * stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static void clt_mdct_backward(MDCTLookup l, int[] input, int input_ptr, int[] output, int output_ptr,
|
||||
int[] window, int overlap, int shift, int stride)
|
||||
{
|
||||
int i;
|
||||
int N, N2, N4;
|
||||
int trig = 0;
|
||||
int xp1, xp2, yp, yp0, yp1;
|
||||
|
||||
N = l.n;
|
||||
for (i = 0; i < shift; i++)
|
||||
{
|
||||
N >>= 1;
|
||||
trig += N;
|
||||
}
|
||||
N2 = N >> 1;
|
||||
N4 = N >> 2;
|
||||
|
||||
/* Pre-rotate */
|
||||
/* Temp pointers to make it really clear to the compiler what we're doing */
|
||||
xp2 = input_ptr + (stride * (N2 - 1));
|
||||
yp = output_ptr + (overlap >> 1);
|
||||
short[] bitrev = l.kfft[shift].bitrev;
|
||||
int bitrav_ptr = 0;
|
||||
for (i = 0; i < N4; i++)
|
||||
{
|
||||
int rev = bitrev[bitrav_ptr++];
|
||||
int ypr = yp + 2 * rev;
|
||||
/* We swap real and imag because we use an FFT instead of an IFFT. */
|
||||
output[ypr + 1] = KissFFT.S_MUL(input[xp2], l.trig[trig + i]) + KissFFT.S_MUL(input[input_ptr], l.trig[trig + N4 + i]); //yr
|
||||
output[ypr] = KissFFT.S_MUL(input[input_ptr], l.trig[trig + i]) - KissFFT.S_MUL(input[xp2], l.trig[trig + N4 + i]); //yi
|
||||
/* Storing the pre-rotation directly in the bitrev order. */
|
||||
input_ptr += (2 * stride);
|
||||
xp2 -= (2 * stride);
|
||||
}
|
||||
|
||||
KissFFT.opus_fft_impl(l.kfft[shift], output, output_ptr + (overlap >> 1));
|
||||
|
||||
/* Post-rotate and de-shuffle from both ends of the buffer at once to make
|
||||
it in-place. */
|
||||
yp0 = output_ptr + (overlap >> 1);
|
||||
yp1 = output_ptr + (overlap >> 1) + N2 - 2;
|
||||
int t = trig;
|
||||
|
||||
/* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
|
||||
middle pair will be computed twice. */
|
||||
int tN4m1 = t + N4 - 1;
|
||||
int tN2m1 = t + N2 - 1;
|
||||
for (i = 0; i < (N4 + 1) >> 1; i++)
|
||||
{
|
||||
int re, im, yr, yi;
|
||||
short t0, t1;
|
||||
/* We swap real and imag because we're using an FFT instead of an IFFT. */
|
||||
re = output[yp0 + 1];
|
||||
im = output[yp0];
|
||||
t0 = l.trig[t + i];
|
||||
t1 = l.trig[t + N4 + i];
|
||||
/* We'd scale up by 2 here, but instead it's done when mixing the windows */
|
||||
yr = KissFFT.S_MUL(re, t0) + KissFFT.S_MUL(im, t1);
|
||||
yi = KissFFT.S_MUL(re, t1) - KissFFT.S_MUL(im, t0);
|
||||
/* We swap real and imag because we're using an FFT instead of an IFFT. */
|
||||
re = output[yp1 + 1];
|
||||
im = output[yp1];
|
||||
output[yp0] = yr;
|
||||
output[yp1 + 1] = yi;
|
||||
t0 = l.trig[tN4m1 - i];
|
||||
t1 = l.trig[tN2m1 - i];
|
||||
/* We'd scale up by 2 here, but instead it's done when mixing the windows */
|
||||
yr = KissFFT.S_MUL(re, t0) + KissFFT.S_MUL(im, t1);
|
||||
yi = KissFFT.S_MUL(re, t1) - KissFFT.S_MUL(im, t0);
|
||||
output[yp1] = yr;
|
||||
output[yp0 + 1] = yi;
|
||||
yp0 += 2;
|
||||
yp1 -= 2;
|
||||
}
|
||||
|
||||
/* Mirror on both sides for TDAC */
|
||||
xp1 = output_ptr + overlap - 1;
|
||||
yp1 = output_ptr;
|
||||
int wp1 = 0;
|
||||
int wp2 = (overlap - 1);
|
||||
|
||||
for (i = 0; i < overlap / 2; i++)
|
||||
{
|
||||
int x1 = output[xp1];
|
||||
int x2 = output[yp1];
|
||||
output[yp1++] = Inlines.MULT16_32_Q15(window[wp2], x2) - Inlines.MULT16_32_Q15(window[wp1], x1);
|
||||
output[xp1--] = Inlines.MULT16_32_Q15(window[wp1], x2) + Inlines.MULT16_32_Q15(window[wp2], x1);
|
||||
wp1++;
|
||||
wp2--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
506
Libraries/Concentus/CSharp/Concentus/Celt/Pitch.cs
Normal file
506
Libraries/Concentus/CSharp/Concentus/Celt/Pitch.cs
Normal file
@@ -0,0 +1,506 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Pitch
|
||||
{
|
||||
internal static void find_best_pitch(int[] xcorr, int[] y, int len,
|
||||
int max_pitch, int[]best_pitch,
|
||||
int yshift, int maxcorr
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
int Syy = 1;
|
||||
int best_num_0;
|
||||
int best_num_1;
|
||||
int best_den_0;
|
||||
int best_den_1;
|
||||
int xshift = Inlines.celt_ilog2(maxcorr) - 14;
|
||||
|
||||
best_num_0 = -1;
|
||||
best_num_1 = -1;
|
||||
best_den_0 = 0;
|
||||
best_den_1 = 0;
|
||||
best_pitch[0] = 0;
|
||||
best_pitch[1] = 1;
|
||||
for (j = 0; j < len; j++)
|
||||
Syy = Inlines.ADD32(Syy, Inlines.SHR32(Inlines.MULT16_16(y[j], y[j]), yshift));
|
||||
for (i = 0; i < max_pitch; i++)
|
||||
{
|
||||
if (xcorr[i] > 0)
|
||||
{
|
||||
int num;
|
||||
int xcorr16;
|
||||
xcorr16 = Inlines.EXTRACT16(Inlines.VSHR32(xcorr[i], xshift));
|
||||
num = Inlines.MULT16_16_Q15((xcorr16), (xcorr16));
|
||||
if (Inlines.MULT16_32_Q15(num, best_den_1) > Inlines.MULT16_32_Q15(best_num_1, Syy))
|
||||
{
|
||||
if (Inlines.MULT16_32_Q15(num, best_den_0) > Inlines.MULT16_32_Q15(best_num_0, Syy))
|
||||
{
|
||||
best_num_1 = best_num_0;
|
||||
best_den_1 = best_den_0;
|
||||
best_pitch[1] = best_pitch[0];
|
||||
best_num_0 = num;
|
||||
best_den_0 = Syy;
|
||||
best_pitch[0] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
best_num_1 = num;
|
||||
best_den_1 = Syy;
|
||||
best_pitch[1] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Syy += Inlines.SHR32(Inlines.MULT16_16(y[i + len], y[i + len]), yshift) - Inlines.SHR32(Inlines.MULT16_16(y[i], y[i]), yshift);
|
||||
Syy = Inlines.MAX32(1, Syy);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void celt_fir5(int[] x,
|
||||
int[] num,
|
||||
int[] y,
|
||||
int N,
|
||||
int[] mem)
|
||||
{
|
||||
int i;
|
||||
int num0, num1, num2, num3, num4;
|
||||
int mem0, mem1, mem2, mem3, mem4;
|
||||
num0 = num[0];
|
||||
num1 = num[1];
|
||||
num2 = num[2];
|
||||
num3 = num[3];
|
||||
num4 = num[4];
|
||||
mem0 = mem[0];
|
||||
mem1 = mem[1];
|
||||
mem2 = mem[2];
|
||||
mem3 = mem[3];
|
||||
mem4 = mem[4];
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
int sum = Inlines.SHL32(Inlines.EXTEND32(x[i]), CeltConstants.SIG_SHIFT);
|
||||
sum = Inlines.MAC16_16(sum, num0, (mem0));
|
||||
sum = Inlines.MAC16_16(sum, num1, (mem1));
|
||||
sum = Inlines.MAC16_16(sum, num2, (mem2));
|
||||
sum = Inlines.MAC16_16(sum, num3, (mem3));
|
||||
sum = Inlines.MAC16_16(sum, num4, (mem4));
|
||||
mem4 = mem3;
|
||||
mem3 = mem2;
|
||||
mem2 = mem1;
|
||||
mem1 = mem0;
|
||||
mem0 = x[i];
|
||||
y[i] = Inlines.ROUND16(sum, CeltConstants.SIG_SHIFT);
|
||||
}
|
||||
mem[0] = (mem0);
|
||||
mem[1] = (mem1);
|
||||
mem[2] = (mem2);
|
||||
mem[3] = (mem3);
|
||||
mem[4] = (mem4);
|
||||
}
|
||||
|
||||
|
||||
internal static void pitch_downsample(int[][] x, int[] x_lp, int len, int C)
|
||||
{
|
||||
int i;
|
||||
int[] ac = new int[5];
|
||||
int tmp = CeltConstants.Q15ONE;
|
||||
int[] lpc = new int[4];
|
||||
int[] mem = new int[] { 0, 0, 0, 0, 0 };
|
||||
int[] lpc2 = new int[5];
|
||||
int c1 = ((short)(0.5 + (0.8f) * (((int)1) << (15))))/*Inlines.QCONST16(0.8f, 15)*/;
|
||||
|
||||
int shift;
|
||||
int maxabs = Inlines.celt_maxabs32(x[0], 0, len);
|
||||
if (C == 2)
|
||||
{
|
||||
int maxabs_1 = Inlines.celt_maxabs32(x[1], 0, len);
|
||||
maxabs = Inlines.MAX32(maxabs, maxabs_1);
|
||||
}
|
||||
if (maxabs < 1)
|
||||
maxabs = 1;
|
||||
shift = Inlines.celt_ilog2(maxabs) - 10;
|
||||
if (shift < 0)
|
||||
shift = 0;
|
||||
if (C == 2)
|
||||
shift++;
|
||||
|
||||
int halflen = len >> 1; // cached for performance
|
||||
for (i = 1; i < halflen; i++)
|
||||
{
|
||||
x_lp[i] = (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][(2 * i - 1)] + x[0][(2 * i + 1)]) + x[0][2 * i]), shift));
|
||||
}
|
||||
|
||||
x_lp[0] = (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][1]) + x[0][0]), shift));
|
||||
|
||||
if (C == 2)
|
||||
{
|
||||
for (i = 1; i < halflen; i++)
|
||||
x_lp[i] += (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][(2 * i - 1)] + x[1][(2 * i + 1)]) + x[1][2 * i]), shift));
|
||||
x_lp[0] += (Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][1]) + x[1][0]), shift));
|
||||
}
|
||||
|
||||
Autocorrelation._celt_autocorr(x_lp, ac, null, 0, 4, halflen);
|
||||
|
||||
/* Noise floor -40 dB */
|
||||
ac[0] += Inlines.SHR32(ac[0], 13);
|
||||
/* Lag windowing */
|
||||
for (i = 1; i <= 4; i++)
|
||||
{
|
||||
/*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
|
||||
ac[i] -= Inlines.MULT16_32_Q15((2 * i * i), ac[i]);
|
||||
}
|
||||
|
||||
CeltLPC.celt_lpc(lpc, ac, 4);
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tmp = Inlines.MULT16_16_Q15(((short)(0.5 + (.9f) * (((int)1) << (15))))/*Inlines.QCONST16(.9f, 15)*/, tmp);
|
||||
lpc[i] = Inlines.MULT16_16_Q15(lpc[i], tmp);
|
||||
}
|
||||
/* Add a zero */
|
||||
lpc2[0] = (lpc[0] + ((short)(0.5 + (0.8f) * (((int)1) << (CeltConstants.SIG_SHIFT))))/*Inlines.QCONST16(0.8f, CeltConstants.SIG_SHIFT)*/);
|
||||
lpc2[1] = (lpc[1] + Inlines.MULT16_16_Q15(c1, lpc[0]));
|
||||
lpc2[2] = (lpc[2] + Inlines.MULT16_16_Q15(c1, lpc[1]));
|
||||
lpc2[3] = (lpc[3] + Inlines.MULT16_16_Q15(c1, lpc[2]));
|
||||
lpc2[4] = Inlines.MULT16_16_Q15(c1, lpc[3]);
|
||||
|
||||
celt_fir5(x_lp, lpc2, x_lp, halflen, mem);
|
||||
}
|
||||
|
||||
// Fixme: remove pointers and optimize
|
||||
internal static void pitch_search(int[] x_lp, int x_lp_ptr, int[] y,
|
||||
int len, int max_pitch, out int pitch)
|
||||
{
|
||||
int i, j;
|
||||
int lag;
|
||||
int[] best_pitch = new int[] { 0, 0 };
|
||||
int maxcorr;
|
||||
int xmax, ymax;
|
||||
int shift = 0;
|
||||
int offset;
|
||||
|
||||
Inlines.OpusAssert(len > 0);
|
||||
Inlines.OpusAssert(max_pitch > 0);
|
||||
lag = len + max_pitch;
|
||||
|
||||
int[] x_lp4 = new int[len >> 2];
|
||||
int[] y_lp4 = new int[lag >> 2];
|
||||
int[] xcorr = new int[max_pitch >> 1];
|
||||
|
||||
/* Downsample by 2 again */
|
||||
for (j = 0; j < len >> 2; j++)
|
||||
x_lp4[j] = x_lp[x_lp_ptr + (2 * j)];
|
||||
for (j = 0; j < lag >> 2; j++)
|
||||
y_lp4[j] = y[2 * j];
|
||||
|
||||
xmax = Inlines.celt_maxabs32(x_lp4, 0, len >> 2);
|
||||
ymax = Inlines.celt_maxabs32(y_lp4, 0, lag >> 2);
|
||||
shift = Inlines.celt_ilog2(Inlines.MAX32(1, Inlines.MAX32(xmax, ymax))) - 11;
|
||||
if (shift > 0)
|
||||
{
|
||||
for (j = 0; j < len >> 2; j++)
|
||||
x_lp4[j] = Inlines.SHR16(x_lp4[j], shift);
|
||||
for (j = 0; j < lag >> 2; j++)
|
||||
y_lp4[j] = Inlines.SHR16(y_lp4[j], shift);
|
||||
/* Use double the shift for a MAC */
|
||||
shift *= 2;
|
||||
}
|
||||
else {
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
/* Coarse search with 4x decimation */
|
||||
maxcorr = CeltPitchXCorr.pitch_xcorr(x_lp4, y_lp4, xcorr, len >> 2, max_pitch >> 2);
|
||||
|
||||
find_best_pitch(xcorr, y_lp4, len >> 2, max_pitch >> 2, best_pitch, 0, maxcorr);
|
||||
|
||||
/* Finer search with 2x decimation */
|
||||
maxcorr = 1;
|
||||
for (i = 0; i < max_pitch >> 1; i++)
|
||||
{
|
||||
int sum;
|
||||
xcorr[i] = 0;
|
||||
if (Inlines.abs(i - 2 * best_pitch[0]) > 2 && Inlines.abs(i - 2 * best_pitch[1]) > 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sum = 0;
|
||||
for (j = 0; j < len >> 1; j++)
|
||||
sum += Inlines.SHR32(Inlines.MULT16_16(x_lp[x_lp_ptr + j], y[i + j]), shift);
|
||||
|
||||
xcorr[i] = Inlines.MAX32(-1, sum);
|
||||
maxcorr = Inlines.MAX32(maxcorr, sum);
|
||||
}
|
||||
find_best_pitch(xcorr, y, len >> 1, max_pitch >> 1, best_pitch, shift + 1, maxcorr);
|
||||
|
||||
/* Refine by pseudo-interpolation */
|
||||
if (best_pitch[0] > 0 && best_pitch[0] < (max_pitch >> 1) - 1)
|
||||
{
|
||||
int a, b, c;
|
||||
a = xcorr[best_pitch[0] - 1];
|
||||
b = xcorr[best_pitch[0]];
|
||||
c = xcorr[best_pitch[0] + 1];
|
||||
if ((c - a) > Inlines.MULT16_32_Q15(((short)(0.5 + (.7f) * (((int)1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, b - a))
|
||||
{
|
||||
offset = 1;
|
||||
}
|
||||
else if ((a - c) > Inlines.MULT16_32_Q15(((short)(0.5 + (.7f) * (((int)1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, b - c))
|
||||
{
|
||||
offset = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
pitch = 2 * best_pitch[0] - offset;
|
||||
}
|
||||
|
||||
private static readonly int[] second_check = { 0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2 };
|
||||
|
||||
internal static int remove_doubling(int[] x, int maxperiod, int minperiod,
|
||||
int N, ref int T0_, int prev_period, int prev_gain)
|
||||
{
|
||||
int k, i, T, T0;
|
||||
int g, g0;
|
||||
int pg;
|
||||
int yy, xx, xy, xy2;
|
||||
int[] xcorr = new int[3];
|
||||
int best_xy, best_yy;
|
||||
int offset;
|
||||
int minperiod0 = minperiod;
|
||||
maxperiod /= 2;
|
||||
minperiod /= 2;
|
||||
T0_ /= 2;
|
||||
prev_period /= 2;
|
||||
N /= 2;
|
||||
int x_ptr = maxperiod;
|
||||
if (T0_ >= maxperiod)
|
||||
T0_ = maxperiod - 1;
|
||||
|
||||
T = T0 = T0_;
|
||||
int[] yy_lookup = new int[maxperiod + 1];
|
||||
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (int* px_base = x)
|
||||
{
|
||||
int* px = px_base + x_ptr;
|
||||
int* px2 = px_base + x_ptr - T0;
|
||||
Kernels.dual_inner_prod(px, px, px2, N, out xx, out xy);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Kernels.dual_inner_prod(x, x_ptr, x, x_ptr, x, x_ptr - T0, N, out xx, out xy);
|
||||
#endif
|
||||
|
||||
yy_lookup[0] = xx;
|
||||
yy = xx;
|
||||
for (i = 1; i <= maxperiod; i++)
|
||||
{
|
||||
int xi = x_ptr - i;
|
||||
yy = yy + Inlines.MULT16_16(x[xi], x[xi]) - Inlines.MULT16_16(x[xi + N], x[xi + N]);
|
||||
yy_lookup[i] = Inlines.MAX32(0, yy);
|
||||
}
|
||||
yy = yy_lookup[T0];
|
||||
best_xy = xy;
|
||||
best_yy = yy;
|
||||
|
||||
{
|
||||
int x2y2;
|
||||
int sh, t;
|
||||
x2y2 = 1 + Inlines.HALF32(Inlines.MULT32_32_Q31(xx, yy));
|
||||
sh = Inlines.celt_ilog2(x2y2) >> 1;
|
||||
t = Inlines.VSHR32(x2y2, 2 * (sh - 7));
|
||||
g = (Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(t), xy), sh + 1));
|
||||
g0 = g;
|
||||
}
|
||||
|
||||
/* Look for any pitch at T/k */
|
||||
for (k = 2; k <= 15; k++)
|
||||
{
|
||||
int T1, T1b;
|
||||
int g1;
|
||||
int cont = 0;
|
||||
int thresh;
|
||||
T1 = Inlines.celt_udiv(2 * T0 + k, 2 * k);
|
||||
if (T1 < minperiod)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Look for another strong correlation at T1b */
|
||||
if (k == 2)
|
||||
{
|
||||
if (T1 + T0 > maxperiod)
|
||||
T1b = T0;
|
||||
else
|
||||
T1b = T0 + T1;
|
||||
}
|
||||
else
|
||||
{
|
||||
T1b = Inlines.celt_udiv(2 * second_check[k] * T0 + k, 2 * k);
|
||||
}
|
||||
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (int* px_base = x)
|
||||
{
|
||||
int* px = px_base + x_ptr;
|
||||
int* px2 = px_base + x_ptr - T1;
|
||||
int* px3 = px_base + x_ptr - T1b;
|
||||
Kernels.dual_inner_prod(px, px2, px3, N, out xy, out xy2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Kernels.dual_inner_prod(x, x_ptr, x, x_ptr - T1, x, x_ptr - T1b, N, out xy, out xy2);
|
||||
#endif
|
||||
|
||||
xy += xy2;
|
||||
yy = yy_lookup[T1] + yy_lookup[T1b];
|
||||
|
||||
{
|
||||
int x2y2;
|
||||
int sh, t;
|
||||
x2y2 = 1 + Inlines.MULT32_32_Q31(xx, yy);
|
||||
sh = Inlines.celt_ilog2(x2y2) >> 1;
|
||||
t = Inlines.VSHR32(x2y2, 2 * (sh - 7));
|
||||
g1 = (Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(t), xy), sh + 1));
|
||||
}
|
||||
|
||||
if (Inlines.abs(T1 - prev_period) <= 1)
|
||||
cont = prev_gain;
|
||||
else if (Inlines.abs(T1 - prev_period) <= 2 && 5 * k * k < T0)
|
||||
{
|
||||
cont = Inlines.HALF16(prev_gain);
|
||||
}
|
||||
else
|
||||
{
|
||||
cont = 0;
|
||||
}
|
||||
thresh = Inlines.MAX16(((short)(0.5 + (.3f) * (((int)1) << (15))))/*Inlines.QCONST16(.3f, 15)*/, (Inlines.MULT16_16_Q15(((short)(0.5 + (.7f) * (((int)1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, g0) - cont));
|
||||
|
||||
/* Bias against very high pitch (very short period) to avoid false-positives
|
||||
due to short-term correlation */
|
||||
if (T1 < 3 * minperiod)
|
||||
{
|
||||
thresh = Inlines.MAX16(((short)(0.5 + (.4f) * (((int)1) << (15))))/*Inlines.QCONST16(.4f, 15)*/, (Inlines.MULT16_16_Q15(((short)(0.5 + (.85f) * (((int)1) << (15))))/*Inlines.QCONST16(.85f, 15)*/, g0) - cont));
|
||||
}
|
||||
else if (T1 < 2 * minperiod)
|
||||
{
|
||||
thresh = Inlines.MAX16(((short)(0.5 + (.5f) * (((int)1) << (15))))/*Inlines.QCONST16(.5f, 15)*/, (Inlines.MULT16_16_Q15(((short)(0.5 + (.9f) * (((int)1) << (15))))/*Inlines.QCONST16(.9f, 15)*/, g0) - cont));
|
||||
}
|
||||
if (g1 > thresh)
|
||||
{
|
||||
best_xy = xy;
|
||||
best_yy = yy;
|
||||
T = T1;
|
||||
g = g1;
|
||||
}
|
||||
}
|
||||
|
||||
best_xy = Inlines.MAX32(0, best_xy);
|
||||
if (best_yy <= best_xy)
|
||||
{
|
||||
pg = CeltConstants.Q15ONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pg = (Inlines.SHR32(Inlines.frac_div32(best_xy, best_yy + 1), 16));
|
||||
}
|
||||
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (int* px_base = x)
|
||||
{
|
||||
int* px = px_base + x_ptr;
|
||||
for (k = 0; k < 3; k++)
|
||||
{
|
||||
xcorr[k] = Kernels.celt_inner_prod(px, px - (T + k - 1), N);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (k = 0; k < 3; k++)
|
||||
{
|
||||
xcorr[k] = Kernels.celt_inner_prod(x, x_ptr, x, x_ptr - (T + k - 1), N);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((xcorr[2] - xcorr[0]) > Inlines.MULT16_32_Q15(((short)(0.5 + (.7f) * (((int)1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, xcorr[1] - xcorr[0]))
|
||||
{
|
||||
offset = 1;
|
||||
}
|
||||
else if ((xcorr[0] - xcorr[2]) > Inlines.MULT16_32_Q15(((short)(0.5 + (.7f) * (((int)1) << (15))))/*Inlines.QCONST16(.7f, 15)*/, xcorr[1] - xcorr[2]))
|
||||
{
|
||||
offset = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (pg > g)
|
||||
{
|
||||
pg = g;
|
||||
}
|
||||
|
||||
T0_ = 2 * T + offset;
|
||||
|
||||
if (T0_ < minperiod0)
|
||||
{
|
||||
T0_ = minperiod0;
|
||||
}
|
||||
|
||||
return pg;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
524
Libraries/Concentus/CSharp/Concentus/Celt/QuantizeBands.cs
Normal file
524
Libraries/Concentus/CSharp/Concentus/Celt/QuantizeBands.cs
Normal file
@@ -0,0 +1,524 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class QuantizeBands
|
||||
{
|
||||
/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */
|
||||
private static readonly int[] pred_coef = new int[]{ 29440, 26112, 21248, 16384 };
|
||||
private static readonly int[] beta_coef = new int[] { 30147, 22282, 12124, 6554 };
|
||||
private static readonly int beta_intra = 4915;
|
||||
private static byte[] small_energy_icdf = { 2, 1, 0 };
|
||||
|
||||
internal static int loss_distortion(int[][] eBands, int[][] oldEBands, int start, int end, int len, int C)
|
||||
{
|
||||
int c, i;
|
||||
int dist = 0;
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
int d = Inlines.SUB16(Inlines.SHR16(eBands[c][i], 3), Inlines.SHR16(oldEBands[c][i], 3));
|
||||
dist = Inlines.MAC16_16(dist, d, d);
|
||||
}
|
||||
} while (++c < C);
|
||||
|
||||
return Inlines.MIN32(200, Inlines.SHR32(dist, 2 * CeltConstants.DB_SHIFT - 6));
|
||||
}
|
||||
|
||||
internal static int quant_coarse_energy_impl(CeltMode m, int start, int end,
|
||||
int[][] eBands, int[][] oldEBands,
|
||||
int budget, int tell,
|
||||
byte[] prob_model, int[][] error, EntropyCoder enc,
|
||||
int C, int LM, int intra, int max_decay, int lfe)
|
||||
{
|
||||
int i, c;
|
||||
int badness = 0;
|
||||
int[] prev = { 0, 0 };
|
||||
int coef;
|
||||
int beta;
|
||||
|
||||
if (tell + 3 <= budget)
|
||||
{
|
||||
enc.enc_bit_logp(intra, 3);
|
||||
}
|
||||
|
||||
if (intra != 0)
|
||||
{
|
||||
coef = 0;
|
||||
beta = beta_intra;
|
||||
}
|
||||
else {
|
||||
beta = beta_coef[LM];
|
||||
coef = pred_coef[LM];
|
||||
}
|
||||
|
||||
/* Encode at a fixed coarse resolution */
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
int bits_left;
|
||||
int qi, qi0;
|
||||
int q;
|
||||
int x;
|
||||
int f, tmp;
|
||||
int oldE;
|
||||
int decay_bound;
|
||||
x = eBands[c][i];
|
||||
oldE = Inlines.MAX16(-((short)(0.5 + (9.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(9.0f, CeltConstants.DB_SHIFT)*/, oldEBands[c][i]);
|
||||
f = Inlines.SHL32(Inlines.EXTEND32(x), 7) - Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) - prev[c];
|
||||
/* Rounding to nearest integer here is really important! */
|
||||
qi = (f + ((int)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT + 7))))/*Inlines.QCONST32(.5f, CeltConstants.DB_SHIFT + 7)*/) >> (CeltConstants.DB_SHIFT + 7);
|
||||
decay_bound = Inlines.EXTRACT16(Inlines.MAX32(-((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/,
|
||||
Inlines.SUB32((int)oldEBands[c][i], max_decay)));
|
||||
/* Prevent the energy from going down too quickly (e.g. for bands
|
||||
that have just one bin) */
|
||||
if (qi < 0 && x < decay_bound)
|
||||
{
|
||||
qi += (int)Inlines.SHR16(Inlines.SUB16(decay_bound, x), CeltConstants.DB_SHIFT);
|
||||
if (qi > 0)
|
||||
qi = 0;
|
||||
}
|
||||
qi0 = qi;
|
||||
/* If we don't have enough bits to encode all the energy, just assume
|
||||
something safe. */
|
||||
tell = enc.tell();
|
||||
bits_left = budget - tell - 3 * C * (end - i);
|
||||
if (i != start && bits_left < 30)
|
||||
{
|
||||
if (bits_left < 24)
|
||||
qi = Inlines.IMIN(1, qi);
|
||||
if (bits_left < 16)
|
||||
qi = Inlines.IMAX(-1, qi);
|
||||
}
|
||||
if (lfe != 0 && i >= 2)
|
||||
qi = Inlines.IMIN(qi, 0);
|
||||
if (budget - tell >= 15)
|
||||
{
|
||||
int pi;
|
||||
pi = 2 * Inlines.IMIN(i, 20);
|
||||
Laplace.ec_laplace_encode(enc, ref qi, (((uint)prob_model[pi]) << 7), ((int)prob_model[pi + 1]) << 6);
|
||||
}
|
||||
else if (budget - tell >= 2)
|
||||
{
|
||||
qi = Inlines.IMAX(-1, Inlines.IMIN(qi, 1));
|
||||
enc.enc_icdf(2 * qi ^ (0 - (qi < 0 ? 1 : 0)), small_energy_icdf, 2);
|
||||
}
|
||||
else if (budget - tell >= 1)
|
||||
{
|
||||
qi = Inlines.IMIN(0, qi);
|
||||
enc.enc_bit_logp(-qi, 1);
|
||||
}
|
||||
else
|
||||
qi = -1;
|
||||
error[c][i] = (Inlines.PSHR32(f, 7) - Inlines.SHL16((qi), CeltConstants.DB_SHIFT));
|
||||
badness += Inlines.abs(qi0 - qi);
|
||||
q = (int)Inlines.SHL32(qi, CeltConstants.DB_SHIFT); // opus bug: useless extend32
|
||||
|
||||
tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) + prev[c] + Inlines.SHL32(q, 7);
|
||||
tmp = Inlines.MAX32(-((int)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT + 7))))/*Inlines.QCONST32(28.0f, CeltConstants.DB_SHIFT + 7)*/, tmp);
|
||||
oldEBands[c][i] = (Inlines.PSHR32(tmp, 7));
|
||||
prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8));
|
||||
} while (++c < C);
|
||||
}
|
||||
return lfe != 0 ? 0 : badness;
|
||||
}
|
||||
|
||||
internal static void quant_coarse_energy(CeltMode m, int start, int end, int effEnd,
|
||||
int[][] eBands, int[][] oldEBands, uint budget,
|
||||
int[][] error, EntropyCoder enc, int C, int LM, int nbAvailableBytes,
|
||||
int force_intra, ref int delayedIntra, int two_pass, int loss_rate, int lfe)
|
||||
{
|
||||
int intra;
|
||||
int max_decay;
|
||||
int[][] oldEBands_intra;
|
||||
int[][] error_intra;
|
||||
EntropyCoder enc_start_state = new EntropyCoder(); // [porting note] stack variable
|
||||
uint tell;
|
||||
int badness1 = 0;
|
||||
int intra_bias;
|
||||
int new_distortion;
|
||||
|
||||
|
||||
intra = (force_intra != 0 || (two_pass == 0 && delayedIntra > 2 * C * (end - start) && nbAvailableBytes > (end - start) * C)) ? 1 : 0;
|
||||
intra_bias = (int)((budget * delayedIntra * loss_rate) / (C * 512));
|
||||
new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m.nbEBands, C);
|
||||
|
||||
tell = (uint)enc.tell();
|
||||
if (tell + 3 > budget)
|
||||
two_pass = intra = 0;
|
||||
|
||||
max_decay = ((short)(0.5 + (16.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(16.0f, CeltConstants.DB_SHIFT)*/;
|
||||
if (end - start > 10)
|
||||
{
|
||||
max_decay = (Inlines.MIN32(max_decay, Inlines.SHL32(nbAvailableBytes, CeltConstants.DB_SHIFT - 3))); // opus bug: useless extend32
|
||||
}
|
||||
if (lfe != 0)
|
||||
{
|
||||
max_decay = ((short)(0.5 + (3.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(3.0f, CeltConstants.DB_SHIFT)*/;
|
||||
}
|
||||
enc_start_state.Assign(enc);
|
||||
|
||||
oldEBands_intra = Arrays.InitTwoDimensionalArray<int>(C, m.nbEBands);
|
||||
error_intra = Arrays.InitTwoDimensionalArray<int>(C, m.nbEBands);
|
||||
Array.Copy(oldEBands[0], 0, oldEBands_intra[0], 0, m.nbEBands);
|
||||
if (C == 2)
|
||||
Array.Copy(oldEBands[1], 0, oldEBands_intra[1], 0, m.nbEBands);
|
||||
|
||||
if (two_pass != 0 || intra != 0)
|
||||
{
|
||||
badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, (int)budget,
|
||||
(int)tell, Tables.e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe);
|
||||
}
|
||||
|
||||
if (intra == 0)
|
||||
{
|
||||
int intra_buf;
|
||||
EntropyCoder enc_intra_state = new EntropyCoder(); // [porting note] stack variable
|
||||
int tell_intra;
|
||||
uint nstart_bytes;
|
||||
uint nintra_bytes;
|
||||
uint save_bytes;
|
||||
int badness2;
|
||||
byte[] intra_bits = null;
|
||||
|
||||
tell_intra = (int)enc.tell_frac();
|
||||
|
||||
enc_intra_state.Assign(enc);
|
||||
|
||||
nstart_bytes = enc_start_state.range_bytes();
|
||||
nintra_bytes = enc_intra_state.range_bytes();
|
||||
intra_buf = enc_intra_state.buf_ptr + (int)nstart_bytes;
|
||||
save_bytes = nintra_bytes - nstart_bytes;
|
||||
|
||||
if (save_bytes != 0)
|
||||
{
|
||||
intra_bits = new byte[(int)save_bytes];
|
||||
/* Copy bits from intra bit-stream */
|
||||
Array.Copy(enc_intra_state.buf, intra_buf, intra_bits, 0, (int)save_bytes);
|
||||
}
|
||||
|
||||
enc.Assign(enc_start_state);
|
||||
|
||||
badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, (int)budget,
|
||||
(int)tell, Tables.e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe);
|
||||
|
||||
if (two_pass != 0 && (badness1 < badness2 || (badness1 == badness2 && ((int)enc.tell_frac()) + intra_bias > tell_intra)))
|
||||
{
|
||||
enc.Assign(enc_intra_state);
|
||||
/* Copy intra bits to bit-stream */
|
||||
if (intra_bits != null)
|
||||
{
|
||||
Array.Copy(intra_bits, 0, enc_intra_state.buf, intra_buf, (int)(nintra_bytes - nstart_bytes));
|
||||
}
|
||||
Array.Copy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands);
|
||||
Array.Copy(error_intra[0], 0, error[0], 0, m.nbEBands);
|
||||
if (C == 2)
|
||||
{
|
||||
Array.Copy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands);
|
||||
Array.Copy(error_intra[1], 0, error[1], 0, m.nbEBands);
|
||||
}
|
||||
intra = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands);
|
||||
Array.Copy(error_intra[0], 0, error[0], 0, m.nbEBands);
|
||||
if (C == 2)
|
||||
{
|
||||
Array.Copy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands);
|
||||
Array.Copy(error_intra[1], 0, error[1], 0, m.nbEBands);
|
||||
}
|
||||
}
|
||||
|
||||
if (intra != 0)
|
||||
{
|
||||
delayedIntra = new_distortion;
|
||||
}
|
||||
else
|
||||
{
|
||||
delayedIntra = Inlines.ADD32(Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(pred_coef[LM], pred_coef[LM]), delayedIntra),
|
||||
new_distortion);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void quant_fine_energy(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, EntropyCoder enc, int C)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
/* Encode finer resolution */
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
int frac = (1 << fine_quant[i]);
|
||||
if (fine_quant[i] <= 0)
|
||||
continue;
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
int q2;
|
||||
int offset;
|
||||
/* Has to be without rounding */
|
||||
q2 = (error[c][i] + ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/) >> (CeltConstants.DB_SHIFT - fine_quant[i]);
|
||||
if (q2 > frac - 1)
|
||||
q2 = frac - 1;
|
||||
if (q2 < 0)
|
||||
q2 = 0;
|
||||
enc.enc_bits((uint)q2, (uint)fine_quant[i]);
|
||||
offset = Inlines.SUB16(
|
||||
(Inlines.SHR32(
|
||||
Inlines.SHL32(q2, CeltConstants.DB_SHIFT) + ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/,
|
||||
fine_quant[i])),
|
||||
((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/);
|
||||
oldEBands[c][i] += offset;
|
||||
error[c][i] -= offset;
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void quant_energy_finalise(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder enc, int C)
|
||||
{
|
||||
int i, prio, c;
|
||||
|
||||
/* Use up the remaining bits */
|
||||
for (prio = 0; prio < 2; prio++)
|
||||
{
|
||||
for (i = start; i < end && bits_left >= C; i++)
|
||||
{
|
||||
if (fine_quant[i] >= CeltConstants.MAX_FINE_BITS || fine_priority[i] != prio)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
int q2;
|
||||
int offset;
|
||||
q2 = error[c][i] < 0 ? 0 : 1;
|
||||
enc.enc_bits((uint)q2, 1);
|
||||
offset = Inlines.SHR16((Inlines.SHL16((q2), CeltConstants.DB_SHIFT) - ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/), fine_quant[i] + 1);
|
||||
oldEBands[c][i] += offset;
|
||||
bits_left--;
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void unquant_coarse_energy(CeltMode m, int start, int end, int[] oldEBands, int intra, EntropyCoder dec, int C, int LM)
|
||||
{
|
||||
byte[] prob_model = Tables.e_prob_model[LM][intra];
|
||||
int i, c;
|
||||
int[] prev = { 0, 0 };
|
||||
int coef;
|
||||
int beta;
|
||||
int budget;
|
||||
int tell;
|
||||
|
||||
if (intra != 0)
|
||||
{
|
||||
coef = 0;
|
||||
beta = beta_intra;
|
||||
}
|
||||
else {
|
||||
beta = beta_coef[LM];
|
||||
coef = pred_coef[LM];
|
||||
}
|
||||
|
||||
budget = (int)dec.storage * 8;
|
||||
|
||||
/* Decode at a fixed coarse resolution */
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
int qi;
|
||||
int q;
|
||||
int tmp;
|
||||
/* It would be better to express this invariant as a
|
||||
test on C at function entry, but that isn't enough
|
||||
to make the static analyzer happy. */
|
||||
Inlines.OpusAssert(c < 2);
|
||||
tell = dec.tell();
|
||||
if (budget - tell >= 15)
|
||||
{
|
||||
int pi;
|
||||
pi = 2 * Inlines.IMIN(i, 20);
|
||||
qi = Laplace.ec_laplace_decode(dec,
|
||||
(uint)prob_model[pi] << 7, prob_model[pi + 1] << 6);
|
||||
}
|
||||
else if (budget - tell >= 2)
|
||||
{
|
||||
qi = dec.dec_icdf(small_energy_icdf, 2);
|
||||
qi = (qi >> 1) ^ -(qi & 1);
|
||||
}
|
||||
else if (budget - tell >= 1)
|
||||
{
|
||||
qi = 0 - dec.dec_bit_logp(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
qi = -1;
|
||||
}
|
||||
q = (int)Inlines.SHL32(qi, CeltConstants.DB_SHIFT); // opus bug: useless extend32
|
||||
|
||||
oldEBands[i + c * m.nbEBands] = Inlines.MAX16((0 - ((short)(0.5 + (9.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(9.0f, CeltConstants.DB_SHIFT)*/), oldEBands[i + c * m.nbEBands]);
|
||||
tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldEBands[i + c * m.nbEBands]), 8) + prev[c] + Inlines.SHL32(q, 7);
|
||||
tmp = Inlines.MAX32(-((int)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT + 7))))/*Inlines.QCONST32(28.0f, CeltConstants.DB_SHIFT + 7)*/, tmp);
|
||||
oldEBands[i + c * m.nbEBands] = (Inlines.PSHR32(tmp, 7));
|
||||
prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8));
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void unquant_fine_energy(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, EntropyCoder dec, int C)
|
||||
{
|
||||
int i, c;
|
||||
/* Decode finer resolution */
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
if (fine_quant[i] <= 0)
|
||||
continue;
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
int q2;
|
||||
int offset;
|
||||
q2 = (int)dec.dec_bits((uint)fine_quant[i]);
|
||||
offset = Inlines.SUB16((Inlines.SHR32(
|
||||
Inlines.SHL32(q2, CeltConstants.DB_SHIFT) +
|
||||
((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/, fine_quant[i])),
|
||||
((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/); // opus bug: unnecessary extend32
|
||||
oldEBands[i + c * m.nbEBands] += offset;
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void unquant_energy_finalise(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder dec, int C)
|
||||
{
|
||||
int i, prio, c;
|
||||
|
||||
/* Use up the remaining bits */
|
||||
for (prio = 0; prio < 2; prio++)
|
||||
{
|
||||
for (i = start; i < end && bits_left >= C; i++)
|
||||
{
|
||||
if (fine_quant[i] >= CeltConstants.MAX_FINE_BITS || fine_priority[i] != prio)
|
||||
continue;
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
int q2;
|
||||
int offset;
|
||||
q2 = (int)dec.dec_bits(1);
|
||||
offset = Inlines.SHR16((Inlines.SHL16((q2), CeltConstants.DB_SHIFT) - ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/), fine_quant[i] + 1);
|
||||
oldEBands[i + c * m.nbEBands] += offset;
|
||||
bits_left--;
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// non-pointer case
|
||||
/// </summary>
|
||||
/// <param name="m"></param>
|
||||
/// <param name="effEnd"></param>
|
||||
/// <param name="end"></param>
|
||||
/// <param name="bandE"></param>
|
||||
/// <param name="bandLogE"></param>
|
||||
/// <param name="C"></param>
|
||||
internal static void amp2Log2(CeltMode m, int effEnd, int end,
|
||||
int[][] bandE, int[][] bandLogE, int C)
|
||||
{
|
||||
int c, i;
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
for (i = 0; i < effEnd; i++)
|
||||
{
|
||||
bandLogE[c][i] =
|
||||
(Inlines.celt_log2(Inlines.SHL32(bandE[c][i], 2))
|
||||
- Inlines.SHL16((int)Tables.eMeans[i], 6));
|
||||
}
|
||||
for (i = effEnd; i < end; i++)
|
||||
{
|
||||
bandLogE[c][i] = (0 - ((short)(0.5 + (14.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(14.0f, CeltConstants.DB_SHIFT)*/);
|
||||
}
|
||||
} while (++c < C);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// only needed in one place
|
||||
/// </summary>
|
||||
/// <param name="m"></param>
|
||||
/// <param name="effEnd"></param>
|
||||
/// <param name="end"></param>
|
||||
/// <param name="bandE"></param>
|
||||
/// <param name="bandLogE"></param>
|
||||
/// <param name="C"></param>
|
||||
internal static void amp2Log2(CeltMode m, int effEnd, int end,
|
||||
int[] bandE, int[] bandLogE, int bandLogE_ptr, int C)
|
||||
{
|
||||
int c, i;
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
for (i = 0; i < effEnd; i++)
|
||||
{
|
||||
bandLogE[bandLogE_ptr + (c * m.nbEBands) + i] =
|
||||
(Inlines.celt_log2(Inlines.SHL32(bandE[i + c * m.nbEBands], 2))
|
||||
- Inlines.SHL16((int)Tables.eMeans[i], 6));
|
||||
}
|
||||
for (i = effEnd; i < end; i++)
|
||||
{
|
||||
bandLogE[bandLogE_ptr + (c * m.nbEBands) + i] = (0 - ((short)(0.5 + (14.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(14.0f, CeltConstants.DB_SHIFT)*/);
|
||||
}
|
||||
} while (++c < C);
|
||||
}
|
||||
}
|
||||
}
|
||||
519
Libraries/Concentus/CSharp/Concentus/Celt/Rate.cs
Normal file
519
Libraries/Concentus/CSharp/Concentus/Celt/Rate.cs
Normal file
@@ -0,0 +1,519 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Rate
|
||||
{
|
||||
private static readonly byte[] LOG2_FRAC_TABLE ={
|
||||
0,
|
||||
8,13,
|
||||
16,19,21,23,
|
||||
24,26,27,28,29,30,31,32,
|
||||
32,33,34,34,35,36,36,37,37
|
||||
};
|
||||
|
||||
private const int ALLOC_STEPS = 6;
|
||||
|
||||
internal static int get_pulses(int i)
|
||||
{
|
||||
return i < 8 ? i : (8 + (i & 7)) << ((i >> 3) - 1);
|
||||
}
|
||||
|
||||
internal static int bits2pulses(CeltMode m, int band, int LM, int bits)
|
||||
{
|
||||
int i;
|
||||
int lo, hi;
|
||||
|
||||
LM++;
|
||||
byte[] cache = m.cache.bits;
|
||||
int cache_ptr = m.cache.index[LM * m.nbEBands + band];
|
||||
|
||||
lo = 0;
|
||||
hi = cache[cache_ptr];
|
||||
bits--;
|
||||
for (i = 0; i < CeltConstants.LOG_MAX_PSEUDO; i++)
|
||||
{
|
||||
int mid = (lo + hi + 1) >> 1;
|
||||
/* OPT: Make sure this is implemented with a conditional move */
|
||||
if ((int)cache[cache_ptr + mid] >= bits)
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid;
|
||||
}
|
||||
if (bits - (lo == 0 ? -1 : (int)cache[cache_ptr + lo]) <= (int)cache[cache_ptr + hi] - bits)
|
||||
return lo;
|
||||
else
|
||||
return hi;
|
||||
}
|
||||
|
||||
internal static int pulses2bits(CeltMode m, int band, int LM, int pulses)
|
||||
{
|
||||
LM++;
|
||||
return pulses == 0 ? 0 : m.cache.bits[m.cache.index[LM * m.nbEBands + band] + pulses] + 1;
|
||||
}
|
||||
|
||||
internal static int interp_bits2pulses(CeltMode m, int start, int end, int skip_start,
|
||||
int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, out int _balance,
|
||||
int skip_rsv, ref int intensity, int intensity_rsv, ref int dual_stereo, int dual_stereo_rsv, int[] bits,
|
||||
int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth)
|
||||
{
|
||||
int psum;
|
||||
int lo, hi;
|
||||
int i, j;
|
||||
int logM;
|
||||
int stereo;
|
||||
int codedBands = -1;
|
||||
int alloc_floor;
|
||||
int left, percoeff;
|
||||
int done;
|
||||
int balance;
|
||||
|
||||
|
||||
alloc_floor = C << EntropyCoder.BITRES;
|
||||
stereo = C > 1 ? 1 : 0;
|
||||
|
||||
logM = LM << EntropyCoder.BITRES;
|
||||
lo = 0;
|
||||
hi = 1 << ALLOC_STEPS;
|
||||
for (i = 0; i < ALLOC_STEPS; i++)
|
||||
{
|
||||
int mid = (lo + hi) >> 1;
|
||||
psum = 0;
|
||||
done = 0;
|
||||
for (j = end; j-- > start;)
|
||||
{
|
||||
int tmp = bits1[j] + (mid * (int)bits2[j] >> ALLOC_STEPS);
|
||||
if (tmp >= thresh[j] || done != 0)
|
||||
{
|
||||
done = 1;
|
||||
/* Don't allocate more than we can actually use */
|
||||
psum += Inlines.IMIN(tmp, cap[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmp >= alloc_floor)
|
||||
psum += alloc_floor;
|
||||
}
|
||||
}
|
||||
if (psum > total)
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid;
|
||||
}
|
||||
psum = 0;
|
||||
/*printf ("interp bisection gave %d\n", lo);*/
|
||||
done = 0;
|
||||
for (j = end; j-- > start;)
|
||||
{
|
||||
int tmp = bits1[j] + (lo * bits2[j] >> ALLOC_STEPS);
|
||||
if (tmp < thresh[j] && done == 0)
|
||||
{
|
||||
if (tmp >= alloc_floor)
|
||||
tmp = alloc_floor;
|
||||
else
|
||||
tmp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
done = 1;
|
||||
}
|
||||
|
||||
/* Don't allocate more than we can actually use */
|
||||
tmp = Inlines.IMIN(tmp, cap[j]);
|
||||
bits[j] = tmp;
|
||||
psum += tmp;
|
||||
}
|
||||
|
||||
/* Decide which bands to skip, working backwards from the end. */
|
||||
for (codedBands = end; ; codedBands--)
|
||||
{
|
||||
int band_width;
|
||||
int band_bits;
|
||||
int rem;
|
||||
j = codedBands - 1;
|
||||
/* Never skip the first band, nor a band that has been boosted by
|
||||
dynalloc.
|
||||
In the first case, we'd be coding a bit to signal we're going to waste
|
||||
all the other bits.
|
||||
In the second case, we'd be coding a bit to redistribute all the bits
|
||||
we just signaled should be cocentrated in this band. */
|
||||
if (j <= skip_start)
|
||||
{
|
||||
/* Give the bit we reserved to end skipping back. */
|
||||
total += skip_rsv;
|
||||
break;
|
||||
}
|
||||
|
||||
/*Figure out how many left-over bits we would be adding to this band.
|
||||
This can include bits we've stolen back from higher, skipped bands.*/
|
||||
left = total - psum;
|
||||
percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
|
||||
left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
|
||||
rem = Inlines.IMAX(left - (m.eBands[j] - m.eBands[start]), 0);
|
||||
band_width = m.eBands[codedBands] - m.eBands[j];
|
||||
band_bits = (int)(bits[j] + percoeff * band_width + rem);
|
||||
/*Only code a skip decision if we're above the threshold for this band.
|
||||
Otherwise it is force-skipped.
|
||||
This ensures that we have enough bits to code the skip flag.*/
|
||||
if (band_bits >= Inlines.IMAX(thresh[j], alloc_floor + (1 << EntropyCoder.BITRES)))
|
||||
{
|
||||
if (encode != 0)
|
||||
{
|
||||
/*This if() block is the only part of the allocation function that
|
||||
is not a mandatory part of the bitstream: any bands we choose to
|
||||
skip here must be explicitly signaled.*/
|
||||
/*Choose a threshold with some hysteresis to keep bands from
|
||||
fluctuating in and out.*/
|
||||
#if FUZZING
|
||||
if ((new Random().Next() & 0x1) == 0)
|
||||
#else
|
||||
if (codedBands <= start + 2 || (band_bits > ((j < prev ? 7 : 9) * band_width << LM << EntropyCoder.BITRES) >> 4 && j <= signalBandwidth))
|
||||
#endif
|
||||
{
|
||||
ec.enc_bit_logp(1, 1);
|
||||
break;
|
||||
}
|
||||
ec.enc_bit_logp(0, 1);
|
||||
}
|
||||
else if (ec.dec_bit_logp(1) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/*We used a bit to skip this band.*/
|
||||
psum += 1 << EntropyCoder.BITRES;
|
||||
band_bits -= 1 << EntropyCoder.BITRES;
|
||||
}
|
||||
/*Reclaim the bits originally allocated to this band.*/
|
||||
psum -= bits[j] + intensity_rsv;
|
||||
if (intensity_rsv > 0)
|
||||
intensity_rsv = LOG2_FRAC_TABLE[j - start];
|
||||
psum += intensity_rsv;
|
||||
if (band_bits >= alloc_floor)
|
||||
{
|
||||
/*If we have enough for a fine energy bit per channel, use it.*/
|
||||
psum += alloc_floor;
|
||||
bits[j] = alloc_floor;
|
||||
}
|
||||
else {
|
||||
/*Otherwise this band gets nothing at all.*/
|
||||
bits[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(codedBands > start);
|
||||
/* Code the intensity and dual stereo parameters. */
|
||||
if (intensity_rsv > 0)
|
||||
{
|
||||
if (encode != 0)
|
||||
{
|
||||
intensity = Inlines.IMIN(intensity, codedBands);
|
||||
ec.enc_uint((uint)(intensity - start), (uint)(codedBands + 1 - start));
|
||||
}
|
||||
else
|
||||
{
|
||||
intensity = start + (int)ec.dec_uint((uint)(codedBands + 1 - start));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
intensity = 0;
|
||||
}
|
||||
|
||||
if (intensity <= start)
|
||||
{
|
||||
total += dual_stereo_rsv;
|
||||
dual_stereo_rsv = 0;
|
||||
}
|
||||
if (dual_stereo_rsv > 0)
|
||||
{
|
||||
if (encode != 0)
|
||||
{
|
||||
ec.enc_bit_logp(dual_stereo, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dual_stereo = ec.dec_bit_logp(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dual_stereo = 0;
|
||||
}
|
||||
|
||||
/* Allocate the remaining bits */
|
||||
left = total - psum;
|
||||
percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]);
|
||||
left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff;
|
||||
for (j = start; j < codedBands; j++)
|
||||
bits[j] += ((int)percoeff * (m.eBands[j + 1] - m.eBands[j]));
|
||||
for (j = start; j < codedBands; j++)
|
||||
{
|
||||
int tmp = (int)Inlines.IMIN(left, m.eBands[j + 1] - m.eBands[j]);
|
||||
bits[j] += tmp;
|
||||
left -= tmp;
|
||||
}
|
||||
/*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/
|
||||
|
||||
balance = 0;
|
||||
for (j = start; j < codedBands; j++)
|
||||
{
|
||||
int N0, N, den;
|
||||
int offset;
|
||||
int NClogN;
|
||||
int excess, bit;
|
||||
|
||||
Inlines.OpusAssert(bits[j] >= 0);
|
||||
N0 = m.eBands[j + 1] - m.eBands[j];
|
||||
N = N0 << LM;
|
||||
bit = (int)bits[j] + balance;
|
||||
|
||||
if (N > 1)
|
||||
{
|
||||
excess = Inlines.MAX32(bit - cap[j], 0);
|
||||
bits[j] = bit - excess;
|
||||
|
||||
/* Compensate for the extra DoF in stereo */
|
||||
den = (C * N + ((C == 2 && N > 2 && (dual_stereo == 0) && j < intensity) ? 1 : 0));
|
||||
|
||||
NClogN = den * (m.logN[j] + logM);
|
||||
|
||||
/* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
|
||||
compared to their "fair share" of total/N */
|
||||
offset = (NClogN >> 1) - den * CeltConstants.FINE_OFFSET;
|
||||
|
||||
/* N=2 is the only point that doesn't match the curve */
|
||||
if (N == 2)
|
||||
offset += den << EntropyCoder.BITRES >> 2;
|
||||
|
||||
/* Changing the offset for allocating the second and third
|
||||
fine energy bit */
|
||||
if (bits[j] + offset < den * 2 << EntropyCoder.BITRES)
|
||||
offset += NClogN >> 2;
|
||||
else if (bits[j] + offset < den * 3 << EntropyCoder.BITRES)
|
||||
offset += NClogN >> 3;
|
||||
|
||||
/* Divide with rounding */
|
||||
ebits[j] = Inlines.IMAX(0, (bits[j] + offset + (den << (EntropyCoder.BITRES - 1))));
|
||||
ebits[j] = Inlines.celt_udiv(ebits[j], den) >> EntropyCoder.BITRES;
|
||||
|
||||
/* Make sure not to bust */
|
||||
if (C * ebits[j] > (bits[j] >> EntropyCoder.BITRES))
|
||||
ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
|
||||
|
||||
/* More than that is useless because that's about as far as PVQ can go */
|
||||
ebits[j] = Inlines.IMIN(ebits[j], CeltConstants.MAX_FINE_BITS);
|
||||
|
||||
/* If we rounded down or capped this band, make it a candidate for the
|
||||
final fine energy pass */
|
||||
fine_priority[j] = (ebits[j] * (den << EntropyCoder.BITRES) >= bits[j] + offset) ? 1 : 0;
|
||||
|
||||
/* Remove the allocated fine bits; the rest are assigned to PVQ */
|
||||
bits[j] -= C * ebits[j] << EntropyCoder.BITRES;
|
||||
|
||||
}
|
||||
else {
|
||||
/* For N=1, all bits go to fine energy except for a single sign bit */
|
||||
excess = Inlines.MAX32(0, bit - (C << EntropyCoder.BITRES));
|
||||
bits[j] = bit - excess;
|
||||
ebits[j] = 0;
|
||||
fine_priority[j] = 1;
|
||||
}
|
||||
|
||||
/* Fine energy can't take advantage of the re-balancing in
|
||||
quant_all_bands().
|
||||
Instead, do the re-balancing here.*/
|
||||
if (excess > 0)
|
||||
{
|
||||
int extra_fine;
|
||||
int extra_bits;
|
||||
extra_fine = Inlines.IMIN(excess >> (stereo + EntropyCoder.BITRES), CeltConstants.MAX_FINE_BITS - ebits[j]);
|
||||
ebits[j] += extra_fine;
|
||||
extra_bits = extra_fine * C << EntropyCoder.BITRES;
|
||||
fine_priority[j] = (extra_bits >= excess - balance) ? 1 : 0;
|
||||
excess -= extra_bits;
|
||||
}
|
||||
balance = excess;
|
||||
|
||||
Inlines.OpusAssert(bits[j] >= 0);
|
||||
Inlines.OpusAssert(ebits[j] >= 0);
|
||||
}
|
||||
/* Save any remaining bits over the cap for the rebalancing in
|
||||
quant_all_bands(). */
|
||||
_balance = balance;
|
||||
|
||||
/* The skipped bands use all their bits for fine energy. */
|
||||
for (; j < end; j++)
|
||||
{
|
||||
ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES;
|
||||
Inlines.OpusAssert(C * ebits[j] << EntropyCoder.BITRES == bits[j]);
|
||||
bits[j] = 0;
|
||||
fine_priority[j] = (ebits[j] < 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
return codedBands;
|
||||
}
|
||||
|
||||
internal static int compute_allocation(CeltMode m, int start, int end, int[] offsets, int[] cap, int alloc_trim, ref int intensity, ref int dual_stereo,
|
||||
int total, out int balance, int[] pulses, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth)
|
||||
{
|
||||
int lo, hi, len, j;
|
||||
int codedBands;
|
||||
int skip_start;
|
||||
int skip_rsv;
|
||||
int intensity_rsv;
|
||||
int dual_stereo_rsv;
|
||||
|
||||
total = Inlines.IMAX(total, 0);
|
||||
len = m.nbEBands;
|
||||
skip_start = start;
|
||||
/* Reserve a bit to signal the end of manually skipped bands. */
|
||||
skip_rsv = total >= 1 << EntropyCoder.BITRES ? 1 << EntropyCoder.BITRES : 0;
|
||||
total -= skip_rsv;
|
||||
/* Reserve bits for the intensity and dual stereo parameters. */
|
||||
intensity_rsv = dual_stereo_rsv = 0;
|
||||
if (C == 2)
|
||||
{
|
||||
intensity_rsv = LOG2_FRAC_TABLE[end - start];
|
||||
if (intensity_rsv > total)
|
||||
intensity_rsv = 0;
|
||||
else
|
||||
{
|
||||
total -= intensity_rsv;
|
||||
dual_stereo_rsv = total >= 1 << EntropyCoder.BITRES ? 1 << EntropyCoder.BITRES : 0;
|
||||
total -= dual_stereo_rsv;
|
||||
}
|
||||
}
|
||||
|
||||
int[] bits1 = new int[len];
|
||||
int[] bits2 = new int[len];
|
||||
int[] thresh = new int[len];
|
||||
int[] trim_offset = new int[len];
|
||||
|
||||
for (j = start; j < end; j++)
|
||||
{
|
||||
/* Below this threshold, we're sure not to allocate any PVQ bits */
|
||||
thresh[j] = Inlines.IMAX((C) << EntropyCoder.BITRES, (3 * (m.eBands[j + 1] - m.eBands[j]) << LM << EntropyCoder.BITRES) >> 4);
|
||||
/* Tilt of the allocation curve */
|
||||
trim_offset[j] = C * (m.eBands[j + 1] - m.eBands[j]) * (alloc_trim - 5 - LM) * (end - j - 1)
|
||||
* (1 << (LM + EntropyCoder.BITRES)) >> 6;
|
||||
/* Giving less resolution to single-coefficient bands because they get
|
||||
more benefit from having one coarse value per coefficient*/
|
||||
if ((m.eBands[j + 1] - m.eBands[j]) << LM == 1)
|
||||
trim_offset[j] -= C << EntropyCoder.BITRES;
|
||||
}
|
||||
lo = 1;
|
||||
hi = m.nbAllocVectors - 1;
|
||||
do
|
||||
{
|
||||
int done = 0;
|
||||
int psum = 0;
|
||||
int mid = (lo + hi) >> 1;
|
||||
for (j = end; j-- > start;)
|
||||
{
|
||||
int bitsj;
|
||||
int N = m.eBands[j + 1] - m.eBands[j];
|
||||
bitsj = C * N * m.allocVectors[mid * len + j] << LM >> 2;
|
||||
|
||||
if (bitsj > 0)
|
||||
{
|
||||
bitsj = Inlines.IMAX(0, bitsj + trim_offset[j]);
|
||||
}
|
||||
|
||||
bitsj += offsets[j];
|
||||
|
||||
if (bitsj >= thresh[j] || done != 0)
|
||||
{
|
||||
done = 1;
|
||||
/* Don't allocate more than we can actually use */
|
||||
psum += Inlines.IMIN(bitsj, cap[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bitsj >= C << EntropyCoder.BITRES)
|
||||
{
|
||||
psum += C << EntropyCoder.BITRES;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (psum > total)
|
||||
{
|
||||
hi = mid - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = mid + 1;
|
||||
}
|
||||
/*printf ("lo = %d, hi = %d\n", lo, hi);*/
|
||||
} while (lo <= hi);
|
||||
|
||||
hi = lo--;
|
||||
/*printf ("interp between %d and %d\n", lo, hi);*/
|
||||
|
||||
for (j = start; j < end; j++)
|
||||
{
|
||||
int bits1j, bits2j;
|
||||
int N = m.eBands[j + 1] - m.eBands[j];
|
||||
bits1j = C * N * m.allocVectors[lo * len + j] << LM >> 2;
|
||||
bits2j = hi >= m.nbAllocVectors ?
|
||||
cap[j] : C * N * m.allocVectors[hi * len + j] << LM >> 2;
|
||||
if (bits1j > 0)
|
||||
bits1j = Inlines.IMAX(0, bits1j + trim_offset[j]);
|
||||
if (bits2j > 0)
|
||||
bits2j = Inlines.IMAX(0, bits2j + trim_offset[j]);
|
||||
if (lo > 0)
|
||||
bits1j += offsets[j];
|
||||
bits2j += offsets[j];
|
||||
if (offsets[j] > 0)
|
||||
skip_start = j;
|
||||
bits2j = Inlines.IMAX(0, bits2j - bits1j);
|
||||
bits1[j] = bits1j;
|
||||
bits2[j] = bits2j;
|
||||
}
|
||||
|
||||
codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap,
|
||||
total, out balance, skip_rsv, ref intensity, intensity_rsv, ref dual_stereo, dual_stereo_rsv,
|
||||
pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth);
|
||||
|
||||
return codedBands;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt.Structs
|
||||
{
|
||||
internal class AnalysisInfo
|
||||
{
|
||||
internal int valid = 0;
|
||||
internal float tonality = 0;
|
||||
internal float tonality_slope = 0;
|
||||
internal float noisiness = 0;
|
||||
internal float activity = 0;
|
||||
internal float music_prob = 0;
|
||||
internal int bandwidth = 0;
|
||||
|
||||
internal AnalysisInfo()
|
||||
{
|
||||
}
|
||||
|
||||
internal void Assign(AnalysisInfo other)
|
||||
{
|
||||
this.valid = other.valid;
|
||||
this.tonality = other.tonality;
|
||||
this.tonality_slope = other.tonality_slope;
|
||||
this.noisiness = other.noisiness;
|
||||
this.activity = other.activity;
|
||||
this.music_prob = other.music_prob;
|
||||
this.bandwidth = other.bandwidth;
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
valid = 0;
|
||||
tonality = 0;
|
||||
tonality_slope = 0;
|
||||
noisiness = 0;
|
||||
activity = 0;
|
||||
music_prob = 0;
|
||||
bandwidth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
873
Libraries/Concentus/CSharp/Concentus/Celt/Structs/CELTDecoder.cs
Normal file
873
Libraries/Concentus/CSharp/Concentus/Celt/Structs/CELTDecoder.cs
Normal file
@@ -0,0 +1,873 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt.Structs
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Decoder state
|
||||
/// </summary>
|
||||
internal class CeltDecoder
|
||||
{
|
||||
internal CeltMode mode = null;
|
||||
internal int overlap = 0;
|
||||
internal int channels = 0;
|
||||
internal int stream_channels = 0;
|
||||
|
||||
internal int downsample = 0;
|
||||
internal int start = 0;
|
||||
internal int end = 0;
|
||||
internal int signalling = 0;
|
||||
|
||||
/* Everything beyond this point gets cleared on a reset */
|
||||
internal uint rng = 0;
|
||||
internal int error = 0;
|
||||
internal int last_pitch_index = 0;
|
||||
internal int loss_count = 0;
|
||||
internal int postfilter_period = 0;
|
||||
internal int postfilter_period_old = 0;
|
||||
internal int postfilter_gain = 0;
|
||||
internal int postfilter_gain_old = 0;
|
||||
internal int postfilter_tapset = 0;
|
||||
internal int postfilter_tapset_old = 0;
|
||||
|
||||
internal readonly int[] preemph_memD = new int[2];
|
||||
|
||||
/// <summary>
|
||||
/// Scratch space used by the decoder. It is actually a variable-sized
|
||||
/// field that resulted in a variable-sized struct. There are 6 distinct regions inside.
|
||||
/// I have laid them out into separate variables here,
|
||||
/// but these were the original definitions:
|
||||
/// val32 decode_mem[], Size = channels*(DECODE_BUFFER_SIZE+mode.overlap)
|
||||
/// val16 lpc[], Size = channels*LPC_ORDER
|
||||
/// val16 oldEBands[], Size = 2*mode.nbEBands
|
||||
/// val16 oldLogE[], Size = 2*mode.nbEBands
|
||||
/// val16 oldLogE2[], Size = 2*mode.nbEBands
|
||||
/// val16 backgroundLogE[], Size = 2*mode.nbEBands
|
||||
/// </summary>
|
||||
internal int[][] decode_mem = null;
|
||||
internal int[][] lpc = null; // Porting note: Split two-part array into separate arrays (one per channel)
|
||||
internal int[] oldEBands = null;
|
||||
internal int[] oldLogE = null;
|
||||
internal int[] oldLogE2 = null;
|
||||
internal int[] backgroundLogE = null;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
mode = null;
|
||||
overlap = 0;
|
||||
channels = 0;
|
||||
stream_channels = 0;
|
||||
downsample = 0;
|
||||
start = 0;
|
||||
end = 0;
|
||||
signalling = 0;
|
||||
PartialReset();
|
||||
}
|
||||
|
||||
private void PartialReset()
|
||||
{
|
||||
rng = 0;
|
||||
error = 0;
|
||||
last_pitch_index = 0;
|
||||
loss_count = 0;
|
||||
postfilter_period = 0;
|
||||
postfilter_period_old = 0;
|
||||
postfilter_gain = 0;
|
||||
postfilter_gain_old = 0;
|
||||
postfilter_tapset = 0;
|
||||
postfilter_tapset_old = 0;
|
||||
Arrays.MemSetInt(preemph_memD, 0, 2);
|
||||
decode_mem = null;
|
||||
lpc = null;
|
||||
oldEBands = null;
|
||||
oldLogE = null;
|
||||
oldLogE2 = null;
|
||||
backgroundLogE = null;
|
||||
}
|
||||
|
||||
#region API functions
|
||||
|
||||
internal void ResetState()
|
||||
{
|
||||
int i;
|
||||
|
||||
this.PartialReset();
|
||||
|
||||
// We have to reconstitute the dynamic buffers here. fixme: this could be better implemented
|
||||
this.decode_mem = new int[this.channels][];
|
||||
this.lpc = new int[this.channels][];
|
||||
for (int c = 0; c < this.channels; c++)
|
||||
{
|
||||
this.decode_mem[c] = new int[CeltConstants.DECODE_BUFFER_SIZE + this.mode.overlap];
|
||||
this.lpc[c] = new int[CeltConstants.LPC_ORDER];
|
||||
}
|
||||
this.oldEBands = new int[2 * this.mode.nbEBands];
|
||||
this.oldLogE = new int[2 * this.mode.nbEBands];
|
||||
this.oldLogE2 = new int[2 * this.mode.nbEBands];
|
||||
this.backgroundLogE = new int[2 * this.mode.nbEBands];
|
||||
|
||||
for (i = 0; i < 2 * this.mode.nbEBands; i++)
|
||||
this.oldLogE[i] = this.oldLogE2[i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
|
||||
}
|
||||
|
||||
internal int celt_decoder_init(int sampling_rate, int channels)
|
||||
{
|
||||
int ret;
|
||||
ret = this.opus_custom_decoder_init(CeltMode.mode48000_960_120, channels);
|
||||
if (ret != OpusError.OPUS_OK)
|
||||
return ret;
|
||||
this.downsample = CeltCommon.resampling_factor(sampling_rate);
|
||||
if (this.downsample == 0)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
else
|
||||
return OpusError.OPUS_OK;
|
||||
}
|
||||
|
||||
private int opus_custom_decoder_init(CeltMode mode, int channels)
|
||||
{
|
||||
if (channels < 0 || channels > 2)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
|
||||
if (this == null)
|
||||
return OpusError.OPUS_ALLOC_FAIL;
|
||||
|
||||
this.Reset();
|
||||
|
||||
this.mode = mode;
|
||||
this.overlap = mode.overlap;
|
||||
this.stream_channels = this.channels = channels;
|
||||
|
||||
this.downsample = 1;
|
||||
this.start = 0;
|
||||
this.end = this.mode.effEBands;
|
||||
this.signalling = 1;
|
||||
|
||||
this.loss_count = 0;
|
||||
|
||||
//this.decode_mem = new int[channels * (CeltConstants.DECODE_BUFFER_SIZE + mode.overlap));
|
||||
//this.lpc = new int[channels * CeltConstants.LPC_ORDER);
|
||||
//this.oldEBands = new int[2 * mode.nbEBands);
|
||||
//this.oldLogE = new int[2 * mode.nbEBands);
|
||||
//this.oldLogE2 = new int[2 * mode.nbEBands);
|
||||
//this.backgroundLogE = new int[2 * mode.nbEBands);
|
||||
|
||||
this.ResetState();
|
||||
|
||||
return OpusError.OPUS_OK;
|
||||
}
|
||||
|
||||
internal void celt_decode_lost(int N, int LM)
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
int C = this.channels;
|
||||
int[][] out_syn = new int[2][];
|
||||
int[] out_syn_ptrs = new int[2];
|
||||
CeltMode mode;
|
||||
int nbEBands;
|
||||
int overlap;
|
||||
int noise_based;
|
||||
short[] eBands;
|
||||
|
||||
mode = this.mode;
|
||||
nbEBands = mode.nbEBands;
|
||||
overlap = mode.overlap;
|
||||
eBands = mode.eBands;
|
||||
|
||||
c = 0; do
|
||||
{
|
||||
out_syn[c] = this.decode_mem[c];
|
||||
out_syn_ptrs[c] = CeltConstants.DECODE_BUFFER_SIZE - N;
|
||||
} while (++c < C);
|
||||
|
||||
noise_based = (loss_count >= 5 || start != 0) ? 1 : 0;
|
||||
if (noise_based != 0)
|
||||
{
|
||||
/* Noise-based PLC/CNG */
|
||||
int[][] X;
|
||||
uint seed;
|
||||
int end;
|
||||
int effEnd;
|
||||
int decay;
|
||||
end = this.end;
|
||||
effEnd = Inlines.IMAX(start, Inlines.IMIN(end, mode.effEBands));
|
||||
|
||||
X = Arrays.InitTwoDimensionalArray<int>(C, N); /*< Interleaved normalised MDCTs */
|
||||
|
||||
/* Energy decay */
|
||||
decay = loss_count == 0 ? ((short)(0.5 + (1.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.5f, CeltConstants.DB_SHIFT)*/ : ((short)(0.5 + (0.5f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.5f, CeltConstants.DB_SHIFT)*/;
|
||||
c = 0; do
|
||||
{
|
||||
for (i = start; i < end; i++)
|
||||
this.oldEBands[c * nbEBands + i] = Inlines.MAX16(backgroundLogE[c * nbEBands + i], this.oldEBands[c * nbEBands + i] - decay);
|
||||
} while (++c < C);
|
||||
seed = this.rng;
|
||||
for (c = 0; c < C; c++)
|
||||
{
|
||||
for (i = start; i < effEnd; i++)
|
||||
{
|
||||
int j;
|
||||
int boffs;
|
||||
int blen;
|
||||
boffs = (eBands[i] << LM);
|
||||
blen = (eBands[i + 1] - eBands[i]) << LM;
|
||||
for (j = 0; j < blen; j++)
|
||||
{
|
||||
seed = Bands.celt_lcg_rand(seed);
|
||||
X[c][boffs + j] = (unchecked((int)seed) >> 20);
|
||||
}
|
||||
|
||||
VQ.renormalise_vector(X[c], 0, blen, CeltConstants.Q15ONE);
|
||||
}
|
||||
}
|
||||
this.rng = seed;
|
||||
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
Arrays.MemMoveInt(this.decode_mem[c], N, 0, CeltConstants.DECODE_BUFFER_SIZE - N + (overlap >> 1));
|
||||
} while (++c < C);
|
||||
|
||||
CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, this.oldEBands, start, effEnd, C, C, 0, LM, this.downsample, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pitch-based PLC */
|
||||
int[] window;
|
||||
int fade = CeltConstants.Q15ONE;
|
||||
int pitch_index;
|
||||
int[] etmp;
|
||||
int[] exc;
|
||||
|
||||
if (loss_count == 0)
|
||||
{
|
||||
this.last_pitch_index = pitch_index = CeltCommon.celt_plc_pitch_search(this.decode_mem, C);
|
||||
}
|
||||
else {
|
||||
pitch_index = this.last_pitch_index;
|
||||
fade = ((short)(0.5 + (.8f) * (((int)1) << (15))))/*Inlines.QCONST16(.8f, 15)*/;
|
||||
}
|
||||
|
||||
etmp = new int[overlap];
|
||||
exc = new int[CeltConstants.MAX_PERIOD];
|
||||
window = mode.window;
|
||||
c = 0; do
|
||||
{
|
||||
int decay;
|
||||
int attenuation;
|
||||
int S1 = 0;
|
||||
int[] buf;
|
||||
int extrapolation_offset;
|
||||
int extrapolation_len;
|
||||
int exc_length;
|
||||
int j;
|
||||
|
||||
buf = this.decode_mem[c];
|
||||
for (i = 0; i < CeltConstants.MAX_PERIOD; i++)
|
||||
{
|
||||
exc[i] = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - CeltConstants.MAX_PERIOD + i], CeltConstants.SIG_SHIFT);
|
||||
}
|
||||
|
||||
if (loss_count == 0)
|
||||
{
|
||||
int[] ac = new int[CeltConstants.LPC_ORDER + 1];
|
||||
/* Compute LPC coefficients for the last MAX_PERIOD samples before
|
||||
the first loss so we can work in the excitation-filter domain. */
|
||||
Autocorrelation._celt_autocorr(exc, ac, window, overlap,
|
||||
CeltConstants.LPC_ORDER, CeltConstants.MAX_PERIOD);
|
||||
/* Add a noise floor of -40 dB. */
|
||||
ac[0] += Inlines.SHR32(ac[0], 13);
|
||||
/* Use lag windowing to stabilize the Levinson-Durbin recursion. */
|
||||
for (i = 1; i <= CeltConstants.LPC_ORDER; i++)
|
||||
{
|
||||
/*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
|
||||
ac[i] -= Inlines.MULT16_32_Q15(2 * i * i, ac[i]);
|
||||
}
|
||||
CeltLPC.celt_lpc(this.lpc[c], ac, CeltConstants.LPC_ORDER);
|
||||
}
|
||||
/* We want the excitation for 2 pitch periods in order to look for a
|
||||
decaying signal, but we can't get more than MAX_PERIOD. */
|
||||
exc_length = Inlines.IMIN(2 * pitch_index, CeltConstants.MAX_PERIOD);
|
||||
/* Initialize the LPC history with the samples just before the start
|
||||
of the region for which we're computing the excitation. */
|
||||
{
|
||||
int[] lpc_mem = new int[CeltConstants.LPC_ORDER];
|
||||
for (i = 0; i < CeltConstants.LPC_ORDER; i++)
|
||||
{
|
||||
lpc_mem[i] =
|
||||
Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - exc_length - 1 - i], CeltConstants.SIG_SHIFT);
|
||||
}
|
||||
|
||||
/* Compute the excitation for exc_length samples before the loss. */
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (int* pexc_base = exc, lpc = this.lpc[c])
|
||||
{
|
||||
int* pexc = pexc_base + (CeltConstants.MAX_PERIOD - exc_length);
|
||||
Kernels.celt_fir(pexc, lpc, pexc, exc_length, CeltConstants.LPC_ORDER, lpc_mem);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Kernels.celt_fir(exc, (CeltConstants.MAX_PERIOD - exc_length), this.lpc[c], 0,
|
||||
exc, (CeltConstants.MAX_PERIOD - exc_length), exc_length, CeltConstants.LPC_ORDER, lpc_mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if the waveform is decaying, and if so how fast.
|
||||
We do this to avoid adding energy when concealing in a segment
|
||||
with decaying energy. */
|
||||
{
|
||||
int E1 = 1, E2 = 1;
|
||||
int decay_length;
|
||||
int shift = Inlines.IMAX(0, 2 * Inlines.celt_zlog2(Inlines.celt_maxabs16(exc, (CeltConstants.MAX_PERIOD - exc_length), exc_length)) - 20);
|
||||
decay_length = exc_length >> 1;
|
||||
for (i = 0; i < decay_length; i++)
|
||||
{
|
||||
int e;
|
||||
e = exc[CeltConstants.MAX_PERIOD - decay_length + i];
|
||||
E1 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift);
|
||||
e = exc[CeltConstants.MAX_PERIOD - 2 * decay_length + i];
|
||||
E2 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift);
|
||||
}
|
||||
E1 = Inlines.MIN32(E1, E2);
|
||||
decay = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(E1, 1), E2));
|
||||
}
|
||||
|
||||
/* Move the decoder memory one frame to the left to give us room to
|
||||
add the data for the new frame. We ignore the overlap that extends
|
||||
past the end of the buffer, because we aren't going to use it. */
|
||||
Arrays.MemMoveInt(buf, N, 0, CeltConstants.DECODE_BUFFER_SIZE - N);
|
||||
|
||||
/* Extrapolate from the end of the excitation with a period of
|
||||
"pitch_index", scaling down each period by an additional factor of
|
||||
"decay". */
|
||||
extrapolation_offset = CeltConstants.MAX_PERIOD - pitch_index;
|
||||
/* We need to extrapolate enough samples to cover a complete MDCT
|
||||
window (including overlap/2 samples on both sides). */
|
||||
extrapolation_len = N + overlap;
|
||||
/* We also apply fading if this is not the first loss. */
|
||||
attenuation = Inlines.MULT16_16_Q15(fade, decay);
|
||||
for (i = j = 0; i < extrapolation_len; i++, j++)
|
||||
{
|
||||
int tmp;
|
||||
if (j >= pitch_index)
|
||||
{
|
||||
j -= pitch_index;
|
||||
attenuation = Inlines.MULT16_16_Q15(attenuation, decay);
|
||||
}
|
||||
buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] =
|
||||
Inlines.SHL32((Inlines.MULT16_16_Q15(attenuation,
|
||||
exc[extrapolation_offset + j])), CeltConstants.SIG_SHIFT);
|
||||
/* Compute the energy of the previously decoded signal whose
|
||||
excitation we're copying. */
|
||||
tmp = Inlines.ROUND16(
|
||||
buf[CeltConstants.DECODE_BUFFER_SIZE - CeltConstants.MAX_PERIOD - N + extrapolation_offset + j],
|
||||
CeltConstants.SIG_SHIFT);
|
||||
S1 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8);
|
||||
}
|
||||
|
||||
{
|
||||
int[] lpc_mem = new int[CeltConstants.LPC_ORDER];
|
||||
/* Copy the last decoded samples (prior to the overlap region) to
|
||||
synthesis filter memory so we can have a continuous signal. */
|
||||
for (i = 0; i < CeltConstants.LPC_ORDER; i++)
|
||||
lpc_mem[i] = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - N - 1 - i], CeltConstants.SIG_SHIFT);
|
||||
/* Apply the synthesis filter to convert the excitation back into
|
||||
the signal domain. */
|
||||
CeltLPC.celt_iir(buf, CeltConstants.DECODE_BUFFER_SIZE - N, this.lpc[c],
|
||||
buf, CeltConstants.DECODE_BUFFER_SIZE - N, extrapolation_len, CeltConstants.LPC_ORDER,
|
||||
lpc_mem);
|
||||
}
|
||||
|
||||
/* Check if the synthesis energy is higher than expected, which can
|
||||
happen with the signal changes during our window. If so,
|
||||
attenuate. */
|
||||
{
|
||||
int S2 = 0;
|
||||
for (i = 0; i < extrapolation_len; i++)
|
||||
{
|
||||
int tmp = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - N + i], CeltConstants.SIG_SHIFT);
|
||||
S2 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8);
|
||||
}
|
||||
/* This checks for an "explosion" in the synthesis. */
|
||||
if (!(S1 > Inlines.SHR32(S2, 2)))
|
||||
{
|
||||
for (i = 0; i < extrapolation_len; i++)
|
||||
buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] = 0;
|
||||
}
|
||||
else if (S1 < S2)
|
||||
{
|
||||
int ratio = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(S1, 1) + 1, S2 + 1));
|
||||
for (i = 0; i < overlap; i++)
|
||||
{
|
||||
int tmp_g = CeltConstants.Q15ONE
|
||||
- Inlines.MULT16_16_Q15(window[i], CeltConstants.Q15ONE - ratio);
|
||||
buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] =
|
||||
Inlines.MULT16_32_Q15(tmp_g, buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]);
|
||||
}
|
||||
for (i = overlap; i < extrapolation_len; i++)
|
||||
{
|
||||
buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] =
|
||||
Inlines.MULT16_32_Q15(ratio, buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply the pre-filter to the MDCT overlap for the next frame because
|
||||
the post-filter will be re-applied in the decoder after the MDCT
|
||||
overlap. */
|
||||
CeltCommon.comb_filter(etmp, 0, buf, CeltConstants.DECODE_BUFFER_SIZE,
|
||||
this.postfilter_period, this.postfilter_period, overlap,
|
||||
-this.postfilter_gain, -this.postfilter_gain,
|
||||
this.postfilter_tapset, this.postfilter_tapset, null, 0);
|
||||
|
||||
/* Simulate TDAC on the concealed audio so that it blends with the
|
||||
MDCT of the next frame. */
|
||||
for (i = 0; i < overlap / 2; i++)
|
||||
{
|
||||
buf[CeltConstants.DECODE_BUFFER_SIZE + i] =
|
||||
Inlines.MULT16_32_Q15(window[i], etmp[overlap - 1 - i])
|
||||
+ Inlines.MULT16_32_Q15(window[overlap - i - 1], etmp[i]);
|
||||
}
|
||||
} while (++c < C);
|
||||
}
|
||||
|
||||
this.loss_count = loss_count + 1;
|
||||
}
|
||||
|
||||
internal int celt_decode_with_ec(byte[] data, int data_ptr,
|
||||
int len, short[] pcm, int pcm_ptr, int frame_size, EntropyCoder dec, int accum)
|
||||
{
|
||||
int c, i, N;
|
||||
int spread_decision;
|
||||
int bits;
|
||||
int[][] X;
|
||||
int[] fine_quant;
|
||||
int[] pulses;
|
||||
int[] cap;
|
||||
int[] offsets;
|
||||
int[] fine_priority;
|
||||
int[] tf_res;
|
||||
byte[] collapse_masks;
|
||||
int[][] out_syn = new int[2][];
|
||||
int[] out_syn_ptrs = new int[2];
|
||||
int[] oldBandE, oldLogE, oldLogE2, backgroundLogE;
|
||||
|
||||
int shortBlocks;
|
||||
int isTransient;
|
||||
int intra_ener;
|
||||
int CC = this.channels;
|
||||
int LM, M;
|
||||
int start;
|
||||
int end;
|
||||
int effEnd;
|
||||
int codedBands;
|
||||
int alloc_trim;
|
||||
int postfilter_pitch;
|
||||
int postfilter_gain;
|
||||
int intensity = 0;
|
||||
int dual_stereo = 0;
|
||||
int total_bits;
|
||||
int balance;
|
||||
int tell;
|
||||
int dynalloc_logp;
|
||||
int postfilter_tapset;
|
||||
int anti_collapse_rsv;
|
||||
int anti_collapse_on = 0;
|
||||
int silence;
|
||||
int C = this.stream_channels;
|
||||
CeltMode mode; // porting note: pointer
|
||||
int nbEBands;
|
||||
int overlap;
|
||||
short[] eBands;
|
||||
|
||||
mode = this.mode;
|
||||
nbEBands = mode.nbEBands;
|
||||
overlap = mode.overlap;
|
||||
eBands = mode.eBands;
|
||||
start = this.start;
|
||||
end = this.end;
|
||||
frame_size *= this.downsample;
|
||||
|
||||
oldBandE = this.oldEBands;
|
||||
oldLogE = this.oldLogE;
|
||||
oldLogE2 = this.oldLogE2;
|
||||
backgroundLogE = this.backgroundLogE;
|
||||
|
||||
{
|
||||
for (LM = 0; LM <= mode.maxLM; LM++)
|
||||
if (mode.shortMdctSize << LM == frame_size)
|
||||
break;
|
||||
if (LM > mode.maxLM)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
}
|
||||
M = 1 << LM;
|
||||
|
||||
if (len < 0 || len > 1275 || pcm == null)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
|
||||
N = M * mode.shortMdctSize;
|
||||
c = 0; do
|
||||
{
|
||||
out_syn[c] = this.decode_mem[c];
|
||||
out_syn_ptrs[c] = CeltConstants.DECODE_BUFFER_SIZE - N;
|
||||
} while (++c < CC);
|
||||
|
||||
effEnd = end;
|
||||
if (effEnd > mode.effEBands)
|
||||
effEnd = mode.effEBands;
|
||||
|
||||
if (data == null || len <= 1)
|
||||
{
|
||||
this.celt_decode_lost(N, LM);
|
||||
CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum);
|
||||
|
||||
return frame_size / this.downsample;
|
||||
}
|
||||
|
||||
if (dec == null)
|
||||
{
|
||||
// If no entropy decoder was passed into this function, we need to create
|
||||
// a new one here for local use only. It only exists in this function scope.
|
||||
dec = new EntropyCoder();
|
||||
dec.dec_init(data, data_ptr, (uint)len);
|
||||
}
|
||||
|
||||
if (C == 1)
|
||||
{
|
||||
for (i = 0; i < nbEBands; i++)
|
||||
oldBandE[i] = Inlines.MAX16(oldBandE[i], oldBandE[nbEBands + i]);
|
||||
}
|
||||
|
||||
total_bits = len * 8;
|
||||
tell = dec.tell();
|
||||
|
||||
if (tell >= total_bits)
|
||||
silence = 1;
|
||||
else if (tell == 1)
|
||||
silence = dec.dec_bit_logp(15);
|
||||
else
|
||||
silence = 0;
|
||||
|
||||
if (silence != 0)
|
||||
{
|
||||
/* Pretend we've read all the remaining bits */
|
||||
tell = len * 8;
|
||||
dec.nbits_total += tell - dec.tell();
|
||||
}
|
||||
|
||||
postfilter_gain = 0;
|
||||
postfilter_pitch = 0;
|
||||
postfilter_tapset = 0;
|
||||
if (start == 0 && tell + 16 <= total_bits)
|
||||
{
|
||||
if (dec.dec_bit_logp(1) != 0)
|
||||
{
|
||||
int qg, octave;
|
||||
octave = (int)dec.dec_uint(6);
|
||||
postfilter_pitch = (16 << octave) + (int)dec.dec_bits(4 + (uint)octave) - 1;
|
||||
qg = (int)dec.dec_bits(3);
|
||||
if (dec.tell() + 2 <= total_bits)
|
||||
postfilter_tapset = dec.dec_icdf(Tables.tapset_icdf, 2);
|
||||
postfilter_gain = ((short)(0.5 + (.09375f) * (((int)1) << (15))))/*Inlines.QCONST16(.09375f, 15)*/ * (qg + 1);
|
||||
}
|
||||
tell = dec.tell();
|
||||
}
|
||||
|
||||
if (LM > 0 && tell + 3 <= total_bits)
|
||||
{
|
||||
isTransient = dec.dec_bit_logp(3);
|
||||
tell = dec.tell();
|
||||
}
|
||||
else
|
||||
isTransient = 0;
|
||||
|
||||
if (isTransient != 0)
|
||||
shortBlocks = M;
|
||||
else
|
||||
shortBlocks = 0;
|
||||
|
||||
/* Decode the global flags (first symbols in the stream) */
|
||||
intra_ener = tell + 3 <= total_bits ? dec.dec_bit_logp(3) : 0;
|
||||
/* Get band energies */
|
||||
QuantizeBands.unquant_coarse_energy(mode, start, end, oldBandE,
|
||||
intra_ener, dec, C, LM);
|
||||
|
||||
tf_res = new int[nbEBands];
|
||||
CeltCommon.tf_decode(start, end, isTransient, tf_res, LM, dec);
|
||||
|
||||
tell = dec.tell();
|
||||
spread_decision = Spread.SPREAD_NORMAL;
|
||||
if (tell + 4 <= total_bits)
|
||||
spread_decision = dec.dec_icdf(Tables.spread_icdf, 5);
|
||||
|
||||
cap = new int[nbEBands];
|
||||
|
||||
CeltCommon.init_caps(mode, cap, LM, C);
|
||||
|
||||
offsets = new int[nbEBands];
|
||||
|
||||
dynalloc_logp = 6;
|
||||
total_bits <<= EntropyCoder.BITRES;
|
||||
tell = (int)dec.tell_frac();
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
int width, quanta;
|
||||
int dynalloc_loop_logp;
|
||||
int boost;
|
||||
width = C * (eBands[i + 1] - eBands[i]) << LM;
|
||||
/* quanta is 6 bits, but no more than 1 bit/sample
|
||||
and no less than 1/8 bit/sample */
|
||||
quanta = Inlines.IMIN(width << EntropyCoder.BITRES, Inlines.IMAX(6 << EntropyCoder.BITRES, width));
|
||||
dynalloc_loop_logp = dynalloc_logp;
|
||||
boost = 0;
|
||||
while (tell + (dynalloc_loop_logp << EntropyCoder.BITRES) < total_bits && boost < cap[i])
|
||||
{
|
||||
int flag;
|
||||
flag = dec.dec_bit_logp((uint)dynalloc_loop_logp);
|
||||
tell = (int)dec.tell_frac();
|
||||
if (flag == 0)
|
||||
break;
|
||||
boost += quanta;
|
||||
total_bits -= quanta;
|
||||
dynalloc_loop_logp = 1;
|
||||
}
|
||||
offsets[i] = boost;
|
||||
/* Making dynalloc more likely */
|
||||
if (boost > 0)
|
||||
dynalloc_logp = Inlines.IMAX(2, dynalloc_logp - 1);
|
||||
}
|
||||
|
||||
fine_quant = new int[nbEBands];
|
||||
alloc_trim = tell + (6 << EntropyCoder.BITRES) <= total_bits ?
|
||||
dec.dec_icdf(Tables.trim_icdf, 7) : 5;
|
||||
|
||||
bits = (((int)len * 8) << EntropyCoder.BITRES) - (int)dec.tell_frac() - 1;
|
||||
anti_collapse_rsv = isTransient != 0 && LM >= 2 && bits >= ((LM + 2) << EntropyCoder.BITRES) ? (1 << EntropyCoder.BITRES) : 0;
|
||||
bits -= anti_collapse_rsv;
|
||||
|
||||
pulses = new int[nbEBands];
|
||||
fine_priority = new int[nbEBands];
|
||||
|
||||
codedBands = Rate.compute_allocation(mode, start, end, offsets, cap,
|
||||
alloc_trim, ref intensity, ref dual_stereo, bits, out balance, pulses,
|
||||
fine_quant, fine_priority, C, LM, dec, 0, 0, 0);
|
||||
|
||||
QuantizeBands.unquant_fine_energy(mode, start, end, oldBandE, fine_quant, dec, C);
|
||||
|
||||
c = 0;
|
||||
do
|
||||
{
|
||||
Arrays.MemMoveInt(decode_mem[c], N, 0, CeltConstants.DECODE_BUFFER_SIZE - N + overlap / 2);
|
||||
} while (++c < CC);
|
||||
|
||||
/* Decode fixed codebook */
|
||||
collapse_masks = new byte[C * nbEBands];
|
||||
|
||||
X = Arrays.InitTwoDimensionalArray<int>(C, N); /*< Interleaved normalised MDCTs */
|
||||
|
||||
Bands.quant_all_bands(0, mode, start, end, X[0], C == 2 ? X[1] : null, collapse_masks,
|
||||
null, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
|
||||
len * (8 << EntropyCoder.BITRES) - anti_collapse_rsv, balance, dec, LM, codedBands, ref this.rng);
|
||||
|
||||
if (anti_collapse_rsv > 0)
|
||||
{
|
||||
anti_collapse_on = (int)dec.dec_bits(1);
|
||||
}
|
||||
|
||||
QuantizeBands.unquant_energy_finalise(mode, start, end, oldBandE,
|
||||
fine_quant, fine_priority, len * 8 - dec.tell(), dec, C);
|
||||
|
||||
if (anti_collapse_on != 0)
|
||||
Bands.anti_collapse(mode, X, collapse_masks, LM, C, N,
|
||||
start, end, oldBandE, oldLogE, oldLogE2, pulses, this.rng);
|
||||
|
||||
if (silence != 0)
|
||||
{
|
||||
for (i = 0; i < C * nbEBands; i++)
|
||||
oldBandE[i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
|
||||
}
|
||||
|
||||
CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, oldBandE, start, effEnd,
|
||||
C, CC, isTransient, LM, this.downsample, silence);
|
||||
|
||||
c = 0; do
|
||||
{
|
||||
this.postfilter_period = Inlines.IMAX(this.postfilter_period, CeltConstants.COMBFILTER_MINPERIOD);
|
||||
this.postfilter_period_old = Inlines.IMAX(this.postfilter_period_old, CeltConstants.COMBFILTER_MINPERIOD);
|
||||
CeltCommon.comb_filter(out_syn[c], out_syn_ptrs[c], out_syn[c], out_syn_ptrs[c], this.postfilter_period_old, this.postfilter_period, mode.shortMdctSize,
|
||||
this.postfilter_gain_old, this.postfilter_gain, this.postfilter_tapset_old, this.postfilter_tapset,
|
||||
mode.window, overlap);
|
||||
if (LM != 0)
|
||||
{
|
||||
CeltCommon.comb_filter(
|
||||
out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize),
|
||||
out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize),
|
||||
this.postfilter_period, postfilter_pitch, N - mode.shortMdctSize,
|
||||
this.postfilter_gain, postfilter_gain, this.postfilter_tapset, postfilter_tapset,
|
||||
mode.window, overlap);
|
||||
}
|
||||
|
||||
} while (++c < CC);
|
||||
this.postfilter_period_old = this.postfilter_period;
|
||||
this.postfilter_gain_old = this.postfilter_gain;
|
||||
this.postfilter_tapset_old = this.postfilter_tapset;
|
||||
this.postfilter_period = postfilter_pitch;
|
||||
this.postfilter_gain = postfilter_gain;
|
||||
this.postfilter_tapset = postfilter_tapset;
|
||||
if (LM != 0)
|
||||
{
|
||||
this.postfilter_period_old = this.postfilter_period;
|
||||
this.postfilter_gain_old = this.postfilter_gain;
|
||||
this.postfilter_tapset_old = this.postfilter_tapset;
|
||||
}
|
||||
|
||||
if (C == 1)
|
||||
{
|
||||
Array.Copy(oldBandE, 0, oldBandE, nbEBands, nbEBands);
|
||||
}
|
||||
|
||||
/* In case start or end were to change */
|
||||
if (isTransient == 0)
|
||||
{
|
||||
int max_background_increase;
|
||||
Array.Copy(oldLogE, oldLogE2, 2 * nbEBands);
|
||||
Array.Copy(oldBandE, oldLogE, 2 * nbEBands);
|
||||
/* In normal circumstances, we only allow the noise floor to increase by
|
||||
up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB
|
||||
increase for each update.*/
|
||||
if (this.loss_count < 10)
|
||||
max_background_increase = M * ((short)(0.5 + (0.001f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(0.001f, CeltConstants.DB_SHIFT)*/;
|
||||
else
|
||||
max_background_increase = ((short)(0.5 + (1.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/;
|
||||
for (i = 0; i < 2 * nbEBands; i++)
|
||||
backgroundLogE[i] = Inlines.MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < 2 * nbEBands; i++)
|
||||
oldLogE[i] = Inlines.MIN16(oldLogE[i], oldBandE[i]);
|
||||
}
|
||||
c = 0; do
|
||||
{
|
||||
for (i = 0; i < start; i++)
|
||||
{
|
||||
oldBandE[c * nbEBands + i] = 0;
|
||||
oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
|
||||
}
|
||||
for (i = end; i < nbEBands; i++)
|
||||
{
|
||||
oldBandE[c * nbEBands + i] = 0;
|
||||
oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT))))/*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/;
|
||||
}
|
||||
} while (++c < 2);
|
||||
this.rng = dec.rng;
|
||||
|
||||
CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum);
|
||||
this.loss_count = 0;
|
||||
|
||||
if (dec.tell() > 8 * len)
|
||||
return OpusError.OPUS_INTERNAL_ERROR;
|
||||
if (dec.get_error() != 0)
|
||||
this.error = 1;
|
||||
return frame_size / this.downsample;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Getters and Setters
|
||||
|
||||
internal void SetStartBand(int value)
|
||||
{
|
||||
if (value < 0 || value >= this.mode.nbEBands)
|
||||
throw new ArgumentException("Start band above max number of ebands (or negative)");
|
||||
this.start = value;
|
||||
}
|
||||
|
||||
internal void SetEndBand(int value)
|
||||
{
|
||||
if (value < 1 || value > this.mode.nbEBands)
|
||||
throw new ArgumentException("End band above max number of ebands (or less than 1)");
|
||||
this.end = value;
|
||||
}
|
||||
|
||||
internal void SetChannels(int value)
|
||||
{
|
||||
if (value < 1 || value > 2)
|
||||
throw new ArgumentException("Channel count must be 1 or 2");
|
||||
this.stream_channels = value;
|
||||
}
|
||||
|
||||
internal int GetAndClearError()
|
||||
{
|
||||
int returnVal = this.error;
|
||||
this.error = 0;
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
public int GetLookahead()
|
||||
{
|
||||
return this.overlap / this.downsample;
|
||||
}
|
||||
|
||||
public int GetPitch()
|
||||
{
|
||||
return this.postfilter_period;
|
||||
}
|
||||
|
||||
public CeltMode GetMode()
|
||||
{
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public void SetSignalling(int value)
|
||||
{
|
||||
this.signalling = value;
|
||||
}
|
||||
|
||||
public uint GetFinalRange()
|
||||
{
|
||||
return this.rng;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
118
Libraries/Concentus/CSharp/Concentus/Celt/Structs/CELTMode.cs
Normal file
118
Libraries/Concentus/CSharp/Concentus/Celt/Structs/CELTMode.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt.Structs
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using System;
|
||||
|
||||
internal class CeltMode
|
||||
{
|
||||
internal int Fs = 0;
|
||||
internal int overlap = 0;
|
||||
|
||||
internal int nbEBands = 0;
|
||||
internal int effEBands = 0;
|
||||
internal int[] preemph = { 0, 0, 0, 0 };
|
||||
|
||||
/// <summary>
|
||||
/// Definition for each "pseudo-critical band"
|
||||
/// </summary>
|
||||
internal short[] eBands = null;
|
||||
|
||||
internal int maxLM = 0;
|
||||
internal int nbShortMdcts = 0;
|
||||
internal int shortMdctSize = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of lines in allocVectors
|
||||
/// </summary>
|
||||
internal int nbAllocVectors = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bits in each band for several rates
|
||||
/// </summary>
|
||||
internal byte[] allocVectors = null;
|
||||
internal short[] logN = null;
|
||||
|
||||
internal int[] window = null;
|
||||
internal MDCTLookup mdct = new MDCTLookup();
|
||||
internal PulseCache cache = new PulseCache();
|
||||
|
||||
private CeltMode()
|
||||
{
|
||||
}
|
||||
|
||||
internal static readonly CeltMode mode48000_960_120 = new CeltMode
|
||||
{
|
||||
Fs = 48000,
|
||||
overlap = 120,
|
||||
nbEBands = 21,
|
||||
effEBands = 21,
|
||||
preemph = new int[] { 27853, 0, 4096, 8192 },
|
||||
eBands = Tables.eband5ms,
|
||||
maxLM = 3,
|
||||
nbShortMdcts = 8,
|
||||
shortMdctSize = 120,
|
||||
nbAllocVectors = 11,
|
||||
allocVectors = Tables.band_allocation,
|
||||
logN = Tables.logN400,
|
||||
window = Tables.window120,
|
||||
mdct = new MDCTLookup()
|
||||
{
|
||||
n = 1920,
|
||||
maxshift = 3,
|
||||
kfft = new FFTState[]
|
||||
{
|
||||
Tables.fft_state48000_960_0,
|
||||
Tables.fft_state48000_960_1,
|
||||
Tables.fft_state48000_960_2,
|
||||
Tables.fft_state48000_960_3,
|
||||
},
|
||||
trig = Tables.mdct_twiddles960
|
||||
},
|
||||
cache = new PulseCache()
|
||||
{
|
||||
size = 392,
|
||||
index = Tables.cache_index50,
|
||||
bits = Tables.cache_bits50,
|
||||
caps = Tables.cache_caps50,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
1300
Libraries/Concentus/CSharp/Concentus/Celt/Structs/CeltEncoder.cs
Normal file
1300
Libraries/Concentus/CSharp/Concentus/Celt/Structs/CeltEncoder.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
/* Copyright (c) 2003-2004, Mark Borgerding
|
||||
Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Modified from KISS-FFT by Jean-Marc Valin
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt.Structs
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using System;
|
||||
|
||||
internal class FFTState
|
||||
{
|
||||
internal int nfft = 0;
|
||||
internal short scale = 0;
|
||||
internal int scale_shift = 0;
|
||||
internal int shift = 0;
|
||||
internal short[] factors = new short[2 * KissFFT.MAXFACTORS];
|
||||
internal short[] bitrev = null;
|
||||
internal short[] twiddles = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright (c) 2003-2004, Mark Borgerding
|
||||
Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Modified from KISS-FFT by Jean-Marc Valin
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt.Structs
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using System;
|
||||
|
||||
internal class MDCTLookup
|
||||
{
|
||||
internal int n = 0;
|
||||
|
||||
internal int maxshift = 0;
|
||||
|
||||
// [porting note] these are pointers to static states defined in tables.cs
|
||||
internal FFTState[] kfft = new FFTState[4];
|
||||
|
||||
internal short[] trig = null;
|
||||
|
||||
internal MDCTLookup()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt.Structs
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using System;
|
||||
|
||||
internal class PulseCache
|
||||
{
|
||||
internal int size = 0;
|
||||
internal short[] index = null;
|
||||
internal byte[] bits = null;
|
||||
internal byte[] caps = null;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
size = 0;
|
||||
index = null;
|
||||
bits = null;
|
||||
caps = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
1128
Libraries/Concentus/CSharp/Concentus/Celt/Tables.cs
Normal file
1128
Libraries/Concentus/CSharp/Concentus/Celt/Tables.cs
Normal file
File diff suppressed because it is too large
Load Diff
430
Libraries/Concentus/CSharp/Concentus/Celt/VQ.cs
Normal file
430
Libraries/Concentus/CSharp/Concentus/Celt/VQ.cs
Normal file
@@ -0,0 +1,430 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Celt
|
||||
{
|
||||
using Concentus.Celt.Enums;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class VQ
|
||||
{
|
||||
internal static void exp_rotation1(int[] X, int X_ptr, int len, int stride, int c, int s)
|
||||
{
|
||||
int i;
|
||||
int ms;
|
||||
int Xptr;
|
||||
Xptr = X_ptr;
|
||||
ms = Inlines.NEG16(s);
|
||||
for (i = 0; i < len - stride; i++)
|
||||
{
|
||||
int x1, x2;
|
||||
x1 = X[Xptr];
|
||||
x2 = X[Xptr + stride];
|
||||
X[Xptr + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x2), s, x1), 15));
|
||||
X[Xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x1), ms, x2), 15));
|
||||
Xptr++;
|
||||
}
|
||||
Xptr = X_ptr + (len - 2 * stride - 1);
|
||||
for (i = len - 2 * stride - 1; i >= 0; i--)
|
||||
{
|
||||
int x1, x2;
|
||||
x1 = X[Xptr];
|
||||
x2 = X[Xptr + stride];
|
||||
X[Xptr + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x2), s, x1), 15));
|
||||
X[Xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, x1), ms, x2), 15));
|
||||
Xptr--;
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] SPREAD_FACTOR = { 15, 10, 5 };
|
||||
|
||||
internal static void exp_rotation(int[] X, int X_ptr, int len, int dir, int stride, int K, int spread)
|
||||
{
|
||||
int i;
|
||||
int c, s;
|
||||
int gain, theta;
|
||||
int stride2 = 0;
|
||||
int factor;
|
||||
|
||||
if (2 * K >= len || spread == Spread.SPREAD_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
factor = SPREAD_FACTOR[spread - 1];
|
||||
|
||||
gain = (Inlines.celt_div((int)Inlines.MULT16_16(CeltConstants.Q15_ONE, len), (int)(len + factor * K)));
|
||||
theta = Inlines.HALF16(Inlines.MULT16_16_Q15(gain, gain));
|
||||
|
||||
c = Inlines.celt_cos_norm(Inlines.EXTEND32(theta));
|
||||
s = Inlines.celt_cos_norm(Inlines.EXTEND32(Inlines.SUB16(CeltConstants.Q15ONE, theta))); /* sin(theta) */
|
||||
|
||||
if (len >= 8 * stride)
|
||||
{
|
||||
stride2 = 1;
|
||||
/* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding.
|
||||
It's basically incrementing long as (stride2+0.5)^2 < len/stride. */
|
||||
while ((stride2 * stride2 + stride2) * stride + (stride >> 2) < len)
|
||||
{
|
||||
stride2++;
|
||||
}
|
||||
}
|
||||
|
||||
/*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
|
||||
extract_collapse_mask().*/
|
||||
len = Inlines.celt_udiv(len, stride);
|
||||
for (i = 0; i < stride; i++)
|
||||
{
|
||||
if (dir < 0)
|
||||
{
|
||||
if (stride2 != 0)
|
||||
{
|
||||
exp_rotation1(X, X_ptr + (i * len), len, stride2, s, c);
|
||||
}
|
||||
|
||||
exp_rotation1(X, X_ptr + (i * len), len, 1, c, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
exp_rotation1(X, X_ptr + (i * len), len, 1, c, (short)(0 - s));
|
||||
|
||||
if (stride2 != 0)
|
||||
{
|
||||
exp_rotation1(X, X_ptr + (i * len), len, stride2, s, (short)(0 - c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Takes the pitch vector and the decoded residual vector, computes the gain
|
||||
that will give ||p+g*y||=1 and mixes the residual with the pitch. */
|
||||
internal static void normalise_residual(int[] iy, int[] X, int X_ptr,
|
||||
int N, int Ryy, int gain)
|
||||
{
|
||||
int i;
|
||||
int k;
|
||||
int t;
|
||||
int g;
|
||||
|
||||
k = Inlines.celt_ilog2(Ryy) >> 1;
|
||||
t = Inlines.VSHR32(Ryy, 2 * (k - 7));
|
||||
g = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(t), gain);
|
||||
|
||||
i = 0;
|
||||
do
|
||||
X[X_ptr + i] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(g, iy[i]), k + 1));
|
||||
while (++i < N);
|
||||
}
|
||||
|
||||
internal static uint extract_collapse_mask(int[] iy, int N, int B)
|
||||
{
|
||||
uint collapse_mask;
|
||||
int N0;
|
||||
int i;
|
||||
if (B <= 1)
|
||||
return 1;
|
||||
/*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
|
||||
exp_rotation().*/
|
||||
N0 = Inlines.celt_udiv(N, B);
|
||||
collapse_mask = 0;
|
||||
i = 0;
|
||||
do
|
||||
{
|
||||
int j;
|
||||
uint tmp = 0;
|
||||
j = 0;
|
||||
do
|
||||
{
|
||||
tmp |= unchecked((uint)iy[i * N0 + j]);
|
||||
} while (++j < N0);
|
||||
|
||||
collapse_mask |= (tmp != 0 ? 1U : 0) << i;
|
||||
} while (++i < B);
|
||||
|
||||
return collapse_mask;
|
||||
}
|
||||
|
||||
internal static uint alg_quant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder enc
|
||||
)
|
||||
{
|
||||
int[] y = new int[N];
|
||||
int[] iy = new int[N];
|
||||
int[] signx = new int[N];
|
||||
int i, j;
|
||||
int s;
|
||||
int pulsesLeft;
|
||||
int sum;
|
||||
int xy;
|
||||
int yy;
|
||||
uint collapse_mask;
|
||||
|
||||
Inlines.OpusAssert(K > 0, "alg_quant() needs at least one pulse");
|
||||
Inlines.OpusAssert(N > 1, "alg_quant() needs at least two dimensions");
|
||||
|
||||
exp_rotation(X, X_ptr, N, 1, B, K, spread);
|
||||
|
||||
/* Get rid of the sign */
|
||||
sum = 0;
|
||||
j = 0;
|
||||
do
|
||||
{
|
||||
int xpj = X_ptr + j;
|
||||
|
||||
/* OPT: Make sure the following two lines result in conditional moves
|
||||
rather than branches. */
|
||||
signx[j] = X[xpj] > 0 ? 1 : -1;
|
||||
X[xpj] = Inlines.ABS16(X[xpj]);
|
||||
|
||||
iy[j] = 0;
|
||||
y[j] = 0;
|
||||
} while (++j < N);
|
||||
|
||||
xy = yy = 0;
|
||||
|
||||
pulsesLeft = K;
|
||||
|
||||
/* Do a pre-search by projecting on the pyramid */
|
||||
if (K > (N >> 1))
|
||||
{
|
||||
int rcp;
|
||||
j = 0; do
|
||||
{
|
||||
sum += X[X_ptr + j];
|
||||
} while (++j < N);
|
||||
|
||||
/* If X is too small, just replace it with a pulse at 0 */
|
||||
/* Prevents infinities and NaNs from causing too many pulses
|
||||
to be allocated. 64 is an approximation of infinity here. */
|
||||
if (sum <= K)
|
||||
{
|
||||
X[X_ptr] = ((short)(0.5 + (1.0f) * (((int)1) << (14))))/*Inlines.QCONST16(1.0f, 14)*/;
|
||||
j = X_ptr + 1;
|
||||
do
|
||||
{
|
||||
X[j] = 0;
|
||||
} while (++j < N + X_ptr);
|
||||
|
||||
sum = ((short)(0.5 + (1.0f) * (((int)1) << (14))))/*Inlines.QCONST16(1.0f, 14)*/;
|
||||
}
|
||||
|
||||
rcp = Inlines.EXTRACT16(Inlines.MULT16_32_Q16((K - 1), Inlines.celt_rcp(sum)));
|
||||
j = 0;
|
||||
|
||||
do
|
||||
{
|
||||
/* It's really important to round *towards zero* here */
|
||||
iy[j] = Inlines.MULT16_16_Q15(X[X_ptr + j], rcp);
|
||||
y[j] = (int)iy[j];
|
||||
yy = (Inlines.MAC16_16(yy, y[j], y[j]));
|
||||
xy = Inlines.MAC16_16(xy, X[X_ptr + j], y[j]);
|
||||
y[j] *= 2;
|
||||
pulsesLeft -= iy[j];
|
||||
} while (++j < N);
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(pulsesLeft >= 1, "Allocated too many pulses in the quick pass");
|
||||
|
||||
/* This should never happen, but just in case it does (e.g. on silence)
|
||||
we fill the first bin with pulses. */
|
||||
if (pulsesLeft > N + 3)
|
||||
{
|
||||
int tmp = (int)pulsesLeft;
|
||||
yy = (Inlines.MAC16_16(yy, tmp, tmp));
|
||||
yy = (Inlines.MAC16_16(yy, tmp, y[0]));
|
||||
iy[0] += pulsesLeft;
|
||||
pulsesLeft = 0;
|
||||
}
|
||||
|
||||
s = 1;
|
||||
for (i = 0; i < pulsesLeft; i++)
|
||||
{
|
||||
int best_id;
|
||||
int best_num = 0 - CeltConstants.VERY_LARGE16;
|
||||
int best_den = 0;
|
||||
int rshift = 1 + Inlines.celt_ilog2(K - pulsesLeft + i + 1);
|
||||
best_id = 0;
|
||||
/* The squared magnitude term gets added anyway, so we might as well
|
||||
add it outside the loop */
|
||||
yy = Inlines.ADD16(yy, 1); // opus bug - was add32
|
||||
j = 0;
|
||||
do
|
||||
{
|
||||
int Rxy, Ryy;
|
||||
/* Temporary sums of the new pulse(s) */
|
||||
Rxy = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + j])), rshift));
|
||||
/* We're multiplying y[j] by two so we don't have to do it here */
|
||||
Ryy = Inlines.ADD16(yy, y[j]);
|
||||
|
||||
/* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
|
||||
Rxy is positive because the sign is pre-computed) */
|
||||
Rxy = Inlines.MULT16_16_Q15(Rxy, Rxy);
|
||||
/* The idea is to check for num/den >= best_num/best_den, but that way
|
||||
we can do it without any division */
|
||||
/* OPT: Make sure to use conditional moves here */
|
||||
if (Inlines.MULT16_16(best_den, Rxy) > Inlines.MULT16_16(Ryy, best_num))
|
||||
{
|
||||
best_den = Ryy;
|
||||
best_num = Rxy;
|
||||
best_id = j;
|
||||
}
|
||||
} while (++j < N);
|
||||
|
||||
/* Updating the sums of the new pulse(s) */
|
||||
xy = Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + best_id]));
|
||||
/* We're multiplying y[j] by two so we don't have to do it here */
|
||||
yy = Inlines.ADD16(yy, y[best_id]);
|
||||
|
||||
/* Only now that we've made the final choice, update y/iy */
|
||||
/* Multiplying y[j] by 2 so we don't have to do it everywhere else */
|
||||
y[best_id] = (y[best_id] + (2 * s));
|
||||
iy[best_id]++;
|
||||
}
|
||||
|
||||
/* Put the original sign back */
|
||||
j = 0;
|
||||
do
|
||||
{
|
||||
X[X_ptr + j] = (Inlines.MULT16_16(signx[j], X[X_ptr + j]));
|
||||
/* OPT: Make sure your compiler uses a conditional move here rather than
|
||||
a branch. */
|
||||
iy[j] = signx[j] < 0 ? -iy[j] : iy[j];
|
||||
} while (++j < N);
|
||||
|
||||
CWRS.encode_pulses(iy, N, K, enc);
|
||||
|
||||
collapse_mask = extract_collapse_mask(iy, N, B);
|
||||
|
||||
return collapse_mask;
|
||||
}
|
||||
|
||||
/** Decode pulse vector and combine the result with the pitch vector to produce
|
||||
the final normalised signal in the current band. */
|
||||
internal static uint alg_unquant(int[] X, int X_ptr, int N, int K, int spread, int B,
|
||||
EntropyCoder dec, int gain)
|
||||
{
|
||||
int Ryy;
|
||||
uint collapse_mask;
|
||||
int[] iy = new int[N];
|
||||
Inlines.OpusAssert(K > 0, "alg_unquant() needs at least one pulse");
|
||||
Inlines.OpusAssert(N > 1, "alg_unquant() needs at least two dimensions");
|
||||
Ryy = CWRS.decode_pulses(iy, N, K, dec);
|
||||
normalise_residual(iy, X, X_ptr, N, Ryy, gain);
|
||||
exp_rotation(X, X_ptr, N, -1, B, K, spread);
|
||||
collapse_mask = extract_collapse_mask(iy, N, B);
|
||||
|
||||
return collapse_mask;
|
||||
}
|
||||
|
||||
internal static void renormalise_vector(int[] X, int X_ptr, int N, int gain)
|
||||
{
|
||||
int i;
|
||||
int k;
|
||||
int E;
|
||||
int g;
|
||||
int t;
|
||||
int xptr;
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (int* px_base = X)
|
||||
{
|
||||
int* px = px_base + X_ptr;
|
||||
E = CeltConstants.EPSILON + Kernels.celt_inner_prod(px, px, N);
|
||||
}
|
||||
}
|
||||
#else
|
||||
E = CeltConstants.EPSILON + Kernels.celt_inner_prod(X, X_ptr, X, X_ptr, N);
|
||||
#endif
|
||||
k = Inlines.celt_ilog2(E) >> 1;
|
||||
t = Inlines.VSHR32(E, 2 * (k - 7));
|
||||
g = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(t), gain);
|
||||
|
||||
xptr = X_ptr;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
X[xptr] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(g, X[xptr]), k + 1));
|
||||
xptr++;
|
||||
}
|
||||
/*return celt_sqrt(E);*/
|
||||
}
|
||||
|
||||
internal static int stereo_itheta(int[] X, int X_ptr, int[] Y, int Y_ptr, int stereo, int N)
|
||||
{
|
||||
int i;
|
||||
int itheta;
|
||||
int mid, side;
|
||||
int Emid, Eside;
|
||||
|
||||
Emid = Eside = CeltConstants.EPSILON;
|
||||
if (stereo != 0)
|
||||
{
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
int m, s;
|
||||
m = Inlines.ADD16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1));
|
||||
s = Inlines.SUB16(Inlines.SHR16(X[X_ptr + i], 1), Inlines.SHR16(Y[Y_ptr + i], 1));
|
||||
Emid = Inlines.MAC16_16(Emid, m, m);
|
||||
Eside = Inlines.MAC16_16(Eside, s, s);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (int* px_base = X, py_base = Y)
|
||||
{
|
||||
int* px = px_base + X_ptr;
|
||||
int* py = py_base + Y_ptr;
|
||||
Emid += Kernels.celt_inner_prod(px, px, N);
|
||||
Eside += Kernels.celt_inner_prod(py, py, N);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Emid += Kernels.celt_inner_prod(X, X_ptr, X, X_ptr, N);
|
||||
Eside += Kernels.celt_inner_prod(Y, Y_ptr, Y, Y_ptr, N);
|
||||
#endif
|
||||
}
|
||||
mid = (Inlines.celt_sqrt(Emid));
|
||||
side = (Inlines.celt_sqrt(Eside));
|
||||
/* 0.63662 = 2/pi */
|
||||
itheta = Inlines.MULT16_16_Q15(((short)(0.5 + (0.63662f) * (((int)1) << (15))))/*Inlines.QCONST16(0.63662f, 15)*/, Inlines.celt_atan2p(side, mid));
|
||||
|
||||
return itheta;
|
||||
}
|
||||
}
|
||||
}
|
||||
284
Libraries/Concentus/CSharp/Concentus/Common/Autocorrelation.cs
Normal file
284
Libraries/Concentus/CSharp/Concentus/Common/Autocorrelation.cs
Normal file
@@ -0,0 +1,284 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
namespace Concentus.Common
|
||||
{
|
||||
using Concentus.Celt;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
|
||||
internal static class Autocorrelation
|
||||
{
|
||||
/* Compute autocorrelation */
|
||||
internal static void silk_autocorr(
|
||||
int[] results, /* O Result (length correlationCount) */
|
||||
BoxedValueInt scale, /* O Scaling of the correlation vector */
|
||||
short[] inputData, /* I Input data to correlate */
|
||||
int inputDataSize, /* I Length of input */
|
||||
int correlationCount /* I Number of correlation taps to compute */
|
||||
)
|
||||
{
|
||||
int corrCount = Inlines.silk_min_int(inputDataSize, correlationCount);
|
||||
scale.Val = Autocorrelation._celt_autocorr(inputData, results, corrCount - 1, inputDataSize);
|
||||
}
|
||||
|
||||
internal static int _celt_autocorr(
|
||||
short[] x, /* in: [0...n-1] samples x */
|
||||
int[] ac, /* out: [0...lag-1] ac values */
|
||||
int lag,
|
||||
int n
|
||||
)
|
||||
{
|
||||
int d;
|
||||
int i, k;
|
||||
int fastN = n - lag;
|
||||
int shift;
|
||||
short[] xptr;
|
||||
short[] xx = new short[n];
|
||||
Inlines.OpusAssert(n > 0);
|
||||
xptr = x;
|
||||
|
||||
shift = 0;
|
||||
{
|
||||
int ac0;
|
||||
ac0 = 1 + (n << 7);
|
||||
if ((n & 1) != 0)
|
||||
{
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9);
|
||||
}
|
||||
for (i = (n & 1); i < n; i += 2)
|
||||
{
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9);
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9);
|
||||
}
|
||||
shift = Inlines.celt_ilog2(ac0) - 30 + 10;
|
||||
shift = (shift) / 2;
|
||||
if (shift > 0)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
xx[i] = (short)(Inlines.PSHR32(xptr[i], shift));
|
||||
}
|
||||
xptr = xx;
|
||||
}
|
||||
else
|
||||
shift = 0;
|
||||
}
|
||||
CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1);
|
||||
for (k = 0; k <= lag; k++)
|
||||
{
|
||||
for (i = k + fastN, d = 0; i < n; i++)
|
||||
d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]);
|
||||
ac[k] += d;
|
||||
}
|
||||
shift = 2 * shift;
|
||||
if (shift <= 0)
|
||||
ac[0] += Inlines.SHL32((int)1, -shift);
|
||||
if (ac[0] < 268435456)
|
||||
{
|
||||
int shift2 = 29 - Inlines.EC_ILOG((uint)ac[0]);
|
||||
for (i = 0; i <= lag; i++)
|
||||
{
|
||||
ac[i] = Inlines.SHL32(ac[i], shift2);
|
||||
}
|
||||
shift -= shift2;
|
||||
}
|
||||
else if (ac[0] >= 536870912)
|
||||
{
|
||||
int shift2 = 1;
|
||||
if (ac[0] >= 1073741824)
|
||||
shift2++;
|
||||
for (i = 0; i <= lag; i++)
|
||||
{
|
||||
ac[i] = Inlines.SHR32(ac[i], shift2);
|
||||
}
|
||||
shift += shift2;
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
internal static int _celt_autocorr(
|
||||
int[] x, /* in: [0...n-1] samples x */
|
||||
int[] ac, /* out: [0...lag-1] ac values */
|
||||
int[] window,
|
||||
int overlap,
|
||||
int lag,
|
||||
int n)
|
||||
{
|
||||
int d;
|
||||
int i, k;
|
||||
int fastN = n - lag;
|
||||
int shift;
|
||||
int[] xptr;
|
||||
int[] xx = new int[n];
|
||||
|
||||
Inlines.OpusAssert(n > 0);
|
||||
Inlines.OpusAssert(overlap >= 0);
|
||||
|
||||
if (overlap == 0)
|
||||
{
|
||||
xptr = x;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
xx[i] = x[i];
|
||||
for (i = 0; i < overlap; i++)
|
||||
{
|
||||
xx[i] = Inlines.MULT16_16_Q15(x[i], window[i]);
|
||||
xx[n - i - 1] = Inlines.MULT16_16_Q15(x[n - i - 1], window[i]);
|
||||
}
|
||||
xptr = xx;
|
||||
}
|
||||
|
||||
shift = 0;
|
||||
|
||||
int ac0;
|
||||
ac0 = 1 + (n << 7);
|
||||
if ((n & 1) != 0)
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9);
|
||||
|
||||
for (i = (n & 1); i < n; i += 2)
|
||||
{
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9);
|
||||
ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9);
|
||||
}
|
||||
|
||||
shift = Inlines.celt_ilog2(ac0) - 30 + 10;
|
||||
shift = (shift) / 2;
|
||||
if (shift > 0)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
xx[i] = (Inlines.PSHR32(xptr[i], shift));
|
||||
xptr = xx;
|
||||
}
|
||||
else
|
||||
shift = 0;
|
||||
|
||||
CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1);
|
||||
for (k = 0; k <= lag; k++)
|
||||
{
|
||||
for (i = k + fastN, d = 0; i < n; i++)
|
||||
d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]);
|
||||
ac[k] += d;
|
||||
}
|
||||
|
||||
shift = 2 * shift;
|
||||
if (shift <= 0)
|
||||
ac[0] += Inlines.SHL32((int)1, -shift);
|
||||
if (ac[0] < 268435456)
|
||||
{
|
||||
int shift2 = 29 - Inlines.EC_ILOG((uint)ac[0]);
|
||||
for (i = 0; i <= lag; i++)
|
||||
ac[i] = Inlines.SHL32(ac[i], shift2);
|
||||
shift -= shift2;
|
||||
}
|
||||
else if (ac[0] >= 536870912)
|
||||
{
|
||||
int shift2 = 1;
|
||||
if (ac[0] >= 1073741824)
|
||||
shift2++;
|
||||
for (i = 0; i <= lag; i++)
|
||||
ac[i] = Inlines.SHR32(ac[i], shift2);
|
||||
shift += shift2;
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
private const int QC = 10;
|
||||
private const int QS = 14;
|
||||
|
||||
/* Autocorrelations for a warped frequency axis */
|
||||
internal static void silk_warped_autocorrelation(
|
||||
int[] corr, /* O Result [order + 1] */
|
||||
BoxedValueInt scale, /* O Scaling of the correlation vector */
|
||||
short[] input, /* I Input data to correlate */
|
||||
int warping_Q16, /* I Warping coefficient */
|
||||
int length, /* I Length of input */
|
||||
int order /* I Correlation order (even) */
|
||||
)
|
||||
{
|
||||
int n, i, lsh;
|
||||
int tmp1_QS, tmp2_QS;
|
||||
int[] state_QS = new int[order + 1];// = { 0 };
|
||||
long[] corr_QC = new long[order + 1];// = { 0 };
|
||||
|
||||
/* Order must be even */
|
||||
Inlines.OpusAssert((order & 1) == 0);
|
||||
Inlines.OpusAssert(2 * QS - QC >= 0);
|
||||
|
||||
/* Loop over samples */
|
||||
for (n = 0; n < length; n++)
|
||||
{
|
||||
tmp1_QS = Inlines.silk_LSHIFT32((int)input[n], QS);
|
||||
/* Loop over allpass sections */
|
||||
for (i = 0; i < order; i += 2)
|
||||
{
|
||||
/* Output of allpass section */
|
||||
tmp2_QS = Inlines.silk_SMLAWB(state_QS[i], state_QS[i + 1] - tmp1_QS, warping_Q16);
|
||||
state_QS[i] = tmp1_QS;
|
||||
corr_QC[i] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, state_QS[0]), 2 * QS - QC);
|
||||
/* Output of allpass section */
|
||||
tmp1_QS = Inlines.silk_SMLAWB(state_QS[i + 1], state_QS[i + 2] - tmp2_QS, warping_Q16);
|
||||
state_QS[i + 1] = tmp2_QS;
|
||||
corr_QC[i + 1] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp2_QS, state_QS[0]), 2 * QS - QC);
|
||||
}
|
||||
state_QS[order] = tmp1_QS;
|
||||
corr_QC[order] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(tmp1_QS, state_QS[0]), 2 * QS - QC);
|
||||
}
|
||||
|
||||
lsh = Inlines.silk_CLZ64(corr_QC[0]) - 35;
|
||||
lsh = Inlines.silk_LIMIT(lsh, -12 - QC, 30 - QC);
|
||||
scale.Val = -(QC + lsh);
|
||||
Inlines.OpusAssert(scale.Val >= -30 && scale.Val <= 12);
|
||||
if (lsh >= 0)
|
||||
{
|
||||
for (i = 0; i < order + 1; i++)
|
||||
{
|
||||
corr[i] = (int)(Inlines.silk_LSHIFT64(corr_QC[i], lsh));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < order + 1; i++)
|
||||
{
|
||||
corr[i] = (int)(Inlines.silk_RSHIFT64(corr_QC[i], -lsh));
|
||||
}
|
||||
}
|
||||
Inlines.OpusAssert(corr_QC[0] >= 0); /* If breaking, decrease QC*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
221
Libraries/Concentus/CSharp/Concentus/Common/CPlusPlus/Arrays.cs
Normal file
221
Libraries/Concentus/CSharp/Concentus/Common/CPlusPlus/Arrays.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
/* Copyright (c) 2016 Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Common.CPlusPlus
|
||||
{
|
||||
using System;
|
||||
|
||||
internal static class Arrays
|
||||
{
|
||||
internal static T[][] InitTwoDimensionalArray<T>(int x, int y)
|
||||
{
|
||||
T[][] returnVal = new T[x][];
|
||||
for (int c = 0; c < x; c++)
|
||||
{
|
||||
returnVal[c] = new T[y];
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
internal static Pointer<Pointer<T>> InitTwoDimensionalArrayPointer<T>(int x, int y)
|
||||
{
|
||||
Pointer<Pointer<T>> returnVal = Pointer.Malloc<Pointer<T>>(x);
|
||||
for (int c = 0; c < x; c++)
|
||||
{
|
||||
returnVal[c] = Pointer.Malloc<T>(y);
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
internal static T[][][] InitThreeDimensionalArray<T>(int x, int y, int z)
|
||||
{
|
||||
T[][][] returnVal = new T[x][][];
|
||||
for (int c = 0; c < x; c++)
|
||||
{
|
||||
returnVal[c] = new T[y][];
|
||||
for (int a = 0; a < y; a++)
|
||||
{
|
||||
returnVal[c][a] = new T[z];
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
//FIXME: For the most part this method is used to zero-out arrays, which is usually already done by the runtime.
|
||||
|
||||
internal static void MemSetByte(byte[] array, byte value)
|
||||
{
|
||||
for (int c = 0; c < array.Length; c++)
|
||||
{
|
||||
array[c] = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemSetInt(int[] array, int value, int length)
|
||||
{
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
array[c] = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemSetShort(short[] array, short value, int length)
|
||||
{
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
array[c] = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemSetFloat(float[] array, float value, int length)
|
||||
{
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
array[c] = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemSetSbyte(sbyte[] array, sbyte value, int length)
|
||||
{
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
array[c] = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemSetWithOffset<T>(T[] array, T value, int offset, int length)
|
||||
{
|
||||
for (int c = offset; c < offset + length; c++)
|
||||
{
|
||||
array[c] = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemMove<T>(T[] array, int src_idx, int dst_idx, int length)
|
||||
{
|
||||
if (src_idx == dst_idx || length == 0)
|
||||
return;
|
||||
|
||||
// Do regions overlap?
|
||||
if (src_idx + length > dst_idx || dst_idx + length > src_idx)
|
||||
{
|
||||
// Take extra precautions
|
||||
if (dst_idx < src_idx)
|
||||
{
|
||||
// Copy forwards
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
array[c + dst_idx] = array[c + src_idx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy backwards
|
||||
for (int c = length - 1; c >= 0; c--)
|
||||
{
|
||||
array[c + dst_idx] = array[c + src_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Memory regions cannot overlap; just do a fast copy
|
||||
Array.Copy(array, src_idx, array, dst_idx, length);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemMoveInt(int[] array, int src_idx, int dst_idx, int length)
|
||||
{
|
||||
if (src_idx == dst_idx || length == 0)
|
||||
return;
|
||||
|
||||
// Do regions overlap?
|
||||
if (src_idx + length > dst_idx || dst_idx + length > src_idx)
|
||||
{
|
||||
// Take extra precautions
|
||||
if (dst_idx < src_idx)
|
||||
{
|
||||
// Copy forwards
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
array[c + dst_idx] = array[c + src_idx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy backwards
|
||||
for (int c = length - 1; c >= 0; c--)
|
||||
{
|
||||
array[c + dst_idx] = array[c + src_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Memory regions cannot overlap; just do a fast copy
|
||||
Array.Copy(array, src_idx, array, dst_idx, length);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MemMoveShort(short[] array, int src_idx, int dst_idx, int length)
|
||||
{
|
||||
if (src_idx == dst_idx || length == 0)
|
||||
return;
|
||||
|
||||
// Do regions overlap?
|
||||
if (src_idx + length > dst_idx || dst_idx + length > src_idx)
|
||||
{
|
||||
// Take extra precautions
|
||||
if (dst_idx < src_idx)
|
||||
{
|
||||
// Copy forwards
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
array[c + dst_idx] = array[c + src_idx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy backwards
|
||||
for (int c = length - 1; c >= 0; c--)
|
||||
{
|
||||
array[c + dst_idx] = array[c + src_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Memory regions cannot overlap; just do a fast copy
|
||||
Array.Copy(array, src_idx, array, dst_idx, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/* Copyright (c) 2016 Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Common.CPlusPlus
|
||||
{
|
||||
public class BoxedValueInt
|
||||
{
|
||||
public int Val;
|
||||
|
||||
public BoxedValueInt(int v = 0)
|
||||
{
|
||||
Val = v;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Val.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class BoxedValueShort
|
||||
{
|
||||
public short Val;
|
||||
|
||||
public BoxedValueShort(short v = 0)
|
||||
{
|
||||
Val = v;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Val.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class BoxedValueSbyte
|
||||
{
|
||||
public sbyte Val;
|
||||
|
||||
public BoxedValueSbyte(sbyte v = 0)
|
||||
{
|
||||
Val = v;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Val.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For performance reasons, do not use this generic class if possible
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class BoxedValue<T>
|
||||
{
|
||||
public T Val;
|
||||
|
||||
public BoxedValue(T v = default(T))
|
||||
{
|
||||
Val = v;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Val == null ? "null" : Val.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
563
Libraries/Concentus/CSharp/Concentus/Common/CPlusPlus/Pointer.cs
Normal file
563
Libraries/Concentus/CSharp/Concentus/Common/CPlusPlus/Pointer.cs
Normal file
@@ -0,0 +1,563 @@
|
||||
/* Copyright (c) 2016 Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Common.CPlusPlus
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// This simulates a C++ style pointer as far as can be implemented in C#. It represents a handle
|
||||
/// to an array of objects, along with a base offset that represents the address.
|
||||
/// When you are programming in debug mode, this class also enforces memory boundaries,
|
||||
/// tracks uninitialized values, and also records all statistics of accesses to its base array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class Pointer<T>
|
||||
{
|
||||
private const bool CHECK_UNINIT_MEM = false;
|
||||
|
||||
#if DEBUG && !NET35
|
||||
private class Statistics
|
||||
{
|
||||
public Statistics(int baseOffset)
|
||||
{
|
||||
this.baseOffset = baseOffset;
|
||||
}
|
||||
|
||||
public int baseOffset;
|
||||
public int minReadIndex = int.MaxValue;
|
||||
public int maxReadIndex = int.MinValue;
|
||||
public int minWriteIndex = int.MaxValue;
|
||||
public int maxWriteIndex = int.MinValue;
|
||||
|
||||
public Tuple<int, int> ReadRange
|
||||
{
|
||||
get
|
||||
{
|
||||
if (minReadIndex == int.MaxValue || maxReadIndex == int.MinValue)
|
||||
return null;
|
||||
return new Tuple<int, int>(minReadIndex - baseOffset, maxReadIndex - baseOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public Tuple<int, int> WriteRange
|
||||
{
|
||||
get
|
||||
{
|
||||
if (minWriteIndex == int.MaxValue || maxWriteIndex == int.MinValue)
|
||||
return null;
|
||||
return new Tuple<int, int>(minWriteIndex - baseOffset, maxWriteIndex - baseOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool[] _initialized;
|
||||
private Statistics _statistics;
|
||||
private int _length;
|
||||
#endif
|
||||
|
||||
private T[] _array;
|
||||
private int _offset;
|
||||
|
||||
public Pointer(int capacity)
|
||||
{
|
||||
_array = new T[capacity];
|
||||
_offset = 0;
|
||||
#if DEBUG && !NET35
|
||||
_length = capacity;
|
||||
_statistics = new Statistics(0);
|
||||
_initialized = new bool[capacity];
|
||||
for (int c = 0; c < capacity; c++)
|
||||
{
|
||||
_initialized[c] = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public Pointer(T[] buffer)
|
||||
{
|
||||
_array = buffer;
|
||||
_offset = 0;
|
||||
#if DEBUG && !NET35
|
||||
_length = buffer.Length;
|
||||
_statistics = new Statistics(0);
|
||||
_initialized = new bool[buffer.Length];
|
||||
for (int c = 0; c < buffer.Length; c++)
|
||||
{
|
||||
_initialized[c] = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public Pointer(T[] buffer, int absoluteOffset)
|
||||
{
|
||||
_array = buffer;
|
||||
_offset = absoluteOffset;
|
||||
#if DEBUG && !NET35
|
||||
_length = buffer.Length - absoluteOffset;
|
||||
//Inlines.OpusAssert(_length >= 0, "Attempted to point past the end of an array");
|
||||
_statistics = new Statistics(absoluteOffset);
|
||||
_initialized = new bool[buffer.Length];
|
||||
for (int c = 0; c < buffer.Length; c++)
|
||||
{
|
||||
_initialized[c] = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG && !NET35
|
||||
private Pointer(T[] buffer, int absoluteOffset, Statistics statistics, bool[] initializedStatus)
|
||||
{
|
||||
_array = buffer;
|
||||
_offset = absoluteOffset;
|
||||
_length = buffer.Length - absoluteOffset;
|
||||
//Inlines.OpusAssert(_length >= 0, "Attempted to point past the end of an array");
|
||||
_statistics = statistics;
|
||||
_initialized = initializedStatus;
|
||||
}
|
||||
|
||||
public Tuple<int, int> ReadRange
|
||||
{
|
||||
get
|
||||
{
|
||||
return _statistics.ReadRange;
|
||||
}
|
||||
}
|
||||
|
||||
public Tuple<int, int> WriteRange
|
||||
{
|
||||
get
|
||||
{
|
||||
return _statistics.WriteRange;
|
||||
}
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public int Offset
|
||||
{
|
||||
get
|
||||
{
|
||||
return _offset;
|
||||
}
|
||||
}
|
||||
|
||||
// This should only be temporary while I migrate from pointers to arrays
|
||||
public T[] Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return _array;
|
||||
}
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
#if DEBUG && !NET35
|
||||
#pragma warning disable 162
|
||||
if (CHECK_UNINIT_MEM) Inlines.OpusAssert(_initialized[index + _offset], "Attempted to read from uninitialized memory!");
|
||||
#pragma warning restore 162
|
||||
// Inlines.OpusAssert(index < _length, "Attempted to read past the end of an array!");
|
||||
_statistics.maxReadIndex = Math.Max(_statistics.maxReadIndex, index + _offset);
|
||||
_statistics.minReadIndex = Math.Min(_statistics.minReadIndex, index + _offset);
|
||||
#endif
|
||||
return _array[index + _offset];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
#if DEBUG && !NET35
|
||||
// Inlines.OpusAssert(index < _length, "Attempted to write past the end of an array!");
|
||||
_statistics.maxWriteIndex = Math.Max(_statistics.maxWriteIndex, index + _offset);
|
||||
_statistics.minWriteIndex = Math.Min(_statistics.minWriteIndex, index + _offset);
|
||||
_initialized[index + _offset] = true;
|
||||
#endif
|
||||
_array[index + _offset] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public T this[uint index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return this[(int)index];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this[(int)index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value currently under the pointer, and returns a new pointer with +1 offset.
|
||||
/// This method is not very efficient because it creates new pointers; this is because we must preserve
|
||||
/// the pass-by-value nature of C++ pointers when they are used as arguments to functions
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Pointer<T> Iterate(out T returnVal)
|
||||
{
|
||||
returnVal = _array[_offset];
|
||||
return Point(1);
|
||||
}
|
||||
|
||||
#if DEBUG && !NET35
|
||||
public Pointer<T> Point(int relativeOffset)
|
||||
{
|
||||
if (relativeOffset == 0) return this;
|
||||
return new Pointer<T>(_array, _offset + relativeOffset, _statistics, _initialized);
|
||||
}
|
||||
|
||||
public Pointer<T> Point(uint relativeOffset)
|
||||
{
|
||||
if (relativeOffset == 0) return this;
|
||||
return new Pointer<T>(_array, _offset + (int)relativeOffset, _statistics, _initialized);
|
||||
}
|
||||
#else
|
||||
public Pointer<T> Point(int relativeOffset)
|
||||
{
|
||||
if (relativeOffset == 0) return this;
|
||||
return new Pointer<T>(_array, _offset + relativeOffset);
|
||||
}
|
||||
|
||||
public Pointer<T> Point(uint relativeOffset)
|
||||
{
|
||||
if (relativeOffset == 0) return this;
|
||||
return new Pointer<T>(_array, _offset + (int)relativeOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
private static string invert_endianness(string hexstring)
|
||||
{
|
||||
StringBuilder b = new StringBuilder(hexstring.Length);
|
||||
for (int c = 0; c < hexstring.Length / 2; c++)
|
||||
{
|
||||
b.Append(hexstring.Substring(hexstring.Length - ((c + 1) * 2), 2));
|
||||
}
|
||||
return b.ToString();
|
||||
}
|
||||
|
||||
private static void PrintMemCopy<E>(E[] source, int sourceOffset, int length)
|
||||
{
|
||||
if (typeof(E) == typeof(int) || typeof(E) == typeof(uint))
|
||||
{
|
||||
Debug.WriteLine(string.Format("memcpy of {0} bytes", length * 4));
|
||||
string buf = string.Empty;
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
buf += invert_endianness(string.Format("{0:x8}", source[c + sourceOffset]));
|
||||
}
|
||||
Debug.WriteLine(buf);
|
||||
}
|
||||
else if (typeof(E) == typeof(short) || typeof(E) == typeof(ushort))
|
||||
{
|
||||
Debug.WriteLine(string.Format("memcpy of {0} bytes", length * 2));
|
||||
string buf = string.Empty;
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
buf += invert_endianness(string.Format("{0:x4}", source[c + sourceOffset]));
|
||||
}
|
||||
Debug.WriteLine(buf);
|
||||
}
|
||||
else if (typeof(E) == typeof(byte) || typeof(E) == typeof(sbyte))
|
||||
{
|
||||
Debug.WriteLine(string.Format("memcpy of {0} bytes", length));
|
||||
string buf = string.Empty;
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
buf += invert_endianness(string.Format("{0:x2}", source[c + sourceOffset]));
|
||||
}
|
||||
Debug.WriteLine(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of this pointer, starting at its current address, into the space of another pointer.
|
||||
/// !!! IMPORTANT !!! REMEMBER THAT C++ memcpy is (DEST, SOURCE, LENGTH) !!!!
|
||||
/// IN C# IT IS (SOURCE, DEST, LENGTH). DON'T GET SCOOPED LIKE I DID
|
||||
/// </summary>
|
||||
/// <param name="destination"></param>
|
||||
/// <param name="length"></param>
|
||||
#if DEBUG
|
||||
public void MemCopyTo(Pointer<T> destination, int length, bool debug = false)
|
||||
{
|
||||
Inlines.OpusAssert(length >= 0, "Cannot memcopy() with a negative length!");
|
||||
if (debug)
|
||||
PrintMemCopy(_array, _offset, length);
|
||||
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
destination[c] = _array[c + _offset];
|
||||
}
|
||||
}
|
||||
#else
|
||||
public void MemCopyTo(Pointer<T> destination, int length)
|
||||
{
|
||||
if (destination is Pointer<T>)
|
||||
{
|
||||
// Use the fast way if we have access to the base array
|
||||
Array.Copy(_array, _offset, ((Pointer<T>)destination)._array, destination.Offset, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise do it the slow way
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
destination[c] = _array[c + _offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of this pointer, starting at its current address, into an array.
|
||||
/// !!! IMPORTANT !!! REMEMBER THAT C++ memcpy is (DEST, SOURCE, LENGTH) !!!!
|
||||
/// </summary>
|
||||
/// <param name="destination"></param>
|
||||
/// <param name="length"></param>
|
||||
#if DEBUG
|
||||
public void MemCopyTo(T[] destination, int destOffset, int length)
|
||||
{
|
||||
Inlines.OpusAssert(length >= 0, "Cannot memcopy() with a negative length!");
|
||||
//PrintMemCopy(_array, _offset, length);
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
destination[c + destOffset] = _array[c + _offset];
|
||||
}
|
||||
}
|
||||
#else
|
||||
public void MemCopyTo(T[] destination, int offset, int length)
|
||||
{
|
||||
// Use the fast way if we have access to the base array
|
||||
Array.Copy(_array, _offset, destination, offset, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Loads N values from a source array into this pointer's space
|
||||
/// </summary>
|
||||
/// <param name="length"></param>
|
||||
#if DEBUG && !NET35
|
||||
public void MemCopyFrom(T[] source, int sourceOffset, int length)
|
||||
{
|
||||
Inlines.OpusAssert(length >= 0, "Cannot memcopy() with a negative length!");
|
||||
//PrintMemCopy(source, sourceOffset, length);
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
_array[c + _offset] = source[c + sourceOffset];
|
||||
_initialized[c + _offset] = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public void MemCopyFrom(T[] source, int sourceOffset, int length)
|
||||
{
|
||||
Array.Copy(source, sourceOffset, _array, _offset, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a certain value to a range of spaces in this array
|
||||
/// </summary>
|
||||
/// <param name="value">The value to set</param>
|
||||
/// <param name="length">The number of values to write</param>
|
||||
public void MemSet(T value, int length)
|
||||
{
|
||||
#if DEBUG
|
||||
Inlines.OpusAssert(length >= 0, "Cannot memset() with a negative length!");
|
||||
#endif
|
||||
MemSet(value, (uint)length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a certain value to a range of spaces in this array
|
||||
/// </summary>
|
||||
/// <param name="value">The value to set</param>
|
||||
/// <param name="length">The number of values to write</param>
|
||||
public void MemSet(T value, uint length)
|
||||
{
|
||||
for (int c = _offset; c < _offset + length; c++)
|
||||
{
|
||||
_array[c] = value;
|
||||
#if DEBUG && !NET35
|
||||
_initialized[c] = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void MemMoveTo(Pointer<T> other, int length)
|
||||
{
|
||||
if (_array == other._array)
|
||||
{
|
||||
// Pointers refer to the same array, perform a move
|
||||
//if (debug)
|
||||
// PrintMemCopy(_array, _offset, length);
|
||||
MemMove(other.Offset - Offset, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pointers refer to different arrays (if you end up here you probably wanted to just to MemCopy())
|
||||
// Debug.WriteLine("Unnecessary memmove detected");
|
||||
MemCopyTo(other, length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves regions of memory within the bounds of this pointer's array.
|
||||
/// Extra checks are done to ensure that the data is not corrupted if the copy
|
||||
/// regions overlap
|
||||
/// </summary>
|
||||
/// <param name="move_dist">The offset to send this pointer's data to</param>
|
||||
/// <param name="length">The number of values to copy</param>
|
||||
#if DEBUG && !NET35
|
||||
public void MemMove(int move_dist, int length)
|
||||
{
|
||||
Inlines.OpusAssert(length >= 0, "Cannot memmove() with a negative length!");
|
||||
if (move_dist == 0 || length == 0)
|
||||
return;
|
||||
|
||||
// Do regions overlap?
|
||||
if ((move_dist > 0 && move_dist < length) || (move_dist < 0 && 0 - move_dist > length))
|
||||
{
|
||||
// Take extra precautions
|
||||
if (move_dist < 0)
|
||||
{
|
||||
// Copy forwards
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
_array[c + _offset + move_dist] = _array[c + _offset];
|
||||
_initialized[c + _offset + move_dist] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy backwards
|
||||
for (int c = length - 1; c >= 0; c--)
|
||||
{
|
||||
_array[c + _offset + move_dist] = _array[c + _offset];
|
||||
_initialized[c + _offset + move_dist] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int c = 0; c < length; c++)
|
||||
{
|
||||
_array[c + _offset + move_dist] = _array[c + _offset];
|
||||
_initialized[c + _offset + move_dist] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
public void MemMove(int move_dist, int length)
|
||||
{
|
||||
Arrays.MemMove(_array, _offset, _offset + move_dist, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*/// <summary>
|
||||
/// Simulates pointer zooming: newPtr = &ptr[offset].
|
||||
/// Returns a pointer that is offset from this one within the same buffer.
|
||||
/// </summary>
|
||||
/// <param name="arg"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
internal static Pointer<T> operator +(Pointer<T> arg, int offset)
|
||||
{
|
||||
return new Pointer<T>(arg._array, arg._offset + offset);
|
||||
}*/
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || GetType() != obj.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Pointer<T> other = (Pointer<T>)obj;
|
||||
return other._offset == _offset &&
|
||||
other._array == _array;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _array.GetHashCode() + _offset.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a helper class which contains static methods that involve pointers
|
||||
/// </summary>
|
||||
public static class Pointer
|
||||
{
|
||||
/// <summary>
|
||||
/// Allocates a new array and returns a pointer to it
|
||||
/// </summary>
|
||||
/// <typeparam name="E"></typeparam>
|
||||
/// <param name="capacity"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer<E> Malloc<E>(int capacity)
|
||||
{
|
||||
//this returns a pointer inside of a random field, to make sure offset indexing works properly
|
||||
//E[] field = new E[capacity * 2];
|
||||
//return new Pointer<E>(field, new Random().Next(0, capacity - 1));
|
||||
return new Pointer<E>(capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a pointer to an existing array
|
||||
/// </summary>
|
||||
/// <typeparam name="E"></typeparam>
|
||||
/// <param name="memory"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static Pointer<E> GetPointer<E>(this E[] memory, int offset = 0)
|
||||
{
|
||||
if (memory == null)
|
||||
return null;
|
||||
//if (Debugger.IsAttached && offset == memory.Length / 2)
|
||||
//{
|
||||
// // This may be a partitioned array. Signal the debugger
|
||||
// Debugger.Break();
|
||||
//}
|
||||
return new Pointer<E>(memory, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
790
Libraries/Concentus/CSharp/Concentus/Common/EntropyCoder.cs
Normal file
790
Libraries/Concentus/CSharp/Concentus/Common/EntropyCoder.cs
Normal file
@@ -0,0 +1,790 @@
|
||||
/* Copyright (c) 2001-2011 Timothy B. Terriberry
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Common
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System.Diagnostics;
|
||||
|
||||
/*A range decoder.
|
||||
This is an entropy decoder based upon \cite{Mar79}, which is itself a
|
||||
rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}.
|
||||
It is very similar to arithmetic encoding, except that encoding is done with
|
||||
digits in any base, instead of with bits, and so it is faster when using
|
||||
larger bases (i.e.: a byte).
|
||||
The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$
|
||||
is the base, longer than the theoretical optimum, but to my knowledge there
|
||||
is no published justification for this claim.
|
||||
This only seems true when using near-infinite precision arithmetic so that
|
||||
the process is carried out with no rounding errors.
|
||||
|
||||
An excellent description of implementation details is available at
|
||||
http://www.arturocampos.com/ac_range.html
|
||||
A recent work \cite{MNW98} which proposes several changes to arithmetic
|
||||
encoding for efficiency actually re-discovers many of the principles
|
||||
behind range encoding, and presents a good theoretical analysis of them.
|
||||
|
||||
End of stream is handled by writing out the smallest number of bits that
|
||||
ensures that the stream will be correctly decoded regardless of the value of
|
||||
any subsequent bits.
|
||||
ec_tell() can be used to determine how many bits were needed to decode
|
||||
all the symbols thus far; other data can be packed in the remaining bits of
|
||||
the input buffer.
|
||||
@PHDTHESIS{Pas76,
|
||||
author="Richard Clark Pasco",
|
||||
title="Source coding algorithms for fast data compression",
|
||||
school="Dept. of Electrical Engineering, Stanford University",
|
||||
address="Stanford, CA",
|
||||
month=May,
|
||||
year=1976
|
||||
}
|
||||
@INPROCEEDINGS{Mar79,
|
||||
author="Martin, G.N.N.",
|
||||
title="Range encoding: an algorithm for removing redundancy from a digitised
|
||||
message",
|
||||
booktitle="Video & Data Recording Conference",
|
||||
year=1979,
|
||||
address="Southampton",
|
||||
month=Jul
|
||||
}
|
||||
@ARTICLE{MNW98,
|
||||
author="Alistair Moffat and Radford Neal and Ian H. Witten",
|
||||
title="Arithmetic Coding Revisited",
|
||||
journal="{ACM} Transactions on Information Systems",
|
||||
year=1998,
|
||||
volume=16,
|
||||
number=3,
|
||||
pages="256--294",
|
||||
month=Jul,
|
||||
URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf"
|
||||
}*/
|
||||
internal class EntropyCoder
|
||||
{
|
||||
private const int EC_WINDOW_SIZE = ((int)sizeof(uint) * 8);
|
||||
|
||||
///*The number of bits to use for the range-coded part of uint integers.*/
|
||||
private const int EC_UINT_BITS = 8;
|
||||
|
||||
///*The resolution of fractional-precision bit usage measurements, i.e.,
|
||||
// 3 => 1/8th bits.*/
|
||||
public const int BITRES = 3;
|
||||
|
||||
/*The number of bits to output at a time.*/
|
||||
private const int EC_SYM_BITS = (8);
|
||||
|
||||
/*The total number of bits in each of the state registers.*/
|
||||
private const int EC_CODE_BITS = (32);
|
||||
|
||||
/*The maximum symbol value.*/
|
||||
private const uint EC_SYM_MAX = ((1U << EC_SYM_BITS) - 1);
|
||||
|
||||
/*Bits to shift by to move a symbol into the high-order position.*/
|
||||
private const uint EC_CODE_SHIFT = (EC_CODE_BITS - EC_SYM_BITS - 1);
|
||||
|
||||
/*Carry bit of the high-order range symbol.*/
|
||||
private const uint EC_CODE_TOP = ((1U) << (EC_CODE_BITS - 1));
|
||||
|
||||
/*Low-order bit of the high-order range symbol.*/
|
||||
private const uint EC_CODE_BOT = (EC_CODE_TOP >> EC_SYM_BITS);
|
||||
|
||||
/*The number of bits available for the last, partial symbol in the code field.*/
|
||||
private const int EC_CODE_EXTRA = ((EC_CODE_BITS - 2) % EC_SYM_BITS + 1);
|
||||
|
||||
//////////////// Coder State ////////////////////
|
||||
|
||||
/*POINTER to Buffered input/output.*/
|
||||
public byte[] buf;
|
||||
public int buf_ptr;
|
||||
|
||||
/*The size of the buffer.*/
|
||||
public uint storage;
|
||||
|
||||
/*The offset at which the last byte containing raw bits was read/written.*/
|
||||
public uint end_offs;
|
||||
|
||||
/*Bits that will be read from/written at the end.*/
|
||||
public uint end_window;
|
||||
|
||||
/*Number of valid bits in end_window.*/
|
||||
public int nend_bits;
|
||||
|
||||
/*The total number of whole bits read/written.
|
||||
This does not include partial bits currently in the range coder.*/
|
||||
public int nbits_total;
|
||||
|
||||
/*The offset at which the next range coder byte will be read/written.*/
|
||||
public uint offs;
|
||||
|
||||
/*The number of values in the current range.*/
|
||||
public uint rng;
|
||||
|
||||
/*In the decoder: the difference between the top of the current range and
|
||||
the input value, minus one.
|
||||
In the encoder: the low end of the current range.*/
|
||||
public uint val;
|
||||
|
||||
/*In the decoder: the saved normalization factor from ec_decode().
|
||||
In the encoder: the number of oustanding carry propagating symbols.*/
|
||||
public uint ext;
|
||||
|
||||
/*A buffered input/output symbol, awaiting carry propagation.*/
|
||||
public int rem;
|
||||
|
||||
/*Nonzero if an error occurred.*/
|
||||
public int error;
|
||||
|
||||
public EntropyCoder()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
buf = null;
|
||||
buf_ptr = 0;
|
||||
storage = 0;
|
||||
end_offs = 0;
|
||||
end_window = 0;
|
||||
nend_bits = 0;
|
||||
offs = 0;
|
||||
rng = 0;
|
||||
val = 0;
|
||||
ext = 0;
|
||||
rem = 0;
|
||||
error = 0;
|
||||
}
|
||||
|
||||
public void Assign(EntropyCoder other)
|
||||
{
|
||||
this.buf = other.buf;
|
||||
this.buf_ptr = other.buf_ptr;
|
||||
this.storage = other.storage;
|
||||
this.end_offs = other.end_offs;
|
||||
this.end_window = other.end_window;
|
||||
this.nend_bits = other.nend_bits;
|
||||
this.nbits_total = other.nbits_total;
|
||||
this.offs = other.offs;
|
||||
this.rng = other.rng;
|
||||
this.val = other.val;
|
||||
this.ext = other.ext;
|
||||
this.rem = other.rem;
|
||||
this.error = other.error;
|
||||
}
|
||||
|
||||
internal int read_byte()
|
||||
{
|
||||
return this.offs < this.storage ? this.buf[buf_ptr + this.offs++] : 0;
|
||||
}
|
||||
|
||||
internal int read_byte_from_end()
|
||||
{
|
||||
return this.end_offs < this.storage ?
|
||||
this.buf[buf_ptr + (this.storage - ++(this.end_offs))] : 0;
|
||||
}
|
||||
|
||||
internal int write_byte(uint _value)
|
||||
{
|
||||
if (this.offs + this.end_offs >= this.storage)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
this.buf[buf_ptr + this.offs++] = (byte)_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal int write_byte_at_end(uint _value)
|
||||
{
|
||||
if (this.offs + this.end_offs >= this.storage)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
this.buf[buf_ptr + (this.storage - ++(this.end_offs))] = (byte)_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes the contents of val and rng so that rng lies entirely in the high-order symbol.
|
||||
/// </summary>
|
||||
internal void dec_normalize()
|
||||
{
|
||||
/*If the range is too small, rescale it and input some bits.*/
|
||||
while (this.rng <= EC_CODE_BOT)
|
||||
{
|
||||
int sym;
|
||||
this.nbits_total += EC_SYM_BITS;
|
||||
this.rng <<= EC_SYM_BITS;
|
||||
|
||||
/*Use up the remaining bits from our last symbol.*/
|
||||
sym = this.rem;
|
||||
|
||||
/*Read the next value from the input.*/
|
||||
this.rem = read_byte();
|
||||
|
||||
/*Take the rest of the bits we need from this new symbol.*/
|
||||
sym = (sym << EC_SYM_BITS | this.rem) >> (EC_SYM_BITS - EC_CODE_EXTRA);
|
||||
|
||||
/*And subtract them from val, capped to be less than EC_CODE_TOP.*/
|
||||
this.val = (uint)((this.val << EC_SYM_BITS) + (EC_SYM_MAX & ~sym)) & (EC_CODE_TOP - 1);
|
||||
}
|
||||
}
|
||||
|
||||
internal void dec_init(byte[] _buf, int _buf_ptr, uint _storage)
|
||||
{
|
||||
this.buf = _buf;
|
||||
this.buf_ptr = _buf_ptr;
|
||||
this.storage = _storage;
|
||||
this.end_offs = 0;
|
||||
this.end_window = 0;
|
||||
this.nend_bits = 0;
|
||||
/*This is the offset from which ec_tell() will subtract partial bits.
|
||||
The final value after the ec_dec_normalize() call will be the same as in
|
||||
the encoder, but we have to compensate for the bits that are added there.*/
|
||||
this.nbits_total = EC_CODE_BITS + 1
|
||||
- ((EC_CODE_BITS - EC_CODE_EXTRA) / EC_SYM_BITS) * EC_SYM_BITS;
|
||||
this.offs = 0;
|
||||
this.rng = 1U << EC_CODE_EXTRA;
|
||||
this.rem = read_byte();
|
||||
this.val = this.rng - 1 - (uint)(this.rem >> (EC_SYM_BITS - EC_CODE_EXTRA));
|
||||
this.error = 0;
|
||||
/*Normalize the interval.*/
|
||||
dec_normalize();
|
||||
}
|
||||
|
||||
internal uint decode(uint _ft)
|
||||
{
|
||||
uint s;
|
||||
this.ext = this.rng / _ft;
|
||||
s = (uint)(this.val / this.ext);
|
||||
return _ft - Inlines.EC_MINI(s + 1, _ft);
|
||||
}
|
||||
|
||||
internal uint decode_bin(uint _bits)
|
||||
{
|
||||
uint s;
|
||||
this.ext = this.rng >> (int)_bits;
|
||||
s = (uint)(this.val / this.ext);
|
||||
return (1U << (int)_bits) - Inlines.EC_MINI(s + 1U, 1U << (int)_bits);
|
||||
}
|
||||
|
||||
internal void dec_update(uint _fl, uint _fh, uint _ft)
|
||||
{
|
||||
uint s;
|
||||
s = this.ext * (_ft - _fh);
|
||||
this.val -= s;
|
||||
this.rng = _fl > 0 ? this.ext * (_fh - _fl) : this.rng - s;
|
||||
dec_normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The probability of having a "one" is 1/(1<<_logp).
|
||||
/// </summary>
|
||||
/// <param name="_logp"></param>
|
||||
/// <returns></returns>
|
||||
internal int dec_bit_logp(uint _logp)
|
||||
{
|
||||
uint r;
|
||||
uint d;
|
||||
uint s;
|
||||
int ret;
|
||||
r = this.rng;
|
||||
d = this.val;
|
||||
s = r >> (int)_logp;
|
||||
ret = d < s ? 1 : 0;
|
||||
if (ret == 0) this.val = d - s;
|
||||
this.rng = ret != 0 ? s : r - s;
|
||||
dec_normalize();
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal int dec_icdf(byte[] _icdf, uint _ftb)
|
||||
{
|
||||
uint r;
|
||||
uint d;
|
||||
uint s;
|
||||
uint t;
|
||||
int ret;
|
||||
s = this.rng;
|
||||
d = this.val;
|
||||
r = s >> (int)_ftb;
|
||||
ret = -1;
|
||||
do
|
||||
{
|
||||
t = s;
|
||||
s = r * _icdf[++ret];
|
||||
}
|
||||
while (d < s);
|
||||
this.val = d - s;
|
||||
this.rng = t - s;
|
||||
dec_normalize();
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal int dec_icdf(byte[] _icdf, int _icdf_offset, uint _ftb)
|
||||
{
|
||||
uint r;
|
||||
uint d;
|
||||
uint s;
|
||||
uint t;
|
||||
int ret;
|
||||
s = this.rng;
|
||||
d = this.val;
|
||||
r = s >> (int)_ftb;
|
||||
ret = _icdf_offset - 1;
|
||||
do
|
||||
{
|
||||
t = s;
|
||||
s = r * _icdf[++ret];
|
||||
}
|
||||
while (d < s);
|
||||
this.val = d - s;
|
||||
this.rng = t - s;
|
||||
dec_normalize();
|
||||
return ret - _icdf_offset;
|
||||
}
|
||||
|
||||
internal uint dec_uint(uint _ft)
|
||||
{
|
||||
uint ft;
|
||||
uint s;
|
||||
int ftb;
|
||||
/*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
|
||||
Inlines.OpusAssert(_ft > 1);
|
||||
_ft--;
|
||||
ftb = Inlines.EC_ILOG(_ft);
|
||||
if (ftb > EC_UINT_BITS)
|
||||
{
|
||||
uint t;
|
||||
ftb -= EC_UINT_BITS;
|
||||
ft = (uint)(_ft >> ftb) + 1;
|
||||
s = decode(ft);
|
||||
dec_update(s, s + 1, ft);
|
||||
t = (uint)s << ftb | dec_bits((uint)ftb);
|
||||
if (t <= _ft) return t;
|
||||
this.error = 1;
|
||||
return _ft;
|
||||
}
|
||||
else {
|
||||
_ft++;
|
||||
s = decode((uint)_ft);
|
||||
dec_update(s, s + 1, (uint)_ft);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
internal uint dec_bits(uint _bits)
|
||||
{
|
||||
uint window;
|
||||
int available;
|
||||
uint ret;
|
||||
window = this.end_window;
|
||||
available = this.nend_bits;
|
||||
if ((uint)available < _bits)
|
||||
{
|
||||
do
|
||||
{
|
||||
window |= (uint)read_byte_from_end() << available;
|
||||
available += EC_SYM_BITS;
|
||||
}
|
||||
while (available <= EC_WINDOW_SIZE - EC_SYM_BITS);
|
||||
}
|
||||
ret = (uint)window & (((uint)1 << (int)_bits) - 1U);
|
||||
window = window >> (int)_bits;
|
||||
available = available - (int)_bits;
|
||||
this.end_window = window;
|
||||
this.nend_bits = available;
|
||||
this.nbits_total = this.nbits_total + (int)_bits;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a symbol, with a carry bit.
|
||||
/// If there is a potential to propagate a carry over several symbols, they are
|
||||
/// buffered until it can be determined whether or not an actual carry will
|
||||
/// occur.
|
||||
/// If the counter for the buffered symbols overflows, then the stream becomes
|
||||
/// undecodable.
|
||||
/// This gives a theoretical limit of a few billion symbols in a single packet on
|
||||
/// 32-bit systems.
|
||||
/// The alternative is to truncate the range in order to force a carry, but
|
||||
/// requires similar carry tracking in the decoder, needlessly slowing it down.
|
||||
/// </summary>
|
||||
/// <param name="_c"></param>
|
||||
internal void enc_carry_out(int _c)
|
||||
{
|
||||
if (_c != EC_SYM_MAX)
|
||||
{
|
||||
/*No further carry propagation possible, flush buffer.*/
|
||||
int carry;
|
||||
carry = _c >> EC_SYM_BITS;
|
||||
|
||||
/*Don't output a byte on the first write.
|
||||
This compare should be taken care of by branch-prediction thereafter.*/
|
||||
if (this.rem >= 0)
|
||||
{
|
||||
this.error |= write_byte((uint)(this.rem + carry));
|
||||
}
|
||||
|
||||
if (this.ext > 0)
|
||||
{
|
||||
uint sym;
|
||||
sym = (EC_SYM_MAX + (uint)carry) & EC_SYM_MAX;
|
||||
do this.error |= write_byte(sym);
|
||||
while (--(this.ext) > 0);
|
||||
}
|
||||
|
||||
this.rem = (int)((uint)_c & EC_SYM_MAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ext++;
|
||||
}
|
||||
}
|
||||
|
||||
internal void enc_normalize()
|
||||
{
|
||||
/*If the range is too small, output some bits and rescale it.*/
|
||||
while (this.rng <= EC_CODE_BOT)
|
||||
{
|
||||
enc_carry_out((int)(this.val >> (int)EC_CODE_SHIFT));
|
||||
/*Move the next-to-high-order symbol into the high-order position.*/
|
||||
this.val = (this.val << EC_SYM_BITS) & (EC_CODE_TOP - 1);
|
||||
this.rng = this.rng << EC_SYM_BITS;
|
||||
this.nbits_total += EC_SYM_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
internal void enc_init(byte[] _buf, int buf_ptr, uint _size)
|
||||
{
|
||||
this.buf = _buf;
|
||||
this.buf_ptr = buf_ptr;
|
||||
this.end_offs = 0;
|
||||
this.end_window = 0;
|
||||
this.nend_bits = 0;
|
||||
/*This is the offset from which ec_tell() will subtract partial bits.*/
|
||||
this.nbits_total = EC_CODE_BITS + 1;
|
||||
this.offs = 0;
|
||||
this.rng = EC_CODE_TOP;
|
||||
this.rem = -1;
|
||||
this.val = 0;
|
||||
this.ext = 0;
|
||||
this.storage = _size;
|
||||
this.error = 0;
|
||||
}
|
||||
|
||||
internal void encode(uint _fl, uint _fh, uint _ft)
|
||||
{
|
||||
uint r;
|
||||
r = this.rng / _ft;
|
||||
if (_fl > 0)
|
||||
{
|
||||
this.val += this.rng - (r * (_ft - _fl));
|
||||
this.rng = (r * (_fh - _fl));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.rng -= (r * (_ft - _fh));
|
||||
}
|
||||
|
||||
enc_normalize();
|
||||
}
|
||||
|
||||
internal void encode_bin(uint _fl, uint _fh, uint _bits)
|
||||
{
|
||||
uint r;
|
||||
r = this.rng >> (int)_bits;
|
||||
if (_fl > 0)
|
||||
{
|
||||
this.val += this.rng - (r * ((1U << (int)_bits) - _fl));
|
||||
this.rng = (r * (_fh - _fl));
|
||||
}
|
||||
else this.rng -= (r * ((1U << (int)_bits) - _fh));
|
||||
enc_normalize();
|
||||
}
|
||||
|
||||
/*The probability of having a "one" is 1/(1<<_logp).*/
|
||||
internal void enc_bit_logp(int _val, uint _logp)
|
||||
{
|
||||
uint r;
|
||||
uint s;
|
||||
uint l;
|
||||
r = this.rng;
|
||||
l = this.val;
|
||||
s = r >> (int)_logp;
|
||||
r -= s;
|
||||
if (_val != 0)
|
||||
{
|
||||
this.val = l + r;
|
||||
}
|
||||
|
||||
this.rng = _val != 0 ? s : r;
|
||||
enc_normalize();
|
||||
}
|
||||
|
||||
internal void enc_icdf(int _s, byte[] _icdf, uint _ftb)
|
||||
{
|
||||
uint r;
|
||||
r = this.rng >> (int)_ftb;
|
||||
if (_s > 0)
|
||||
{
|
||||
this.val += this.rng - (r * _icdf[_s - 1]);
|
||||
this.rng = (r * (uint)(_icdf[_s - 1] - _icdf[_s]));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.rng -= (r * _icdf[_s]);
|
||||
}
|
||||
enc_normalize();
|
||||
}
|
||||
|
||||
internal void enc_icdf(int _s, byte[] _icdf, int icdf_ptr, uint _ftb)
|
||||
{
|
||||
uint r;
|
||||
r = this.rng >> (int)_ftb;
|
||||
if (_s > 0)
|
||||
{
|
||||
this.val += this.rng - (r * _icdf[icdf_ptr + _s - 1]);
|
||||
this.rng = (r * (uint)(_icdf[icdf_ptr + _s - 1] - _icdf[icdf_ptr + _s]));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.rng -= (r * _icdf[icdf_ptr + _s]);
|
||||
}
|
||||
enc_normalize();
|
||||
}
|
||||
|
||||
internal void enc_uint(uint _fl, uint _ft)
|
||||
{
|
||||
uint ft;
|
||||
uint fl;
|
||||
int ftb;
|
||||
/*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
|
||||
Inlines.OpusAssert(_ft > 1);
|
||||
_ft--;
|
||||
ftb = Inlines.EC_ILOG(_ft);
|
||||
if (ftb > EC_UINT_BITS)
|
||||
{
|
||||
ftb -= EC_UINT_BITS;
|
||||
ft = (_ft >> ftb) + 1;
|
||||
fl = (uint)(_fl >> ftb);
|
||||
encode(fl, fl + 1, ft);
|
||||
enc_bits(_fl & (((uint)1 << ftb) - 1U), (uint)ftb);
|
||||
}
|
||||
else encode(_fl, _fl + 1, _ft + 1);
|
||||
}
|
||||
|
||||
internal void enc_bits(uint _fl, uint _bits)
|
||||
{
|
||||
uint window;
|
||||
int used;
|
||||
window = this.end_window;
|
||||
used = this.nend_bits;
|
||||
Inlines.OpusAssert(_bits > 0);
|
||||
|
||||
if (used + _bits > EC_WINDOW_SIZE)
|
||||
{
|
||||
do
|
||||
{
|
||||
this.error |= write_byte_at_end((uint)window & EC_SYM_MAX);
|
||||
window >>= EC_SYM_BITS;
|
||||
used -= EC_SYM_BITS;
|
||||
}
|
||||
while (used >= EC_SYM_BITS);
|
||||
}
|
||||
|
||||
window |= (uint)_fl << used;
|
||||
used += (int)_bits;
|
||||
this.end_window = window;
|
||||
this.nend_bits = used;
|
||||
this.nbits_total += (int)_bits;
|
||||
}
|
||||
|
||||
internal void enc_patch_initial_bits(uint _val, uint _nbits)
|
||||
{
|
||||
int shift;
|
||||
uint mask;
|
||||
Inlines.OpusAssert(_nbits <= EC_SYM_BITS);
|
||||
shift = EC_SYM_BITS - (int)_nbits;
|
||||
mask = ((1U << (int)_nbits) - 1) << shift;
|
||||
|
||||
if (this.offs > 0)
|
||||
{
|
||||
/*The first byte has been finalized.*/
|
||||
this.buf[buf_ptr] = (byte)((this.buf[buf_ptr] & ~mask) | _val << shift);
|
||||
}
|
||||
else if (this.rem >= 0)
|
||||
{
|
||||
/*The first byte is still awaiting carry propagation.*/
|
||||
this.rem = (int)(((uint)this.rem & ~mask) | _val) << shift;
|
||||
}
|
||||
else if (this.rng <= (EC_CODE_TOP >> (int)_nbits))
|
||||
{
|
||||
/*The renormalization loop has never been run.*/
|
||||
this.val = (this.val & ~((uint)mask << (int)EC_CODE_SHIFT)) |
|
||||
(uint)_val << (int)(EC_CODE_SHIFT + shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*The encoder hasn't even encoded _nbits of data yet.*/
|
||||
this.error = -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal void enc_shrink(uint _size)
|
||||
{
|
||||
Inlines.OpusAssert(this.offs + this.end_offs <= _size);
|
||||
//(memmove(this.buf + _size - this.end_offs, this.buf + this.storage - this.end_offs, this.end_offs * sizeof(*(dst))))
|
||||
Arrays.MemMove<byte>(this.buf, buf_ptr + (int)_size - (int)this.end_offs, buf_ptr + (int)this.storage - (int)this.end_offs, (int)this.end_offs);
|
||||
this.storage = _size;
|
||||
}
|
||||
|
||||
internal uint range_bytes()
|
||||
{
|
||||
return this.offs;
|
||||
}
|
||||
|
||||
internal int get_error()
|
||||
{
|
||||
return this.error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of bits "used" by the encoded or decoded symbols so far.
|
||||
/// This same number can be computed in either the encoder or the decoder, and is
|
||||
/// suitable for making coding decisions.
|
||||
/// This will always be slightly larger than the exact value (e.g., all
|
||||
/// rounding error is in the positive direction).
|
||||
/// </summary>
|
||||
/// <returns>The number of bits.</returns>
|
||||
internal int tell()
|
||||
{
|
||||
int returnVal = this.nbits_total - Inlines.EC_ILOG(this.rng);
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
private static readonly uint[] correction = {35733, 38967, 42495, 46340, 50535, 55109, 60097, 65535};
|
||||
|
||||
/// <summary>
|
||||
/// This is a faster version of ec_tell_frac() that takes advantage
|
||||
/// of the low(1/8 bit) resolution to use just a linear function
|
||||
/// followed by a lookup to determine the exact transition thresholds.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal uint tell_frac()
|
||||
{
|
||||
int nbits;
|
||||
int r;
|
||||
int l;
|
||||
uint b;
|
||||
nbits = this.nbits_total << EntropyCoder.BITRES;
|
||||
l = Inlines.EC_ILOG(this.rng);
|
||||
r = (int)(this.rng >> (l - 16));
|
||||
b = (uint)((r >> 12) - 8);
|
||||
b += (r > correction[b] ? 1u : 0);
|
||||
l = (int)((l << 3) + b);
|
||||
return (uint)(nbits - l);
|
||||
}
|
||||
|
||||
internal void enc_done()
|
||||
{
|
||||
uint window;
|
||||
int used;
|
||||
uint msk;
|
||||
uint end;
|
||||
int l;
|
||||
/*We output the minimum number of bits that ensures that the symbols encoded
|
||||
thus far will be decoded correctly regardless of the bits that follow.*/
|
||||
l = EC_CODE_BITS - Inlines.EC_ILOG(this.rng);
|
||||
msk = (EC_CODE_TOP - 1) >> l;
|
||||
end = (this.val + msk) & ~msk;
|
||||
|
||||
if ((end | msk) >= this.val + this.rng)
|
||||
{
|
||||
l++;
|
||||
msk >>= 1;
|
||||
end = (this.val + msk) & ~msk;
|
||||
}
|
||||
|
||||
while (l > 0)
|
||||
{
|
||||
enc_carry_out((int)(end >> (int)EC_CODE_SHIFT));
|
||||
end = (end << EC_SYM_BITS) & (EC_CODE_TOP - 1);
|
||||
l -= EC_SYM_BITS;
|
||||
}
|
||||
|
||||
/*If we have a buffered byte flush it into the output buffer.*/
|
||||
if (this.rem >= 0 || this.ext > 0)
|
||||
{
|
||||
enc_carry_out(0);
|
||||
}
|
||||
|
||||
/*If we have buffered extra bits, flush them as well.*/
|
||||
window = this.end_window;
|
||||
used = this.nend_bits;
|
||||
|
||||
while (used >= EC_SYM_BITS)
|
||||
{
|
||||
this.error |= write_byte_at_end((uint)window & EC_SYM_MAX);
|
||||
window >>= EC_SYM_BITS;
|
||||
used -= EC_SYM_BITS;
|
||||
}
|
||||
|
||||
/*Clear any excess space and add any remaining extra bits to the last byte.*/
|
||||
if (this.error == 0)
|
||||
{
|
||||
Arrays.MemSetWithOffset<byte>(this.buf, 0, buf_ptr + (int)this.offs, (int)this.storage - (int)this.offs - (int)this.end_offs);
|
||||
if (used > 0)
|
||||
{
|
||||
/*If there's no range coder data at all, give up.*/
|
||||
if (this.end_offs >= this.storage)
|
||||
{
|
||||
this.error = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = -l;
|
||||
/*If we've busted, don't add too many extra bits to the last byte; it
|
||||
would corrupt the range coder data, and that's more important.*/
|
||||
if (this.offs + this.end_offs >= this.storage && l < used)
|
||||
{
|
||||
window = window & ((1U << l) - 1);
|
||||
this.error = -1;
|
||||
}
|
||||
|
||||
this.buf[buf_ptr + this.storage - this.end_offs - 1] |= (byte)window;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2714
Libraries/Concentus/CSharp/Concentus/Common/Inlines.cs
Normal file
2714
Libraries/Concentus/CSharp/Concentus/Common/Inlines.cs
Normal file
File diff suppressed because it is too large
Load Diff
1035
Libraries/Concentus/CSharp/Concentus/Common/Resampler.cs
Normal file
1035
Libraries/Concentus/CSharp/Concentus/Common/Resampler.cs
Normal file
File diff suppressed because it is too large
Load Diff
182
Libraries/Concentus/CSharp/Concentus/Concentus.csproj
Normal file
182
Libraries/Concentus/CSharp/Concentus/Concentus.csproj
Normal file
@@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{0E7FEE6A-15E5-4A4E-943C-80276003478C}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Concentus</RootNamespace>
|
||||
<AssemblyName>Concentus</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Celt\AutocorrelationUnsafe.cs" />
|
||||
<Compile Include="Celt\Bands.cs" />
|
||||
<Compile Include="Celt\CeltCommon.cs" />
|
||||
<Compile Include="Celt\CeltConstants.cs" />
|
||||
<Compile Include="Celt\CeltLPC.cs" />
|
||||
<Compile Include="Celt\CeltLPCUnsafe.cs" />
|
||||
<Compile Include="Celt\CeltPitchXCorr.cs" />
|
||||
<Compile Include="Celt\CeltPitchXCorrUnsafe.cs" />
|
||||
<Compile Include="Celt\CWRS.cs" />
|
||||
<Compile Include="Celt\Enums\Spread.cs" />
|
||||
<Compile Include="Celt\Kernels.cs" />
|
||||
<Compile Include="Celt\KernelsUnsafe.cs" />
|
||||
<Compile Include="Celt\KissFFT.cs" />
|
||||
<Compile Include="Celt\KissFFTUnsafe.cs" />
|
||||
<Compile Include="Celt\Laplace.cs" />
|
||||
<Compile Include="Celt\MDCT.cs" />
|
||||
<Compile Include="Celt\Pitch.cs" />
|
||||
<Compile Include="Celt\QuantizeBands.cs" />
|
||||
<Compile Include="Celt\Rate.cs" />
|
||||
<Compile Include="Celt\Structs\AnalysisInfo.cs" />
|
||||
<Compile Include="Celt\Structs\CELTDecoder.cs" />
|
||||
<Compile Include="Celt\Structs\CeltEncoder.cs" />
|
||||
<Compile Include="Celt\Structs\CELTMode.cs" />
|
||||
<Compile Include="Celt\Structs\FFTState.cs" />
|
||||
<Compile Include="Celt\Structs\MDCTLookup.cs" />
|
||||
<Compile Include="Celt\Structs\PulseCache.cs" />
|
||||
<Compile Include="Celt\Tables.cs" />
|
||||
<Compile Include="Celt\VQ.cs" />
|
||||
<Compile Include="Common\Autocorrelation.cs" />
|
||||
<Compile Include="Common\CPlusPlus\Arrays.cs" />
|
||||
<Compile Include="Common\CPlusPlus\BoxedValue.cs" />
|
||||
<Compile Include="Common\CPlusPlus\Pointer.cs" />
|
||||
<Compile Include="Common\EntropyCoder.cs" />
|
||||
<Compile Include="Common\Inlines.cs" />
|
||||
<Compile Include="Common\Resampler.cs" />
|
||||
<Compile Include="Opus\Analysis.cs" />
|
||||
<Compile Include="Opus\CodecHelpers.cs" />
|
||||
<Compile Include="Opus\Downmix.cs" />
|
||||
<Compile Include="Opus\Enums\OpusApplication.cs" />
|
||||
<Compile Include="Opus\Enums\OpusBandwidth.cs" />
|
||||
<Compile Include="Opus\Enums\OpusControl.cs" />
|
||||
<Compile Include="Opus\Enums\OpusError.cs" />
|
||||
<Compile Include="Opus\Enums\OpusFramesize.cs" />
|
||||
<Compile Include="Opus\Enums\OpusMode.cs" />
|
||||
<Compile Include="Opus\Enums\OpusSignal.cs" />
|
||||
<Compile Include="Opus\MultiLayerPerceptron.cs" />
|
||||
<Compile Include="Opus\OpusCompare.cs" />
|
||||
<Compile Include="Opus\OpusConstants.cs" />
|
||||
<Compile Include="Opus\OpusException.cs" />
|
||||
<Compile Include="Opus\OpusMultistream.cs" />
|
||||
<Compile Include="Opus\Structs\ChannelLayout.cs" />
|
||||
<Compile Include="Opus\Structs\MLP.cs" />
|
||||
<Compile Include="Opus\Structs\OpusDecoder.cs" />
|
||||
<Compile Include="Opus\Structs\OpusEncoder.cs" />
|
||||
<Compile Include="Opus\Structs\OpusMSDecoder.cs" />
|
||||
<Compile Include="Opus\Structs\OpusMSEncoder.cs" />
|
||||
<Compile Include="Opus\Structs\OpusPacketInfo.cs" />
|
||||
<Compile Include="Opus\Structs\OpusRepacketizer.cs" />
|
||||
<Compile Include="Opus\Structs\StereoWidthState.cs" />
|
||||
<Compile Include="Opus\Structs\TonalityAnalysisState.cs" />
|
||||
<Compile Include="Opus\Structs\VorbisLayout.cs" />
|
||||
<Compile Include="Opus\Tables.cs" />
|
||||
<Compile Include="Silk\ApplySineWindow.cs" />
|
||||
<Compile Include="Silk\BurgModified.cs" />
|
||||
<Compile Include="Silk\BurgModifiedUnsafe.cs" />
|
||||
<Compile Include="Silk\BWExpander.cs" />
|
||||
<Compile Include="Silk\CNG.cs" />
|
||||
<Compile Include="Silk\CodeSigns.cs" />
|
||||
<Compile Include="Silk\CorrelateMatrix.cs" />
|
||||
<Compile Include="Silk\DecodeAPI.cs" />
|
||||
<Compile Include="Silk\DecodeCore.cs" />
|
||||
<Compile Include="Silk\DecodeIndices.cs" />
|
||||
<Compile Include="Silk\DecodeParameters.cs" />
|
||||
<Compile Include="Silk\DecodePitch.cs" />
|
||||
<Compile Include="Silk\DecodePulses.cs" />
|
||||
<Compile Include="Silk\EncodeAPI.cs" />
|
||||
<Compile Include="Silk\EncodeIndices.cs" />
|
||||
<Compile Include="Silk\EncodePulses.cs" />
|
||||
<Compile Include="Silk\Enums\DecoderAPIFlag.cs" />
|
||||
<Compile Include="Silk\Enums\SilkError.cs" />
|
||||
<Compile Include="Silk\Filters.cs" />
|
||||
<Compile Include="Silk\FindLPC.cs" />
|
||||
<Compile Include="Silk\FindLTP.cs" />
|
||||
<Compile Include="Silk\FindPitchLags.cs" />
|
||||
<Compile Include="Silk\FindPredCoefs.cs" />
|
||||
<Compile Include="Silk\GainQuantization.cs" />
|
||||
<Compile Include="Silk\HPVariableCutoff.cs" />
|
||||
<Compile Include="Silk\K2A.cs" />
|
||||
<Compile Include="Silk\LinearAlgebra.cs" />
|
||||
<Compile Include="Silk\LPCInversePredGain.cs" />
|
||||
<Compile Include="Silk\LTPAnalysisFilter.cs" />
|
||||
<Compile Include="Silk\LTPScaleControl.cs" />
|
||||
<Compile Include="Silk\NLSF.cs" />
|
||||
<Compile Include="Silk\NoiseShapeAnalysis.cs" />
|
||||
<Compile Include="Silk\PitchAnalysisCore.cs" />
|
||||
<Compile Include="Silk\PLC.cs" />
|
||||
<Compile Include="Silk\ProcessGains.cs" />
|
||||
<Compile Include="Silk\QuantizeLTPGains.cs" />
|
||||
<Compile Include="Silk\RegularizeCorrelations.cs" />
|
||||
<Compile Include="Silk\Resampler.cs" />
|
||||
<Compile Include="Silk\ResidualEnergy.cs" />
|
||||
<Compile Include="Silk\Schur.cs" />
|
||||
<Compile Include="Silk\ShellCoder.cs" />
|
||||
<Compile Include="Silk\Sigmoid.cs" />
|
||||
<Compile Include="Silk\SilkConstants.cs" />
|
||||
<Compile Include="Silk\Sort.cs" />
|
||||
<Compile Include="Silk\Stereo.cs" />
|
||||
<Compile Include="Silk\Structs\CNGState.cs" />
|
||||
<Compile Include="Silk\Structs\DecControlState.cs" />
|
||||
<Compile Include="Silk\Structs\EncControlState.cs" />
|
||||
<Compile Include="Silk\Structs\NLSFCodebook.cs" />
|
||||
<Compile Include="Silk\Structs\PLCStruct.cs" />
|
||||
<Compile Include="Silk\Structs\SideInfoIndices.cs" />
|
||||
<Compile Include="Silk\Structs\SilkChannelDecoder.cs" />
|
||||
<Compile Include="Silk\Structs\SilkChannelEncoder.cs" />
|
||||
<Compile Include="Silk\Structs\SilkDecoder.cs" />
|
||||
<Compile Include="Silk\Structs\SilkDecoderControl.cs" />
|
||||
<Compile Include="Silk\Structs\SilkEncoder.cs" />
|
||||
<Compile Include="Silk\Structs\SilkEncoderControl.cs" />
|
||||
<Compile Include="Silk\Structs\SilkLPState.cs" />
|
||||
<Compile Include="Silk\Structs\SilkNSQState.cs" />
|
||||
<Compile Include="Silk\Structs\SilkPrefilterState.cs" />
|
||||
<Compile Include="Silk\Structs\SilkResamplerState.cs" />
|
||||
<Compile Include="Silk\Structs\SilkShapeState.cs" />
|
||||
<Compile Include="Silk\Structs\SilkVADState.cs" />
|
||||
<Compile Include="Silk\Structs\StereoDecodeState.cs" />
|
||||
<Compile Include="Silk\Structs\StereoEncodeState.cs" />
|
||||
<Compile Include="Silk\Structs\TOCStruct.cs" />
|
||||
<Compile Include="Silk\SumSqrShift.cs" />
|
||||
<Compile Include="Silk\Tables.cs" />
|
||||
<Compile Include="Silk\TuningParameters.cs" />
|
||||
<Compile Include="Silk\VoiceActivityDetection.cs" />
|
||||
<Compile Include="Silk\VQ_WMat_EC.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
590
Libraries/Concentus/CSharp/Concentus/Opus/Analysis.cs
Normal file
590
Libraries/Concentus/CSharp/Concentus/Opus/Analysis.cs
Normal file
@@ -0,0 +1,590 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Celt;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus;
|
||||
using Concentus.Structs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
internal static class Analysis
|
||||
{
|
||||
private const double M_PI = 3.141592653;
|
||||
private const float cA = 0.43157974f;
|
||||
private const float cB = 0.67848403f;
|
||||
private const float cC = 0.08595542f;
|
||||
private const float cE = ((float)M_PI / 2);
|
||||
|
||||
private const int NB_TONAL_SKIP_BANDS = 9;
|
||||
|
||||
internal static float fast_atan2f(float y, float x)
|
||||
{
|
||||
float x2, y2;
|
||||
/* Should avoid underflow on the values we'll get */
|
||||
if (Inlines.ABS16(x) + Inlines.ABS16(y) < 1e-9f)
|
||||
{
|
||||
x *= 1e12f;
|
||||
y *= 1e12f;
|
||||
}
|
||||
x2 = x * x;
|
||||
y2 = y * y;
|
||||
if (x2 < y2)
|
||||
{
|
||||
float den = (y2 + cB * x2) * (y2 + cC * x2);
|
||||
if (den != 0)
|
||||
return -x * y * (y2 + cA * x2) / den + (y < 0 ? -cE : cE);
|
||||
else
|
||||
return (y < 0 ? -cE : cE);
|
||||
}
|
||||
else {
|
||||
float den = (x2 + cB * y2) * (x2 + cC * y2);
|
||||
if (den != 0)
|
||||
return x * y * (x2 + cA * y2) / den + (y < 0 ? -cE : cE) - (x * y < 0 ? -cE : cE);
|
||||
else
|
||||
return (y < 0 ? -cE : cE) - (x * y < 0 ? -cE : cE);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void tonality_analysis_init(TonalityAnalysisState tonal)
|
||||
{
|
||||
tonal.Reset();
|
||||
}
|
||||
|
||||
internal static void tonality_get_info(TonalityAnalysisState tonal, AnalysisInfo info_out, int len)
|
||||
{
|
||||
int pos;
|
||||
int curr_lookahead;
|
||||
float psum;
|
||||
int i;
|
||||
|
||||
pos = tonal.read_pos;
|
||||
curr_lookahead = tonal.write_pos - tonal.read_pos;
|
||||
if (curr_lookahead < 0)
|
||||
curr_lookahead += OpusConstants.DETECT_SIZE;
|
||||
|
||||
if (len > 480 && pos != tonal.write_pos)
|
||||
{
|
||||
pos++;
|
||||
if (pos == OpusConstants.DETECT_SIZE)
|
||||
pos = 0;
|
||||
}
|
||||
if (pos == tonal.write_pos)
|
||||
pos--;
|
||||
if (pos < 0)
|
||||
pos = OpusConstants.DETECT_SIZE - 1;
|
||||
|
||||
info_out.Assign(tonal.info[pos]);
|
||||
tonal.read_subframe += len / 120;
|
||||
while (tonal.read_subframe >= 4)
|
||||
{
|
||||
tonal.read_subframe -= 4;
|
||||
tonal.read_pos++;
|
||||
}
|
||||
if (tonal.read_pos >= OpusConstants.DETECT_SIZE)
|
||||
tonal.read_pos -= OpusConstants.DETECT_SIZE;
|
||||
|
||||
/* Compensate for the delay in the features themselves.
|
||||
FIXME: Need a better estimate the 10 I just made up */
|
||||
curr_lookahead = Inlines.IMAX(curr_lookahead - 10, 0);
|
||||
|
||||
psum = 0;
|
||||
/* Summing the probability of transition patterns that involve music at
|
||||
time (DETECT_SIZE-curr_lookahead-1) */
|
||||
for (i = 0; i < OpusConstants.DETECT_SIZE - curr_lookahead; i++)
|
||||
psum += tonal.pmusic[i];
|
||||
for (; i < OpusConstants.DETECT_SIZE; i++)
|
||||
psum += tonal.pspeech[i];
|
||||
psum = psum * tonal.music_confidence + (1 - psum) * tonal.speech_confidence;
|
||||
/*printf("%f %f %f\n", psum, info_out.music_prob, info_out.tonality);*/
|
||||
|
||||
info_out.music_prob = psum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of signal being handled (either short or float) - changes based on which API is used</typeparam>
|
||||
/// <param name="tonal"></param>
|
||||
/// <param name="celt_mode"></param>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="len"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="c1"></param>
|
||||
/// <param name="c2"></param>
|
||||
/// <param name="C"></param>
|
||||
/// <param name="lsb_depth"></param>
|
||||
/// <param name="downmix"></param>
|
||||
internal static void tonality_analysis<T>(TonalityAnalysisState tonal, CeltMode celt_mode, T[] x, int x_ptr, int len, int offset, int c1, int c2, int C, int lsb_depth, Downmix.downmix_func<T> downmix)
|
||||
{
|
||||
int i, b;
|
||||
FFTState kfft;
|
||||
int[] input;
|
||||
int[] output;
|
||||
int N = 480, N2 = 240;
|
||||
float[] A = tonal.angle;
|
||||
float[] dA = tonal.d_angle;
|
||||
float[] d2A = tonal.d2_angle;
|
||||
float[] tonality;
|
||||
float[] noisiness;
|
||||
float[] band_tonality = new float[OpusConstants.NB_TBANDS];
|
||||
float[] logE = new float[OpusConstants.NB_TBANDS];
|
||||
float[] BFCC = new float[8];
|
||||
float[] features = new float[25];
|
||||
float frame_tonality;
|
||||
float max_frame_tonality;
|
||||
/*float tw_sum=0;*/
|
||||
float frame_noisiness;
|
||||
float pi4 = (float)(M_PI * M_PI * M_PI * M_PI);
|
||||
float slope = 0;
|
||||
float frame_stationarity;
|
||||
float relativeE;
|
||||
float[] frame_probs = new float[2];
|
||||
float alpha, alphaE, alphaE2;
|
||||
float frame_loudness;
|
||||
float bandwidth_mask;
|
||||
int bandwidth = 0;
|
||||
float maxE = 0;
|
||||
float noise_floor;
|
||||
int remaining;
|
||||
AnalysisInfo info; //[porting note] pointer
|
||||
|
||||
tonal.last_transition++;
|
||||
alpha = 1.0f / Inlines.IMIN(20, 1 + tonal.count);
|
||||
alphaE = 1.0f / Inlines.IMIN(50, 1 + tonal.count);
|
||||
alphaE2 = 1.0f / Inlines.IMIN(1000, 1 + tonal.count);
|
||||
|
||||
if (tonal.count < 4)
|
||||
tonal.music_prob = 0.5f;
|
||||
kfft = celt_mode.mdct.kfft[0];
|
||||
if (tonal.count == 0)
|
||||
tonal.mem_fill = 240;
|
||||
|
||||
downmix(x, x_ptr, tonal.inmem, tonal.mem_fill, Inlines.IMIN(len, OpusConstants.ANALYSIS_BUF_SIZE - tonal.mem_fill), offset, c1, c2, C);
|
||||
|
||||
if (tonal.mem_fill + len < OpusConstants.ANALYSIS_BUF_SIZE)
|
||||
{
|
||||
tonal.mem_fill += len;
|
||||
/* Don't have enough to update the analysis */
|
||||
return;
|
||||
}
|
||||
|
||||
info = tonal.info[tonal.write_pos++];
|
||||
if (tonal.write_pos >= OpusConstants.DETECT_SIZE)
|
||||
tonal.write_pos -= OpusConstants.DETECT_SIZE;
|
||||
|
||||
input = new int[960];
|
||||
output = new int[960];
|
||||
tonality = new float[240];
|
||||
noisiness = new float[240];
|
||||
for (i = 0; i < N2; i++)
|
||||
{
|
||||
float w = Tables.analysis_window[i];
|
||||
input[2 * i] = (int)(w * tonal.inmem[i]);
|
||||
input[2 * i + 1] = (int)(w * tonal.inmem[N2 + i]);
|
||||
input[(2 * (N - i - 1))] = (int)(w * tonal.inmem[N - i - 1]);
|
||||
input[(2 * (N - i - 1)) + 1] = (int)(w * tonal.inmem[N + N2 - i - 1]);
|
||||
}
|
||||
Arrays.MemMoveInt(tonal.inmem, OpusConstants.ANALYSIS_BUF_SIZE - 240, 0, 240);
|
||||
|
||||
remaining = len - (OpusConstants.ANALYSIS_BUF_SIZE - tonal.mem_fill);
|
||||
downmix(x, x_ptr, tonal.inmem, 240, remaining, offset + OpusConstants.ANALYSIS_BUF_SIZE - tonal.mem_fill, c1, c2, C);
|
||||
tonal.mem_fill = 240 + remaining;
|
||||
|
||||
KissFFT.opus_fft(kfft, input, output);
|
||||
|
||||
for (i = 1; i < N2; i++)
|
||||
{
|
||||
float X1r, X2r, X1i, X2i;
|
||||
float angle, d_angle, d2_angle;
|
||||
float angle2, d_angle2, d2_angle2;
|
||||
float mod1, mod2, avg_mod;
|
||||
X1r = (float)output[2 * i] + output[2 * (N - i)];
|
||||
X1i = (float)output[(2 * i) + 1] - output[2 * (N - i) + 1];
|
||||
X2r = (float)output[(2 * i) + 1] + output[2 * (N - i) + 1];
|
||||
X2i = (float)output[2 * (N - i)] - output[2 * i];
|
||||
|
||||
angle = (float)(.5f / M_PI) * fast_atan2f(X1i, X1r);
|
||||
d_angle = angle - A[i];
|
||||
d2_angle = d_angle - dA[i];
|
||||
|
||||
angle2 = (float)(.5f / M_PI) * fast_atan2f(X2i, X2r);
|
||||
d_angle2 = angle2 - angle;
|
||||
d2_angle2 = d_angle2 - d_angle;
|
||||
|
||||
mod1 = d2_angle - (float)Math.Floor(0.5f + d2_angle);
|
||||
noisiness[i] = Inlines.ABS16(mod1);
|
||||
mod1 *= mod1;
|
||||
mod1 *= mod1;
|
||||
|
||||
mod2 = d2_angle2 - (float)Math.Floor(0.5f + d2_angle2);
|
||||
noisiness[i] += Inlines.ABS16(mod2);
|
||||
mod2 *= mod2;
|
||||
mod2 *= mod2;
|
||||
|
||||
avg_mod = .25f * (d2A[i] + 2.0f * mod1 + mod2);
|
||||
tonality[i] = 1.0f / (1.0f + 40.0f * 16.0f * pi4 * avg_mod) - .015f;
|
||||
|
||||
A[i] = angle2;
|
||||
dA[i] = d_angle2;
|
||||
d2A[i] = mod2;
|
||||
}
|
||||
|
||||
frame_tonality = 0;
|
||||
max_frame_tonality = 0;
|
||||
/*tw_sum = 0;*/
|
||||
info.activity = 0;
|
||||
frame_noisiness = 0;
|
||||
frame_stationarity = 0;
|
||||
if (tonal.count == 0)
|
||||
{
|
||||
for (b = 0; b < OpusConstants.NB_TBANDS; b++)
|
||||
{
|
||||
tonal.lowE[b] = 1e10f;
|
||||
tonal.highE[b] = -1e10f;
|
||||
}
|
||||
}
|
||||
relativeE = 0;
|
||||
frame_loudness = 0;
|
||||
for (b = 0; b < OpusConstants.NB_TBANDS; b++)
|
||||
{
|
||||
float E = 0, tE = 0, nE = 0;
|
||||
float L1, L2;
|
||||
float stationarity;
|
||||
for (i = Tables.tbands[b]; i < Tables.tbands[b + 1]; i++)
|
||||
{
|
||||
float binE = output[2 * i] * (float)output[2 * i] + output[2 * (N - i)] * (float)output[2 * (N - i)]
|
||||
+ output[2 * i + 1] * (float)output[2 * i + 1] + output[2 * (N - i) + 1] * (float)output[2 * (N - i) + 1];
|
||||
/* FIXME: It's probably best to change the BFCC filter initial state instead */
|
||||
binE *= 5.55e-17f;
|
||||
E += binE;
|
||||
tE += binE * tonality[i];
|
||||
nE += binE * 2.0f * (.5f - noisiness[i]);
|
||||
}
|
||||
|
||||
tonal.E[tonal.E_count][b] = E;
|
||||
frame_noisiness += nE / (1e-15f + E);
|
||||
|
||||
frame_loudness += (float)Math.Sqrt(E + 1e-10f);
|
||||
logE[b] = (float)Math.Log(E + 1e-10f);
|
||||
tonal.lowE[b] = Inlines.MIN32(logE[b], tonal.lowE[b] + 0.01f);
|
||||
tonal.highE[b] = Inlines.MAX32(logE[b], tonal.highE[b] - 0.1f);
|
||||
if (tonal.highE[b] < tonal.lowE[b] + 1.0f)
|
||||
{
|
||||
tonal.highE[b] += 0.5f;
|
||||
tonal.lowE[b] -= 0.5f;
|
||||
}
|
||||
relativeE += (logE[b] - tonal.lowE[b]) / (1e-15f + tonal.highE[b] - tonal.lowE[b]);
|
||||
|
||||
L1 = L2 = 0;
|
||||
for (i = 0; i < OpusConstants.NB_FRAMES; i++)
|
||||
{
|
||||
L1 += (float)Math.Sqrt(tonal.E[i][b]);
|
||||
L2 += tonal.E[i][b];
|
||||
}
|
||||
|
||||
stationarity = Inlines.MIN16(0.99f, L1 / (float)Math.Sqrt(1e-15 + OpusConstants.NB_FRAMES * L2));
|
||||
stationarity *= stationarity;
|
||||
stationarity *= stationarity;
|
||||
frame_stationarity += stationarity;
|
||||
/*band_tonality[b] = tE/(1e-15+E)*/
|
||||
band_tonality[b] = Inlines.MAX16(tE / (1e-15f + E), stationarity * tonal.prev_band_tonality[b]);
|
||||
frame_tonality += band_tonality[b];
|
||||
if (b >= OpusConstants.NB_TBANDS - OpusConstants.NB_TONAL_SKIP_BANDS)
|
||||
frame_tonality -= band_tonality[b - OpusConstants.NB_TBANDS + OpusConstants.NB_TONAL_SKIP_BANDS];
|
||||
max_frame_tonality = Inlines.MAX16(max_frame_tonality, (1.0f + .03f * (b - OpusConstants.NB_TBANDS)) * frame_tonality);
|
||||
slope += band_tonality[b] * (b - 8);
|
||||
tonal.prev_band_tonality[b] = band_tonality[b];
|
||||
}
|
||||
|
||||
bandwidth_mask = 0;
|
||||
bandwidth = 0;
|
||||
maxE = 0;
|
||||
noise_floor = 5.7e-4f / (1 << (Inlines.IMAX(0, lsb_depth - 8)));
|
||||
noise_floor *= 1 << (15 + CeltConstants.SIG_SHIFT);
|
||||
noise_floor *= noise_floor;
|
||||
for (b = 0; b < OpusConstants.NB_TOT_BANDS; b++)
|
||||
{
|
||||
float E = 0;
|
||||
int band_start, band_end;
|
||||
/* Keep a margin of 300 Hz for aliasing */
|
||||
band_start = Tables.extra_bands[b];
|
||||
band_end = Tables.extra_bands[b + 1];
|
||||
for (i = band_start; i < band_end; i++)
|
||||
{
|
||||
float binE = output[2 * i] * (float)output[2 * i] + output[2 * (N - i)] * (float)output[2 * (N - i)]
|
||||
+ output[2 * i + 1] * (float)output[2 * i + 1] + output[2 * (N - i) + 1] * (float)output[2 * (N - i) + 1];
|
||||
E += binE;
|
||||
}
|
||||
maxE = Inlines.MAX32(maxE, E);
|
||||
tonal.meanE[b] = Inlines.MAX32((1 - alphaE2) * tonal.meanE[b], E);
|
||||
E = Inlines.MAX32(E, tonal.meanE[b]);
|
||||
/* Use a simple follower with 13 dB/Bark slope for spreading function */
|
||||
bandwidth_mask = Inlines.MAX32(.05f * bandwidth_mask, E);
|
||||
/* Consider the band "active" only if all these conditions are met:
|
||||
1) less than 10 dB below the simple follower
|
||||
2) less than 90 dB below the peak band (maximal masking possible considering
|
||||
both the ATH and the loudness-dependent slope of the spreading function)
|
||||
3) above the PCM quantization noise floor
|
||||
*/
|
||||
if (E > .1 * bandwidth_mask && E * 1e9f > maxE && E > noise_floor * (band_end - band_start))
|
||||
bandwidth = b;
|
||||
}
|
||||
if (tonal.count <= 2)
|
||||
bandwidth = 20;
|
||||
frame_loudness = 20 * (float)Math.Log10(frame_loudness);
|
||||
tonal.Etracker = Inlines.MAX32(tonal.Etracker - .03f, frame_loudness);
|
||||
tonal.lowECount *= (1 - alphaE);
|
||||
if (frame_loudness < tonal.Etracker - 30)
|
||||
tonal.lowECount += alphaE;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
float sum = 0;
|
||||
for (b = 0; b < 16; b++)
|
||||
sum += Tables.dct_table[i * 16 + b] * logE[b];
|
||||
BFCC[i] = sum;
|
||||
}
|
||||
|
||||
frame_stationarity /= OpusConstants.NB_TBANDS;
|
||||
relativeE /= OpusConstants.NB_TBANDS;
|
||||
if (tonal.count < 10)
|
||||
relativeE = 0.5f;
|
||||
frame_noisiness /= OpusConstants.NB_TBANDS;
|
||||
info.activity = frame_noisiness + (1 - frame_noisiness) * relativeE;
|
||||
frame_tonality = (max_frame_tonality / (OpusConstants.NB_TBANDS - OpusConstants.NB_TONAL_SKIP_BANDS));
|
||||
frame_tonality = Inlines.MAX16(frame_tonality, tonal.prev_tonality * .8f);
|
||||
tonal.prev_tonality = frame_tonality;
|
||||
|
||||
slope /= 8 * 8;
|
||||
info.tonality_slope = slope;
|
||||
|
||||
tonal.E_count = (tonal.E_count + 1) % OpusConstants.NB_FRAMES;
|
||||
tonal.count++;
|
||||
info.tonality = frame_tonality;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
features[i] = -0.12299f * (BFCC[i] + tonal.mem[i + 24]) + 0.49195f * (tonal.mem[i] + tonal.mem[i + 16]) + 0.69693f * tonal.mem[i + 8] - 1.4349f * tonal.cmean[i];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
tonal.cmean[i] = (1 - alpha) * tonal.cmean[i] + alpha * BFCC[i];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
features[4 + i] = 0.63246f * (BFCC[i] - tonal.mem[i + 24]) + 0.31623f * (tonal.mem[i] - tonal.mem[i + 16]);
|
||||
for (i = 0; i < 3; i++)
|
||||
features[8 + i] = 0.53452f * (BFCC[i] + tonal.mem[i + 24]) - 0.26726f * (tonal.mem[i] + tonal.mem[i + 16]) - 0.53452f * tonal.mem[i + 8];
|
||||
|
||||
if (tonal.count > 5)
|
||||
{
|
||||
for (i = 0; i < 9; i++)
|
||||
tonal.std[i] = (1 - alpha) * tonal.std[i] + alpha * features[i] * features[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
tonal.mem[i + 24] = tonal.mem[i + 16];
|
||||
tonal.mem[i + 16] = tonal.mem[i + 8];
|
||||
tonal.mem[i + 8] = tonal.mem[i];
|
||||
tonal.mem[i] = BFCC[i];
|
||||
}
|
||||
for (i = 0; i < 9; i++)
|
||||
features[11 + i] = (float)Math.Sqrt(tonal.std[i]);
|
||||
features[20] = info.tonality;
|
||||
features[21] = info.activity;
|
||||
features[22] = frame_stationarity;
|
||||
features[23] = info.tonality_slope;
|
||||
features[24] = tonal.lowECount;
|
||||
|
||||
mlp.mlp_process(Tables.net, features, frame_probs);
|
||||
frame_probs[0] = .5f * (frame_probs[0] + 1);
|
||||
/* Curve fitting between the MLP probability and the actual probability */
|
||||
frame_probs[0] = .01f + 1.21f * frame_probs[0] * frame_probs[0] - .23f * (float)Math.Pow(frame_probs[0], 10);
|
||||
/* Probability of active audio (as opposed to silence) */
|
||||
frame_probs[1] = .5f * frame_probs[1] + .5f;
|
||||
/* Consider that silence has a 50-50 probability. */
|
||||
frame_probs[0] = frame_probs[1] * frame_probs[0] + (1 - frame_probs[1]) * .5f;
|
||||
|
||||
/*printf("%f %f ", frame_probs[0], frame_probs[1]);*/
|
||||
{
|
||||
/* Probability of state transition */
|
||||
float tau;
|
||||
/* Represents independence of the MLP probabilities, where
|
||||
beta=1 means fully independent. */
|
||||
float beta;
|
||||
/* Denormalized probability of speech (p0) and music (p1) after update */
|
||||
float p0, p1;
|
||||
/* Probabilities for "all speech" and "all music" */
|
||||
float s0, m0;
|
||||
/* Probability sum for renormalisation */
|
||||
float psum;
|
||||
/* Instantaneous probability of speech and music, with beta pre-applied. */
|
||||
float speech0;
|
||||
float music0;
|
||||
|
||||
/* One transition every 3 minutes of active audio */
|
||||
tau = .00005f * frame_probs[1];
|
||||
beta = .05f;
|
||||
//if (1)
|
||||
{
|
||||
/* Adapt beta based on how "unexpected" the new prob is */
|
||||
float p, q;
|
||||
p = Inlines.MAX16(.05f, Inlines.MIN16(.95f, frame_probs[0]));
|
||||
q = Inlines.MAX16(.05f, Inlines.MIN16(.95f, tonal.music_prob));
|
||||
beta = .01f + .05f * Inlines.ABS16(p - q) / (p * (1 - q) + q * (1 - p));
|
||||
}
|
||||
/* p0 and p1 are the probabilities of speech and music at this frame
|
||||
using only information from previous frame and applying the
|
||||
state transition model */
|
||||
p0 = (1 - tonal.music_prob) * (1 - tau) + tonal.music_prob * tau;
|
||||
p1 = tonal.music_prob * (1 - tau) + (1 - tonal.music_prob) * tau;
|
||||
/* We apply the current probability with exponent beta to work around
|
||||
the fact that the probability estimates aren't independent. */
|
||||
p0 *= (float)Math.Pow(1 - frame_probs[0], beta);
|
||||
p1 *= (float)Math.Pow(frame_probs[0], beta);
|
||||
/* Normalise the probabilities to get the Marokv probability of music. */
|
||||
tonal.music_prob = p1 / (p0 + p1);
|
||||
info.music_prob = tonal.music_prob;
|
||||
|
||||
/* This chunk of code deals with delayed decision. */
|
||||
psum = 1e-20f;
|
||||
/* Instantaneous probability of speech and music, with beta pre-applied. */
|
||||
speech0 = (float)Math.Pow(1 - frame_probs[0], beta);
|
||||
music0 = (float)Math.Pow(frame_probs[0], beta);
|
||||
if (tonal.count == 1)
|
||||
{
|
||||
tonal.pspeech[0] = 0.5f;
|
||||
tonal.pmusic[0] = 0.5f;
|
||||
}
|
||||
/* Updated probability of having only speech (s0) or only music (m0),
|
||||
before considering the new observation. */
|
||||
s0 = tonal.pspeech[0] + tonal.pspeech[1];
|
||||
m0 = tonal.pmusic[0] + tonal.pmusic[1];
|
||||
/* Updates s0 and m0 with instantaneous probability. */
|
||||
tonal.pspeech[0] = s0 * (1 - tau) * speech0;
|
||||
tonal.pmusic[0] = m0 * (1 - tau) * music0;
|
||||
/* Propagate the transition probabilities */
|
||||
for (i = 1; i < OpusConstants.DETECT_SIZE - 1; i++)
|
||||
{
|
||||
tonal.pspeech[i] = tonal.pspeech[i + 1] * speech0;
|
||||
tonal.pmusic[i] = tonal.pmusic[i + 1] * music0;
|
||||
}
|
||||
/* Probability that the latest frame is speech, when all the previous ones were music. */
|
||||
tonal.pspeech[OpusConstants.DETECT_SIZE - 1] = m0 * tau * speech0;
|
||||
/* Probability that the latest frame is music, when all the previous ones were speech. */
|
||||
tonal.pmusic[OpusConstants.DETECT_SIZE - 1] = s0 * tau * music0;
|
||||
|
||||
/* Renormalise probabilities to 1 */
|
||||
for (i = 0; i < OpusConstants.DETECT_SIZE; i++)
|
||||
psum += tonal.pspeech[i] + tonal.pmusic[i];
|
||||
psum = 1.0f / psum;
|
||||
for (i = 0; i < OpusConstants.DETECT_SIZE; i++)
|
||||
{
|
||||
tonal.pspeech[i] *= psum;
|
||||
tonal.pmusic[i] *= psum;
|
||||
}
|
||||
psum = tonal.pmusic[0];
|
||||
for (i = 1; i < OpusConstants.DETECT_SIZE; i++)
|
||||
psum += tonal.pspeech[i];
|
||||
|
||||
/* Estimate our confidence in the speech/music decisions */
|
||||
if (frame_probs[1] > .75)
|
||||
{
|
||||
if (tonal.music_prob > .9)
|
||||
{
|
||||
float adapt;
|
||||
adapt = 1.0f / (++tonal.music_confidence_count);
|
||||
tonal.music_confidence_count = Inlines.IMIN(tonal.music_confidence_count, 500);
|
||||
tonal.music_confidence += adapt * Inlines.MAX16(-.2f, frame_probs[0] - tonal.music_confidence);
|
||||
}
|
||||
if (tonal.music_prob < .1)
|
||||
{
|
||||
float adapt;
|
||||
adapt = 1.0f / (++tonal.speech_confidence_count);
|
||||
tonal.speech_confidence_count = Inlines.IMIN(tonal.speech_confidence_count, 500);
|
||||
tonal.speech_confidence += adapt * Inlines.MIN16(.2f, frame_probs[0] - tonal.speech_confidence);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tonal.music_confidence_count == 0)
|
||||
tonal.music_confidence = .9f;
|
||||
if (tonal.speech_confidence_count == 0)
|
||||
tonal.speech_confidence = .1f;
|
||||
}
|
||||
}
|
||||
if (tonal.last_music != ((tonal.music_prob > .5f) ? 1 : 0))
|
||||
tonal.last_transition = 0;
|
||||
tonal.last_music = (tonal.music_prob > .5f) ? 1 : 0;
|
||||
|
||||
info.bandwidth = bandwidth;
|
||||
info.noisiness = frame_noisiness;
|
||||
info.valid = 1;
|
||||
}
|
||||
|
||||
internal static void run_analysis<T>(TonalityAnalysisState analysis, CeltMode celt_mode, T[] analysis_pcm, int analysis_pcm_ptr,
|
||||
int analysis_frame_size, int frame_size, int c1, int c2, int C, int Fs,
|
||||
int lsb_depth, Downmix.downmix_func<T> downmix, AnalysisInfo analysis_info)
|
||||
{
|
||||
int offset;
|
||||
int pcm_len;
|
||||
|
||||
if (analysis_pcm != null)
|
||||
{
|
||||
/* Avoid overflow/wrap-around of the analysis buffer */
|
||||
analysis_frame_size = Inlines.IMIN((OpusConstants.DETECT_SIZE - 5) * Fs / 100, analysis_frame_size);
|
||||
|
||||
pcm_len = analysis_frame_size - analysis.analysis_offset;
|
||||
offset = analysis.analysis_offset;
|
||||
do
|
||||
{
|
||||
tonality_analysis(analysis, celt_mode, analysis_pcm, analysis_pcm_ptr, Inlines.IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
|
||||
offset += 480;
|
||||
pcm_len -= 480;
|
||||
} while (pcm_len > 0);
|
||||
analysis.analysis_offset = analysis_frame_size;
|
||||
|
||||
analysis.analysis_offset -= frame_size;
|
||||
}
|
||||
|
||||
analysis_info.valid = 0;
|
||||
tonality_get_info(analysis, analysis_info, frame_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
712
Libraries/Concentus/CSharp/Concentus/Opus/CodecHelpers.cs
Normal file
712
Libraries/Concentus/CSharp/Concentus/Opus/CodecHelpers.cs
Normal file
@@ -0,0 +1,712 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Celt;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus;
|
||||
using Concentus.Enums;
|
||||
using Concentus.Silk;
|
||||
using Concentus.Silk.Structs;
|
||||
using Concentus.Structs;
|
||||
using System;
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
public static class CodecHelpers
|
||||
{
|
||||
internal static byte gen_toc(OpusMode mode, int framerate, OpusBandwidth bandwidth, int channels)
|
||||
{
|
||||
int period;
|
||||
byte toc;
|
||||
period = 0;
|
||||
while (framerate < 400)
|
||||
{
|
||||
framerate <<= 1;
|
||||
period++;
|
||||
}
|
||||
if (mode == OpusMode.MODE_SILK_ONLY)
|
||||
{
|
||||
toc = (byte)((bandwidth - OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) << 5);
|
||||
toc |= (byte)((period - 2) << 3);
|
||||
}
|
||||
else if (mode == OpusMode.MODE_CELT_ONLY)
|
||||
{
|
||||
int tmp = bandwidth - OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND;
|
||||
if (tmp < 0)
|
||||
tmp = 0;
|
||||
toc = 0x80;
|
||||
toc |= (byte)(tmp << 5);
|
||||
toc |= (byte)(period << 3);
|
||||
}
|
||||
else /* Hybrid */
|
||||
{
|
||||
toc = 0x60;
|
||||
toc |= (byte)((bandwidth - OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) << 4);
|
||||
toc |= (byte)((period - 2) << 3);
|
||||
}
|
||||
toc |= (byte)((channels == 2 ? 1 : 0) << 2);
|
||||
return toc;
|
||||
}
|
||||
|
||||
internal static void hp_cutoff(short[] input, int input_ptr, int cutoff_Hz, short[] output, int output_ptr, int[] hp_mem, int len, int channels, int Fs)
|
||||
{
|
||||
int[] B_Q28 = new int[3];
|
||||
int[] A_Q28 = new int[2];
|
||||
int Fc_Q19, r_Q28, r_Q22;
|
||||
|
||||
Inlines.OpusAssert(cutoff_Hz <= int.MaxValue / ((int)((1.5f * 3.14159f / 1000) * ((long)1 << (19)) + 0.5))/*Inlines.SILK_CONST(1.5f * 3.14159f / 1000, 19)*/);
|
||||
Fc_Q19 = Inlines.silk_DIV32_16(Inlines.silk_SMULBB(((int)((1.5f * 3.14159f / 1000) * ((long)1 << (19)) + 0.5))/*Inlines.SILK_CONST(1.5f * 3.14159f / 1000, 19)*/, cutoff_Hz), Fs / 1000);
|
||||
Inlines.OpusAssert(Fc_Q19 > 0 && Fc_Q19 < 32768);
|
||||
|
||||
r_Q28 = ((int)((1.0f) * ((long)1 << (28)) + 0.5))/*Inlines.SILK_CONST(1.0f, 28)*/ - Inlines.silk_MUL(((int)((0.92f) * ((long)1 << (9)) + 0.5))/*Inlines.SILK_CONST(0.92f, 9)*/, Fc_Q19);
|
||||
|
||||
/* b = r * [ 1; -2; 1 ]; */
|
||||
/* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */
|
||||
B_Q28[0] = r_Q28;
|
||||
B_Q28[1] = Inlines.silk_LSHIFT(-r_Q28, 1);
|
||||
B_Q28[2] = r_Q28;
|
||||
|
||||
/* -r * ( 2 - Fc * Fc ); */
|
||||
r_Q22 = Inlines.silk_RSHIFT(r_Q28, 6);
|
||||
A_Q28[0] = Inlines.silk_SMULWW(r_Q22, Inlines.silk_SMULWW(Fc_Q19, Fc_Q19) - ((int)((2.0f) * ((long)1 << (22)) + 0.5))/*Inlines.SILK_CONST(2.0f, 22)*/);
|
||||
A_Q28[1] = Inlines.silk_SMULWW(r_Q22, r_Q22);
|
||||
|
||||
Filters.silk_biquad_alt(input, input_ptr, B_Q28, A_Q28, hp_mem, 0, output, output_ptr, len, channels);
|
||||
if (channels == 2)
|
||||
{
|
||||
Filters.silk_biquad_alt(input, input_ptr + 1, B_Q28, A_Q28, hp_mem, 2, output, output_ptr + 1, len, channels);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void dc_reject(short[] input, int input_ptr, int cutoff_Hz, short[] output, int output_ptr, int[] hp_mem, int len, int channels, int Fs)
|
||||
{
|
||||
int c, i;
|
||||
int shift;
|
||||
|
||||
/* Approximates -round(log2(4.*cutoff_Hz/Fs)) */
|
||||
shift = Inlines.celt_ilog2(Fs / (cutoff_Hz * 3));
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
int x, tmp, y;
|
||||
x = Inlines.SHL32(Inlines.EXTEND32(input[channels * i + c + input_ptr]), 15);
|
||||
/* First stage */
|
||||
tmp = x - hp_mem[2 * c];
|
||||
hp_mem[2 * c] = hp_mem[2 * c] + Inlines.PSHR32(x - hp_mem[2 * c], shift);
|
||||
/* Second stage */
|
||||
y = tmp - hp_mem[2 * c + 1];
|
||||
hp_mem[2 * c + 1] = hp_mem[2 * c + 1] + Inlines.PSHR32(tmp - hp_mem[2 * c + 1], shift);
|
||||
output[channels * i + c + output_ptr] = Inlines.EXTRACT16(Inlines.SATURATE(Inlines.PSHR32(y, 15), 32767));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void stereo_fade(
|
||||
short[] pcm_buf,
|
||||
int g1,
|
||||
int g2,
|
||||
int overlap48,
|
||||
int frame_size,
|
||||
int channels,
|
||||
int[] window,
|
||||
int Fs)
|
||||
{
|
||||
int i;
|
||||
int overlap;
|
||||
int inc;
|
||||
inc = 48000 / Fs;
|
||||
overlap = overlap48 / inc;
|
||||
g1 = CeltConstants.Q15ONE - g1;
|
||||
g2 = CeltConstants.Q15ONE - g2;
|
||||
for (i = 0; i < overlap; i++)
|
||||
{
|
||||
int diff;
|
||||
int g, w;
|
||||
w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
|
||||
g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2),
|
||||
CeltConstants.Q15ONE - w, g1), 15);
|
||||
diff = Inlines.EXTRACT16(Inlines.HALF32((int)pcm_buf[i * channels] - (int)pcm_buf[i * channels + 1]));
|
||||
diff = Inlines.MULT16_16_Q15(g, diff);
|
||||
pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - diff);
|
||||
pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + diff);
|
||||
}
|
||||
for (; i < frame_size; i++)
|
||||
{
|
||||
int diff;
|
||||
diff = Inlines.EXTRACT16(Inlines.HALF32((int)pcm_buf[i * channels] - (int)pcm_buf[i * channels + 1]));
|
||||
diff = Inlines.MULT16_16_Q15(g2, diff);
|
||||
pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - diff);
|
||||
pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + diff);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void gain_fade(short[] buffer, int buf_ptr, int g1, int g2,
|
||||
int overlap48, int frame_size, int channels, int[] window, int Fs)
|
||||
{
|
||||
int i;
|
||||
int inc;
|
||||
int overlap;
|
||||
int c;
|
||||
inc = 48000 / Fs;
|
||||
overlap = overlap48 / inc;
|
||||
if (channels == 1)
|
||||
{
|
||||
for (i = 0; i < overlap; i++)
|
||||
{
|
||||
int g, w;
|
||||
w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
|
||||
g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2),
|
||||
CeltConstants.Q15ONE - w, g1), 15);
|
||||
buffer[buf_ptr + i] = (short)Inlines.MULT16_16_Q15(g, buffer[buf_ptr + i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < overlap; i++)
|
||||
{
|
||||
int g, w;
|
||||
w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
|
||||
g = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, g2),
|
||||
CeltConstants.Q15ONE - w, g1), 15);
|
||||
buffer[buf_ptr + i * 2] = (short)Inlines.MULT16_16_Q15(g, buffer[buf_ptr + i * 2]);
|
||||
buffer[buf_ptr + i * 2 + 1] = (short)Inlines.MULT16_16_Q15(g, buffer[buf_ptr + i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
c = 0; do
|
||||
{
|
||||
for (i = overlap; i < frame_size; i++)
|
||||
{
|
||||
buffer[buf_ptr + i * channels + c] = (short)Inlines.MULT16_16_Q15(g2, buffer[buf_ptr + i * channels + c]);
|
||||
}
|
||||
}
|
||||
while (++c < channels);
|
||||
}
|
||||
|
||||
/* Don't use more than 60 ms for the frame size analysis */
|
||||
private const int MAX_DYNAMIC_FRAMESIZE = 24;
|
||||
|
||||
/* Estimates how much the bitrate will be boosted based on the sub-frame energy */
|
||||
internal static float transient_boost(float[] E, int E_ptr, float[] E_1, int LM, int maxM)
|
||||
{
|
||||
int i;
|
||||
int M;
|
||||
float sumE = 0, sumE_1 = 0;
|
||||
float metric;
|
||||
|
||||
M = Inlines.IMIN(maxM, (1 << LM) + 1);
|
||||
for (i = E_ptr; i < M + E_ptr; i++)
|
||||
{
|
||||
sumE += E[i];
|
||||
sumE_1 += E_1[i];
|
||||
}
|
||||
metric = sumE * sumE_1 / (M * M);
|
||||
/*if (LM==3)
|
||||
printf("%f\n", metric);*/
|
||||
/*return metric>10 ? 1 : 0;*/
|
||||
/*return Inlines.MAX16(0,1-exp(-.25*(metric-2.)));*/
|
||||
return Inlines.MIN16(1, (float)Math.Sqrt(Inlines.MAX16(0, .05f * (metric - 2))));
|
||||
}
|
||||
|
||||
/* Viterbi decoding trying to find the best frame size combination using look-ahead
|
||||
|
||||
State numbering:
|
||||
0: unused
|
||||
1: 2.5 ms
|
||||
2: 5 ms (#1)
|
||||
3: 5 ms (#2)
|
||||
4: 10 ms (#1)
|
||||
5: 10 ms (#2)
|
||||
6: 10 ms (#3)
|
||||
7: 10 ms (#4)
|
||||
8: 20 ms (#1)
|
||||
9: 20 ms (#2)
|
||||
10: 20 ms (#3)
|
||||
11: 20 ms (#4)
|
||||
12: 20 ms (#5)
|
||||
13: 20 ms (#6)
|
||||
14: 20 ms (#7)
|
||||
15: 20 ms (#8)
|
||||
*/
|
||||
internal static int transient_viterbi(float[] E, float[] E_1, int N, int frame_cost, int rate)
|
||||
{
|
||||
int i;
|
||||
float[][] cost = Arrays.InitTwoDimensionalArray<float>(MAX_DYNAMIC_FRAMESIZE, 16);
|
||||
int[][] states = Arrays.InitTwoDimensionalArray<int>(MAX_DYNAMIC_FRAMESIZE, 16);
|
||||
float best_cost;
|
||||
int best_state;
|
||||
float factor;
|
||||
/* Take into account that we damp VBR in the 32 kb/s to 64 kb/s range. */
|
||||
if (rate < 80)
|
||||
factor = 0;
|
||||
else if (rate > 160)
|
||||
factor = 1;
|
||||
else
|
||||
factor = (rate - 80.0f) / 80.0f;
|
||||
/* Makes variable framesize less aggressive at lower bitrates, but I can't
|
||||
find any valid theoretical justification for this (other than it seems
|
||||
to help) */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
/* Impossible state */
|
||||
states[0][i] = -1;
|
||||
cost[0][i] = 1e10f;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
cost[0][1 << i] = (frame_cost + rate * (1 << i)) * (1 + factor * transient_boost(E, 0, E_1, i, N + 1));
|
||||
states[0][1 << i] = i;
|
||||
}
|
||||
for (i = 1; i < N; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
/* Follow continuations */
|
||||
for (j = 2; j < 16; j++)
|
||||
{
|
||||
cost[i][j] = cost[i - 1][j - 1];
|
||||
states[i][j] = j - 1;
|
||||
}
|
||||
|
||||
/* New frames */
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
int k;
|
||||
float min_cost;
|
||||
float curr_cost;
|
||||
states[i][1 << j] = 1;
|
||||
min_cost = cost[i - 1][1];
|
||||
for (k = 1; k < 4; k++)
|
||||
{
|
||||
float tmp = cost[i - 1][(1 << (k + 1)) - 1];
|
||||
if (tmp < min_cost)
|
||||
{
|
||||
states[i][1 << j] = (1 << (k + 1)) - 1;
|
||||
min_cost = tmp;
|
||||
}
|
||||
}
|
||||
curr_cost = (frame_cost + rate * (1 << j)) * (1 + factor * transient_boost(E, i, E_1, j, N - i + 1));
|
||||
cost[i][1 << j] = min_cost;
|
||||
/* If part of the frame is outside the analysis window, only count part of the cost */
|
||||
if (N - i < (1 << j))
|
||||
cost[i][1 << j] += curr_cost * (float)(N - i) / (1 << j);
|
||||
else
|
||||
cost[i][1 << j] += curr_cost;
|
||||
}
|
||||
}
|
||||
|
||||
best_state = 1;
|
||||
best_cost = cost[N - 1][1];
|
||||
/* Find best end state (doesn't force a frame to end at N-1) */
|
||||
for (i = 2; i < 16; i++)
|
||||
{
|
||||
if (cost[N - 1][i] < best_cost)
|
||||
{
|
||||
best_cost = cost[N - 1][i];
|
||||
best_state = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Follow transitions back */
|
||||
for (i = N - 1; i >= 0; i--)
|
||||
{
|
||||
/*printf("%d ", best_state);*/
|
||||
best_state = states[i][best_state];
|
||||
}
|
||||
/*printf("%d\n", best_state);*/
|
||||
return best_state;
|
||||
}
|
||||
|
||||
internal static int optimize_framesize<T>(T[] x, int x_ptr, int len, int C, int Fs,
|
||||
int bitrate, int tonality, float[] mem, int buffering,
|
||||
Downmix.downmix_func<T> downmix)
|
||||
{
|
||||
int N;
|
||||
int i;
|
||||
float[] e = new float[MAX_DYNAMIC_FRAMESIZE + 4];
|
||||
float[] e_1 = new float[MAX_DYNAMIC_FRAMESIZE + 3];
|
||||
int memx;
|
||||
int bestLM = 0;
|
||||
int subframe;
|
||||
int pos;
|
||||
int offset;
|
||||
int[] sub;
|
||||
|
||||
subframe = Fs / 400;
|
||||
sub = new int[subframe];
|
||||
e[0] = mem[0];
|
||||
e_1[0] = 1.0f / (CeltConstants.EPSILON + mem[0]);
|
||||
if (buffering != 0)
|
||||
{
|
||||
/* Consider the CELT delay when not in restricted-lowdelay */
|
||||
/* We assume the buffering is between 2.5 and 5 ms */
|
||||
offset = 2 * subframe - buffering;
|
||||
Inlines.OpusAssert(offset >= 0 && offset <= subframe);
|
||||
len -= offset;
|
||||
e[1] = mem[1];
|
||||
e_1[1] = 1.0f / (CeltConstants.EPSILON + mem[1]);
|
||||
e[2] = mem[2];
|
||||
e_1[2] = 1.0f / (CeltConstants.EPSILON + mem[2]);
|
||||
pos = 3;
|
||||
}
|
||||
else {
|
||||
pos = 1;
|
||||
offset = 0;
|
||||
}
|
||||
N = Inlines.IMIN(len / subframe, MAX_DYNAMIC_FRAMESIZE);
|
||||
/* Just silencing a warning, it's really initialized later */
|
||||
memx = 0;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
float tmp;
|
||||
int tmpx;
|
||||
int j;
|
||||
tmp = CeltConstants.EPSILON;
|
||||
|
||||
downmix(x, x_ptr, sub, 0, subframe, i * subframe + offset, 0, -2, C);
|
||||
if (i == 0)
|
||||
memx = sub[0];
|
||||
for (j = 0; j < subframe; j++)
|
||||
{
|
||||
tmpx = sub[j];
|
||||
tmp += (tmpx - memx) * (float)(tmpx - memx);
|
||||
memx = tmpx;
|
||||
}
|
||||
e[i + pos] = tmp;
|
||||
e_1[i + pos] = 1.0f / tmp;
|
||||
}
|
||||
/* Hack to get 20 ms working with APPLICATION_AUDIO
|
||||
The real problem is that the corresponding memory needs to use 1.5 ms
|
||||
from this frame and 1 ms from the next frame */
|
||||
e[i + pos] = e[i + pos - 1];
|
||||
if (buffering != 0)
|
||||
N = Inlines.IMIN(MAX_DYNAMIC_FRAMESIZE, N + 2);
|
||||
bestLM = transient_viterbi(e, e_1, N, (int)((1.0f + .5f * tonality) * (60 * C + 40)), bitrate / 400);
|
||||
mem[0] = e[1 << bestLM];
|
||||
if (buffering != 0)
|
||||
{
|
||||
mem[1] = e[(1 << bestLM) + 1];
|
||||
mem[2] = e[(1 << bestLM) + 2];
|
||||
}
|
||||
return bestLM;
|
||||
}
|
||||
|
||||
internal static int frame_size_select(int frame_size, OpusFramesize variable_duration, int Fs)
|
||||
{
|
||||
int new_size;
|
||||
if (frame_size < Fs / 400)
|
||||
return -1;
|
||||
if (variable_duration == OpusFramesize.OPUS_FRAMESIZE_ARG)
|
||||
new_size = frame_size;
|
||||
else if (variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE)
|
||||
new_size = Fs / 50;
|
||||
else if (variable_duration >= OpusFramesize.OPUS_FRAMESIZE_2_5_MS && variable_duration <= OpusFramesize.OPUS_FRAMESIZE_60_MS)
|
||||
new_size = Inlines.IMIN(3 * Fs / 50, (Fs / 400) << (variable_duration - OpusFramesize.OPUS_FRAMESIZE_2_5_MS));
|
||||
else
|
||||
return -1;
|
||||
if (new_size > frame_size)
|
||||
return -1;
|
||||
if (400 * new_size != Fs && 200 * new_size != Fs && 100 * new_size != Fs &&
|
||||
50 * new_size != Fs && 25 * new_size != Fs && 50 * new_size != 3 * Fs)
|
||||
return -1;
|
||||
return new_size;
|
||||
}
|
||||
|
||||
internal static int compute_frame_size<T>(T[] analysis_pcm, int analysis_pcm_ptr, int frame_size,
|
||||
OpusFramesize variable_duration, int C, int Fs, int bitrate_bps,
|
||||
int delay_compensation, Downmix.downmix_func<T> downmix, float[] subframe_mem, bool analysis_enabled
|
||||
)
|
||||
{
|
||||
|
||||
if (analysis_enabled && variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs / 200)
|
||||
{
|
||||
int LM = 3;
|
||||
LM = optimize_framesize(analysis_pcm, analysis_pcm_ptr, frame_size, C, Fs, bitrate_bps,
|
||||
0, subframe_mem, delay_compensation, downmix);
|
||||
while ((Fs / 400 << LM) > frame_size)
|
||||
LM--;
|
||||
frame_size = (Fs / 400 << LM);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_size = frame_size_select(frame_size, variable_duration, Fs);
|
||||
}
|
||||
|
||||
if (frame_size < 0)
|
||||
return -1;
|
||||
return frame_size;
|
||||
}
|
||||
|
||||
internal static int compute_stereo_width(short[] pcm, int pcm_ptr, int frame_size, int Fs, StereoWidthState mem)
|
||||
{
|
||||
int corr;
|
||||
int ldiff;
|
||||
int width;
|
||||
int xx, xy, yy;
|
||||
int sqrt_xx, sqrt_yy;
|
||||
int qrrt_xx, qrrt_yy;
|
||||
int frame_rate;
|
||||
int i;
|
||||
int short_alpha;
|
||||
|
||||
frame_rate = Fs / frame_size;
|
||||
short_alpha = CeltConstants.Q15ONE - (25 * CeltConstants.Q15ONE / Inlines.IMAX(50, frame_rate));
|
||||
xx = xy = yy = 0;
|
||||
for (i = 0; i < frame_size - 3; i += 4)
|
||||
{
|
||||
int pxx = 0;
|
||||
int pxy = 0;
|
||||
int pyy = 0;
|
||||
int x, y;
|
||||
int p2i = pcm_ptr + (2 * i);
|
||||
x = pcm[p2i];
|
||||
y = pcm[p2i + 1];
|
||||
pxx = Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
|
||||
pxy = Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
|
||||
pyy = Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
|
||||
x = pcm[p2i + 2];
|
||||
y = pcm[p2i + 3];
|
||||
pxx += Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
|
||||
pxy += Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
|
||||
pyy += Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
|
||||
x = pcm[p2i + 4];
|
||||
y = pcm[p2i + 5];
|
||||
pxx += Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
|
||||
pxy += Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
|
||||
pyy += Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
|
||||
x = pcm[p2i + 6];
|
||||
y = pcm[p2i + 7];
|
||||
pxx += Inlines.SHR32(Inlines.MULT16_16(x, x), 2);
|
||||
pxy += Inlines.SHR32(Inlines.MULT16_16(x, y), 2);
|
||||
pyy += Inlines.SHR32(Inlines.MULT16_16(y, y), 2);
|
||||
|
||||
xx += Inlines.SHR32(pxx, 10);
|
||||
xy += Inlines.SHR32(pxy, 10);
|
||||
yy += Inlines.SHR32(pyy, 10);
|
||||
}
|
||||
|
||||
mem.XX += Inlines.MULT16_32_Q15(short_alpha, xx - mem.XX);
|
||||
mem.XY += Inlines.MULT16_32_Q15(short_alpha, xy - mem.XY);
|
||||
mem.YY += Inlines.MULT16_32_Q15(short_alpha, yy - mem.YY);
|
||||
mem.XX = Inlines.MAX32(0, mem.XX);
|
||||
mem.XY = Inlines.MAX32(0, mem.XY);
|
||||
mem.YY = Inlines.MAX32(0, mem.YY);
|
||||
if (Inlines.MAX32(mem.XX, mem.YY) > ((short)(0.5 + (8e-4f) * (((int)1) << (18))))/*Inlines.QCONST16(8e-4f, 18)*/)
|
||||
{
|
||||
sqrt_xx = Inlines.celt_sqrt(mem.XX);
|
||||
sqrt_yy = Inlines.celt_sqrt(mem.YY);
|
||||
qrrt_xx = Inlines.celt_sqrt(sqrt_xx);
|
||||
qrrt_yy = Inlines.celt_sqrt(sqrt_yy);
|
||||
/* Inter-channel correlation */
|
||||
mem.XY = Inlines.MIN32(mem.XY, sqrt_xx * sqrt_yy);
|
||||
corr = Inlines.SHR32(Inlines.frac_div32(mem.XY, CeltConstants.EPSILON + Inlines.MULT16_16(sqrt_xx, sqrt_yy)), 16);
|
||||
/* Approximate loudness difference */
|
||||
ldiff = CeltConstants.Q15ONE * Inlines.ABS16(qrrt_xx - qrrt_yy) / (CeltConstants.EPSILON + qrrt_xx + qrrt_yy);
|
||||
width = Inlines.MULT16_16_Q15(Inlines.celt_sqrt(((int)(0.5 + (1.0f) * (((int)1) << (30))))/*Inlines.QCONST32(1.0f, 30)*/ - Inlines.MULT16_16(corr, corr)), ldiff);
|
||||
/* Smoothing over one second */
|
||||
mem.smoothed_width += (width - mem.smoothed_width) / frame_rate;
|
||||
/* Peak follower */
|
||||
mem.max_follower = Inlines.MAX16(mem.max_follower - ((short)(0.5 + (.02f) * (((int)1) << (15))))/*Inlines.QCONST16(.02f, 15)*/ / frame_rate, mem.smoothed_width);
|
||||
}
|
||||
else {
|
||||
width = 0;
|
||||
corr = CeltConstants.Q15ONE;
|
||||
ldiff = 0;
|
||||
}
|
||||
/*printf("%f %f %f %f %f ", corr/(float)1.0f, ldiff/(float)1.0f, width/(float)1.0f, mem.smoothed_width/(float)1.0f, mem.max_follower/(float)1.0f);*/
|
||||
return Inlines.EXTRACT16(Inlines.MIN32(CeltConstants.Q15ONE, 20 * mem.max_follower));
|
||||
}
|
||||
|
||||
internal static void smooth_fade(short[] in1, int in1_ptr, short[] in2, int in2_ptr,
|
||||
short[] output, int output_ptr, int overlap, int channels,
|
||||
int[] window, int Fs)
|
||||
{
|
||||
int i, c;
|
||||
int inc = 48000 / Fs;
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
for (i = 0; i < overlap; i++)
|
||||
{
|
||||
int w = Inlines.MULT16_16_Q15(window[i * inc], window[i * inc]);
|
||||
output[output_ptr + (i * channels) + c] = (short)(Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(w, in2[in2_ptr + (i * channels) + c]),
|
||||
CeltConstants.Q15ONE - w, in1[in1_ptr + (i * channels) + c]), 15));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//internal static void opus_pcm_soft_clip(Pointer<float> _x, int N, int C, Pointer<float> declip_mem)
|
||||
//{
|
||||
// int c;
|
||||
// int i;
|
||||
// Pointer<float> x;
|
||||
|
||||
// if (C < 1 || N < 1 || _x == null || declip_mem == null) return;
|
||||
|
||||
// /* First thing: saturate everything to +/- 2 which is the highest level our
|
||||
// non-linearity can handle. At the point where the signal reaches +/-2,
|
||||
// the derivative will be zero anyway, so this doesn't introduce any
|
||||
// discontinuity in the derivative. */
|
||||
// for (i = 0; i < N * C; i++)
|
||||
// _x[i] = Inlines.MAX16(-2.0f, Inlines.MIN16(2.0f, _x[i]));
|
||||
// for (c = 0; c < C; c++)
|
||||
// {
|
||||
// float a;
|
||||
// float x0;
|
||||
// int curr;
|
||||
|
||||
// x = _x.Point(c);
|
||||
// a = declip_mem[c];
|
||||
// /* Continue applying the non-linearity from the previous frame to avoid
|
||||
// any discontinuity. */
|
||||
// for (i = 0; i < N; i++)
|
||||
// {
|
||||
// if (x[i * C] * a >= 0)
|
||||
// break;
|
||||
// x[i * C] = x[i * C] + a * x[i * C] * x[i * C];
|
||||
// }
|
||||
|
||||
// curr = 0;
|
||||
// x0 = x[0];
|
||||
|
||||
// while (true)
|
||||
// {
|
||||
// int start, end;
|
||||
// float maxval;
|
||||
// int special = 0;
|
||||
// int peak_pos;
|
||||
// for (i = curr; i < N; i++)
|
||||
// {
|
||||
// if (x[i * C] > 1 || x[i * C] < -1)
|
||||
// break;
|
||||
// }
|
||||
// if (i == N)
|
||||
// {
|
||||
// a = 0;
|
||||
// break;
|
||||
// }
|
||||
// peak_pos = i;
|
||||
// start = end = i;
|
||||
// maxval = Inlines.ABS16(x[i * C]);
|
||||
// /* Look for first zero crossing before clipping */
|
||||
// while (start > 0 && x[i * C] * x[(start - 1) * C] >= 0)
|
||||
// start--;
|
||||
// /* Look for first zero crossing after clipping */
|
||||
// while (end < N && x[i * C] * x[end * C] >= 0)
|
||||
// {
|
||||
// /* Look for other peaks until the next zero-crossing. */
|
||||
// if (Inlines.ABS16(x[end * C]) > maxval)
|
||||
// {
|
||||
// maxval = Inlines.ABS16(x[end * C]);
|
||||
// peak_pos = end;
|
||||
// }
|
||||
// end++;
|
||||
// }
|
||||
// /* Detect the special case where we clip before the first zero crossing */
|
||||
// special = (start == 0 && x[i * C] * x[0] >= 0) ? 1 : 0;
|
||||
|
||||
// /* Compute a such that maxval + a*maxval^2 = 1 */
|
||||
// a = (maxval - 1) / (maxval * maxval);
|
||||
// if (x[i * C] > 0)
|
||||
// a = -a;
|
||||
// /* Apply soft clipping */
|
||||
// for (i = start; i < end; i++)
|
||||
// x[i * C] = x[i * C] + a * x[i * C] * x[i * C];
|
||||
|
||||
// if (special != 0 && peak_pos >= 2)
|
||||
// {
|
||||
// /* Add a linear ramp from the first sample to the signal peak.
|
||||
// This avoids a discontinuity at the beginning of the frame. */
|
||||
// float delta;
|
||||
// float offset = x0 - x[0];
|
||||
// delta = offset / peak_pos;
|
||||
// for (i = curr; i < peak_pos; i++)
|
||||
// {
|
||||
// offset -= delta;
|
||||
// x[i * C] += offset;
|
||||
// x[i * C] = Inlines.MAX16(-1.0f, Inlines.MIN16(1.0f, x[i * C]));
|
||||
// }
|
||||
// }
|
||||
// curr = end;
|
||||
// if (curr == N)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// declip_mem[c] = a;
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
internal static string opus_strerror(int error)
|
||||
{
|
||||
string[] error_strings = {
|
||||
"success",
|
||||
"invalid argument",
|
||||
"buffer too small",
|
||||
"internal error",
|
||||
"corrupted stream",
|
||||
"request not implemented",
|
||||
"invalid state",
|
||||
"memory allocation failed"
|
||||
};
|
||||
if (error > 0 || error < -7)
|
||||
return "unknown error";
|
||||
else
|
||||
return error_strings[-error];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the version number of this library
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetVersionString()
|
||||
{
|
||||
return "Concentus 1.1.6"
|
||||
#if DEBUG
|
||||
+ "-debug"
|
||||
#endif
|
||||
#if FUZZING
|
||||
+ "-fuzzing"
|
||||
#endif
|
||||
#if PARITY
|
||||
#else
|
||||
+ "-nonparity"
|
||||
#endif
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
125
Libraries/Concentus/CSharp/Concentus/Opus/Downmix.cs
Normal file
125
Libraries/Concentus/CSharp/Concentus/Opus/Downmix.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
internal static class Downmix
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of signal being handled (either short or float)</typeparam>
|
||||
/// <param name="_x"></param>
|
||||
/// <param name="sub"></param>
|
||||
/// <param name="subframe"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="c1"></param>
|
||||
/// <param name="c2"></param>
|
||||
/// <param name="C"></param>
|
||||
public delegate void downmix_func<T>(T[] _x, int x_ptr, int[] sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C);
|
||||
|
||||
internal static void downmix_float(float[] x, int x_ptr, int[] sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C)
|
||||
{
|
||||
int scale;
|
||||
int j;
|
||||
int c1x = c1 + x_ptr;
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[sub_ptr + j] = Inlines.FLOAT2INT16(x[(j + offset) * C + c1x]);
|
||||
if (c2 > -1)
|
||||
{
|
||||
int c2x = c2 + x_ptr;
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[sub_ptr + j] += Inlines.FLOAT2INT16(x[(j + offset) * C + c2x]);
|
||||
}
|
||||
else if (c2 == -2)
|
||||
{
|
||||
int c;
|
||||
int cx;
|
||||
for (c = 1; c < C; c++)
|
||||
{
|
||||
cx = c + x_ptr;
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[sub_ptr + j] += Inlines.FLOAT2INT16(x[(j + offset) * C + cx]);
|
||||
}
|
||||
}
|
||||
scale = (1 << CeltConstants.SIG_SHIFT);
|
||||
if (C == -2)
|
||||
scale /= C;
|
||||
else
|
||||
scale /= 2;
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[sub_ptr + j] *= scale;
|
||||
}
|
||||
|
||||
internal static void downmix_int(short[] x, int x_ptr, int[] sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C)
|
||||
{
|
||||
int scale;
|
||||
int j;
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[j + sub_ptr] = x[(j + offset) * C + c1];
|
||||
if (c2 > -1)
|
||||
{
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[j + sub_ptr] += x[(j + offset) * C + c2];
|
||||
}
|
||||
else if (c2 == -2)
|
||||
{
|
||||
int c;
|
||||
for (c = 1; c < C; c++)
|
||||
{
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[j + sub_ptr] += x[(j + offset) * C + c];
|
||||
}
|
||||
}
|
||||
scale = (1 << CeltConstants.SIG_SHIFT);
|
||||
if (C == -2)
|
||||
scale /= C;
|
||||
else
|
||||
scale /= 2;
|
||||
for (j = 0; j < subframe; j++)
|
||||
sub[j + sub_ptr] *= scale;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Enums
|
||||
{
|
||||
public enum OpusApplication
|
||||
{
|
||||
OPUS_APPLICATION_UNIMPLEMENTED = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Best for most VoIP/videoconference applications where listening quality and intelligibility matter most
|
||||
/// </summary>
|
||||
OPUS_APPLICATION_VOIP = 2048,
|
||||
|
||||
/// <summary>
|
||||
/// Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input
|
||||
/// </summary>
|
||||
OPUS_APPLICATION_AUDIO = 2049,
|
||||
|
||||
/// <summary>
|
||||
/// Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used.
|
||||
/// </summary>
|
||||
OPUS_APPLICATION_RESTRICTED_LOWDELAY = 2051
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Enums
|
||||
{
|
||||
public enum OpusBandwidth
|
||||
{
|
||||
OPUS_BANDWIDTH_AUTO = -1000,
|
||||
OPUS_BANDWIDTH_NARROWBAND = 1101,
|
||||
OPUS_BANDWIDTH_MEDIUMBAND = 1102,
|
||||
OPUS_BANDWIDTH_WIDEBAND = 1103,
|
||||
OPUS_BANDWIDTH_SUPERWIDEBAND = 1104,
|
||||
OPUS_BANDWIDTH_FULLBAND = 1105
|
||||
}
|
||||
|
||||
// FIXME: We should remove all cases where bandwidth is cast to int, it's.....improper
|
||||
internal static class OpusBandwidthHelpers
|
||||
{
|
||||
internal static int GetOrdinal(OpusBandwidth bw)
|
||||
{
|
||||
return (int)bw - (int)OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
|
||||
}
|
||||
|
||||
internal static OpusBandwidth MIN(OpusBandwidth a, OpusBandwidth b)
|
||||
{
|
||||
if ((int)a < (int)b)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
internal static OpusBandwidth MAX(OpusBandwidth a, OpusBandwidth b)
|
||||
{
|
||||
if ((int)a > (int)b)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Enums
|
||||
{
|
||||
public static class OpusControl
|
||||
{
|
||||
/** These are the actual Encoder CTL ID numbers.
|
||||
* They should not be used directly by applications.
|
||||
* In general, SETs should be even and GETs should be odd.*/
|
||||
public const int OPUS_SET_APPLICATION_REQUEST = 4000;
|
||||
public const int OPUS_GET_APPLICATION_REQUEST = 4001;
|
||||
public const int OPUS_SET_BITRATE_REQUEST = 4002;
|
||||
public const int OPUS_GET_BITRATE_REQUEST = 4003;
|
||||
public const int OPUS_SET_MAX_BANDWIDTH_REQUEST = 4004;
|
||||
public const int OPUS_GET_MAX_BANDWIDTH_REQUEST = 4005;
|
||||
public const int OPUS_SET_VBR_REQUEST = 4006;
|
||||
public const int OPUS_GET_VBR_REQUEST = 4007;
|
||||
public const int OPUS_SET_BANDWIDTH_REQUEST = 4008;
|
||||
public const int OPUS_GET_BANDWIDTH_REQUEST = 4009;
|
||||
public const int OPUS_SET_COMPLEXITY_REQUEST = 4010;
|
||||
public const int OPUS_GET_COMPLEXITY_REQUEST = 4011;
|
||||
public const int OPUS_SET_INBAND_FEC_REQUEST = 4012;
|
||||
public const int OPUS_GET_INBAND_FEC_REQUEST = 4013;
|
||||
public const int OPUS_SET_PACKET_LOSS_PERC_REQUEST = 4014;
|
||||
public const int OPUS_GET_PACKET_LOSS_PERC_REQUEST = 4015;
|
||||
public const int OPUS_SET_DTX_REQUEST = 4016;
|
||||
public const int OPUS_GET_DTX_REQUEST = 4017;
|
||||
public const int OPUS_SET_VBR_CONSTRAINT_REQUEST = 4020;
|
||||
public const int OPUS_GET_VBR_CONSTRAINT_REQUEST = 4021;
|
||||
public const int OPUS_SET_FORCE_CHANNELS_REQUEST = 4022;
|
||||
public const int OPUS_GET_FORCE_CHANNELS_REQUEST = 4023;
|
||||
public const int OPUS_SET_SIGNAL_REQUEST = 4024;
|
||||
public const int OPUS_GET_SIGNAL_REQUEST = 4025;
|
||||
public const int OPUS_GET_LOOKAHEAD_REQUEST = 4027;
|
||||
/* public const int OPUS_RESET_STATE 4028 */
|
||||
public const int OPUS_GET_SAMPLE_RATE_REQUEST = 4029;
|
||||
public const int OPUS_GET_FINAL_RANGE_REQUEST = 4031;
|
||||
public const int OPUS_GET_PITCH_REQUEST = 4033;
|
||||
public const int OPUS_SET_GAIN_REQUEST = 4034;
|
||||
public const int OPUS_GET_GAIN_REQUEST = 4045;
|
||||
public const int OPUS_SET_LSB_DEPTH_REQUEST = 4036;
|
||||
public const int OPUS_GET_LSB_DEPTH_REQUEST = 4037;
|
||||
public const int OPUS_GET_LAST_PACKET_DURATION_REQUEST = 4039;
|
||||
public const int OPUS_SET_EXPERT_FRAME_DURATION_REQUEST = 4040;
|
||||
public const int OPUS_GET_EXPERT_FRAME_DURATION_REQUEST = 4041;
|
||||
public const int OPUS_SET_PREDICTION_DISABLED_REQUEST = 4042;
|
||||
public const int OPUS_GET_PREDICTION_DISABLED_REQUEST = 4043;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the codec state to be equivalent to a freshly initialized state.
|
||||
/// This should be called when switching streams in order to prevent
|
||||
/// the back to back decoding from giving different results from
|
||||
/// one at a time decoding.
|
||||
/// </summary>
|
||||
public const int OPUS_RESET_STATE = 4028;
|
||||
|
||||
public const int OPUS_SET_VOICE_RATIO_REQUEST = 11018;
|
||||
public const int OPUS_GET_VOICE_RATIO_REQUEST = 11019;
|
||||
public const int OPUS_SET_FORCE_MODE_REQUEST = 11002;
|
||||
}
|
||||
}
|
||||
68
Libraries/Concentus/CSharp/Concentus/Opus/Enums/OpusError.cs
Normal file
68
Libraries/Concentus/CSharp/Concentus/Opus/Enums/OpusError.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Note that since most API-level errors are detected and thrown as
|
||||
/// OpusExceptions, direct use of this class is not usually needed
|
||||
/// </summary>
|
||||
public static class OpusError
|
||||
{
|
||||
/** No error*/
|
||||
public const int OPUS_OK = 0;
|
||||
|
||||
/** One or more invalid/out of range arguments*/
|
||||
public const int OPUS_BAD_ARG = -1;
|
||||
|
||||
/** Not enough bytes allocated in the buffer*/
|
||||
public const int OPUS_BUFFER_TOO_SMALL = -2;
|
||||
|
||||
/** An public error was detected*/
|
||||
public const int OPUS_INTERNAL_ERROR = -3;
|
||||
|
||||
/** The compressed data passed is corrupted*/
|
||||
public const int OPUS_INVALID_PACKET = -4;
|
||||
|
||||
/** Invalid/unsupported request number*/
|
||||
public const int OPUS_UNIMPLEMENTED = -5;
|
||||
|
||||
/** An encoder or decoder structure is invalid or already freed*/
|
||||
public const int OPUS_INVALID_STATE = -6;
|
||||
|
||||
/** Memory allocation has failed*/
|
||||
public const int OPUS_ALLOC_FAIL = -7;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Enums
|
||||
{
|
||||
public enum OpusFramesize
|
||||
{
|
||||
/// <summary>
|
||||
/// Select frame size from the argument (default)
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_ARG = 5000,
|
||||
|
||||
/// <summary>
|
||||
/// Use 2.5 ms frames
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_2_5_MS = 5001,
|
||||
|
||||
/// <summary>
|
||||
/// Use 5 ms frames
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_5_MS = 5002,
|
||||
|
||||
/// <summary>
|
||||
/// Use 10 ms frames
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_10_MS = 5003,
|
||||
|
||||
/// <summary>
|
||||
/// Use 20 ms frames
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_20_MS = 5004,
|
||||
|
||||
/// <summary>
|
||||
/// Use 40 ms frames
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_40_MS = 5005,
|
||||
|
||||
/// <summary>
|
||||
/// Use 60 ms frames
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_60_MS = 5006,
|
||||
|
||||
/// <summary>
|
||||
/// Do not use - not fully implemented. Optimize the frame size dynamically.
|
||||
/// </summary>
|
||||
OPUS_FRAMESIZE_VARIABLE = 5010
|
||||
}
|
||||
}
|
||||
45
Libraries/Concentus/CSharp/Concentus/Opus/Enums/OpusMode.cs
Normal file
45
Libraries/Concentus/CSharp/Concentus/Opus/Enums/OpusMode.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Enums
|
||||
{
|
||||
public enum OpusMode
|
||||
{
|
||||
MODE_AUTO = -1000,
|
||||
MODE_SILK_ONLY = 1000,
|
||||
MODE_HYBRID = 1001,
|
||||
MODE_CELT_ONLY = 1002
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Enums
|
||||
{
|
||||
public enum OpusSignal
|
||||
{
|
||||
OPUS_SIGNAL_AUTO = -1000,
|
||||
|
||||
/// <summary>
|
||||
/// Signal being encoded is voice
|
||||
/// </summary>
|
||||
OPUS_SIGNAL_VOICE = 3001,
|
||||
|
||||
/// <summary>
|
||||
/// Signal being encoded is music
|
||||
/// </summary>
|
||||
OPUS_SIGNAL_MUSIC = 3002
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* Copyright (c) 2008-2011 Octasic Inc.
|
||||
Originally written by Jean-Marc Valin
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Structs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
/// <summary>
|
||||
/// multi-layer perceptron processor
|
||||
/// </summary>
|
||||
internal static class mlp
|
||||
{
|
||||
private const int MAX_NEURONS = 100;
|
||||
|
||||
internal static float tansig_approx(float x)
|
||||
{
|
||||
int i;
|
||||
float y, dy;
|
||||
float sign = 1;
|
||||
/* Tests are reversed to catch NaNs */
|
||||
if (!(x < 8))
|
||||
return 1;
|
||||
if (!(x > -8))
|
||||
return -1;
|
||||
if (x < 0)
|
||||
{
|
||||
x = -x;
|
||||
sign = -1;
|
||||
}
|
||||
i = (int)Math.Floor(.5f + 25 * x);
|
||||
x -= .04f * i;
|
||||
y = Tables.tansig_table[i];
|
||||
dy = 1 - y * y;
|
||||
y = y + x * dy * (1 - y * x);
|
||||
return sign * y;
|
||||
}
|
||||
|
||||
internal static void mlp_process(MLP m, float[] input, float[] output)
|
||||
{
|
||||
int j;
|
||||
float[] hidden = new float[MAX_NEURONS];
|
||||
float[] W = m.weights;
|
||||
int W_ptr = 0;
|
||||
|
||||
/* Copy to tmp_in */
|
||||
|
||||
for (j = 0; j < m.topo[1]; j++)
|
||||
{
|
||||
int k;
|
||||
float sum = W[W_ptr];
|
||||
W_ptr++;
|
||||
for (k = 0; k < m.topo[0]; k++)
|
||||
{
|
||||
sum = sum + input[k] * W[W_ptr];
|
||||
W_ptr++;
|
||||
}
|
||||
hidden[j] = tansig_approx(sum);
|
||||
}
|
||||
|
||||
for (j = 0; j < m.topo[2]; j++)
|
||||
{
|
||||
int k;
|
||||
float sum = W[W_ptr];
|
||||
W_ptr++;
|
||||
for (k = 0; k < m.topo[1]; k++)
|
||||
{
|
||||
sum = sum + hidden[k] * W[W_ptr];
|
||||
W_ptr++;
|
||||
}
|
||||
output[j] = tansig_approx(sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
340
Libraries/Concentus/CSharp/Concentus/Opus/OpusCompare.cs
Normal file
340
Libraries/Concentus/CSharp/Concentus/Opus/OpusCompare.cs
Normal file
@@ -0,0 +1,340 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
internal static class OpusCompare
|
||||
{
|
||||
private const int NBANDS = 21;
|
||||
private const int NFREQS = 240;
|
||||
private const int TEST_WIN_SIZE = 480;
|
||||
private const int TEST_WIN_STEP = 120;
|
||||
|
||||
/*Bands on which we compute the pseudo-NMR (Bark-derived CELT bands).*/
|
||||
private static readonly int[] BANDS/*[NBANDS + 1]*/ ={
|
||||
0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200
|
||||
};
|
||||
|
||||
private static void band_energy(Pointer<float> _out, Pointer<float> _ps,
|
||||
Pointer<int> _bands, int _nbands,
|
||||
Pointer<float> _in, int _nchannels, int _nframes, int _window_sz,
|
||||
int _step, int _downsample)
|
||||
{
|
||||
Pointer<float> window;
|
||||
Pointer<float> x;
|
||||
Pointer<float> c;
|
||||
Pointer<float> s;
|
||||
int xi;
|
||||
int xj;
|
||||
int ps_sz;
|
||||
window = Pointer.Malloc<float>((3 + _nchannels) * _window_sz);
|
||||
c = window.Point(_window_sz);
|
||||
s = c.Point(_window_sz);
|
||||
x = s.Point(_window_sz);
|
||||
ps_sz = _window_sz / 2;
|
||||
for (xj = 0; xj < _window_sz; xj++)
|
||||
{
|
||||
window[xj] = (float)(0.5 - 0.5 * Math.Cos((2 * Math.PI / (_window_sz - 1)) * xj));
|
||||
}
|
||||
for (xj = 0; xj < _window_sz; xj++)
|
||||
{
|
||||
c[xj] = (float)Math.Cos((2 * Math.PI / _window_sz) * xj);
|
||||
}
|
||||
for (xj = 0; xj < _window_sz; xj++)
|
||||
{
|
||||
s[xj] = (float)Math.Sin((2 * Math.PI / _window_sz) * xj);
|
||||
}
|
||||
for (xi = 0; xi < _nframes; xi++)
|
||||
{
|
||||
int ci;
|
||||
int xk;
|
||||
int bi;
|
||||
for (ci = 0; ci < _nchannels; ci++)
|
||||
{
|
||||
for (xk = 0; xk < _window_sz; xk++)
|
||||
{
|
||||
x[ci * _window_sz + xk] = window[xk] * _in[(xi * _step + xk) * _nchannels + ci];
|
||||
}
|
||||
}
|
||||
for (bi = xj = 0; bi < _nbands; bi++)
|
||||
{
|
||||
float[] p = { 0, 0 };
|
||||
for (; xj < _bands[bi + 1]; xj++)
|
||||
{
|
||||
for (ci = 0; ci < _nchannels; ci++)
|
||||
{
|
||||
float re;
|
||||
float im;
|
||||
int ti;
|
||||
ti = 0;
|
||||
re = im = 0;
|
||||
for (xk = 0; xk < _window_sz; xk++)
|
||||
{
|
||||
re += c[ti] * x[ci * _window_sz + xk];
|
||||
im -= s[ti] * x[ci * _window_sz + xk];
|
||||
ti += xj;
|
||||
if (ti >= _window_sz) ti -= _window_sz;
|
||||
}
|
||||
re *= _downsample;
|
||||
im *= _downsample;
|
||||
_ps[(xi * ps_sz + xj) * _nchannels + ci] = re * re + im * im + 100000;
|
||||
p[ci] += _ps[(xi * ps_sz + xj) * _nchannels + ci];
|
||||
}
|
||||
}
|
||||
if (_out != null)
|
||||
{
|
||||
_out[(xi * _nbands + bi) * _nchannels] = p[0] / (_bands[bi + 1] - _bands[bi]);
|
||||
if (_nchannels == 2)
|
||||
{
|
||||
_out[(xi * _nbands + bi) * _nchannels + 1] = p[1] / (_bands[bi + 1] - _bands[bi]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static float compare(float[] x, float[] y, int nchannels, int rate = 48000)
|
||||
{
|
||||
Pointer<float> xb;
|
||||
Pointer<float> X;
|
||||
Pointer<float> Y;
|
||||
double err;
|
||||
float Q;
|
||||
int xlength = x.Length;
|
||||
int ylength = y.Length;
|
||||
int nframes;
|
||||
int xi;
|
||||
int ci;
|
||||
int xj;
|
||||
int bi;
|
||||
int downsample;
|
||||
int ybands;
|
||||
int yfreqs;
|
||||
int max_compare;
|
||||
ybands = NBANDS;
|
||||
yfreqs = NFREQS;
|
||||
if (rate != 8000 && rate != 12000 && rate != 16000 && rate != 24000 && rate != 48000)
|
||||
{
|
||||
throw new ArgumentException("Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n");
|
||||
}
|
||||
if (rate != 48000)
|
||||
{
|
||||
downsample = 48000 / rate;
|
||||
switch (rate)
|
||||
{
|
||||
case 8000: ybands = 13; break;
|
||||
case 12000: ybands = 15; break;
|
||||
case 16000: ybands = 17; break;
|
||||
case 24000: ybands = 19; break;
|
||||
}
|
||||
yfreqs = NFREQS / downsample;
|
||||
}
|
||||
else
|
||||
{
|
||||
downsample = 1;
|
||||
}
|
||||
|
||||
if (xlength != ylength * downsample)
|
||||
{
|
||||
throw new ArgumentException("Sample counts do not match");
|
||||
}
|
||||
|
||||
if (xlength < TEST_WIN_SIZE)
|
||||
{
|
||||
throw new ArgumentException("Insufficient sample data");
|
||||
}
|
||||
|
||||
nframes = (xlength - TEST_WIN_SIZE + TEST_WIN_STEP) / TEST_WIN_STEP;
|
||||
xb = Pointer.Malloc<float>(nframes * NBANDS * nchannels);
|
||||
X = Pointer.Malloc<float>(nframes * NFREQS * nchannels);
|
||||
Y = Pointer.Malloc<float>(nframes * yfreqs * nchannels);
|
||||
/*Compute the per-band spectral energy of the original signal
|
||||
and the error.*/
|
||||
band_energy(xb, X, BANDS.GetPointer(), NBANDS, x.GetPointer(), nchannels, nframes,
|
||||
TEST_WIN_SIZE, TEST_WIN_STEP, 1);
|
||||
band_energy(null, Y, BANDS.GetPointer(), ybands, y.GetPointer(), nchannels, nframes,
|
||||
TEST_WIN_SIZE / downsample, TEST_WIN_STEP / downsample, downsample);
|
||||
for (xi = 0; xi < nframes; xi++)
|
||||
{
|
||||
/*Frequency masking (low to high): 10 dB/Bark slope.*/
|
||||
for (bi = 1; bi < NBANDS; bi++)
|
||||
{
|
||||
for (ci = 0; ci < nchannels; ci++)
|
||||
{
|
||||
xb[(xi * NBANDS + bi) * nchannels + ci] +=
|
||||
0.1F * xb[(xi * NBANDS + bi - 1) * nchannels + ci];
|
||||
}
|
||||
}
|
||||
/*Frequency masking (high to low): 15 dB/Bark slope.*/
|
||||
for (bi = NBANDS - 1; bi-- > 0;)
|
||||
{
|
||||
for (ci = 0; ci < nchannels; ci++)
|
||||
{
|
||||
xb[(xi * NBANDS + bi) * nchannels + ci] +=
|
||||
0.03F * xb[(xi * NBANDS + bi + 1) * nchannels + ci];
|
||||
}
|
||||
}
|
||||
if (xi > 0)
|
||||
{
|
||||
/*Temporal masking: -3 dB/2.5ms slope.*/
|
||||
for (bi = 0; bi < NBANDS; bi++)
|
||||
{
|
||||
for (ci = 0; ci < nchannels; ci++)
|
||||
{
|
||||
xb[(xi * NBANDS + bi) * nchannels + ci] +=
|
||||
0.5F * xb[((xi - 1) * NBANDS + bi) * nchannels + ci];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Allowing some cross-talk */
|
||||
if (nchannels == 2)
|
||||
{
|
||||
for (bi = 0; bi < NBANDS; bi++)
|
||||
{
|
||||
float l, r;
|
||||
l = xb[(xi * NBANDS + bi) * nchannels + 0];
|
||||
r = xb[(xi * NBANDS + bi) * nchannels + 1];
|
||||
xb[(xi * NBANDS + bi) * nchannels + 0] += 0.01F * r;
|
||||
xb[(xi * NBANDS + bi) * nchannels + 1] += 0.01F * l;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply masking */
|
||||
for (bi = 0; bi < ybands; bi++)
|
||||
{
|
||||
for (xj = BANDS[bi]; xj < BANDS[bi + 1]; xj++)
|
||||
{
|
||||
for (ci = 0; ci < nchannels; ci++)
|
||||
{
|
||||
X[(xi * NFREQS + xj) * nchannels + ci] +=
|
||||
0.1F * xb[(xi * NBANDS + bi) * nchannels + ci];
|
||||
Y[(xi * yfreqs + xj) * nchannels + ci] +=
|
||||
0.1F * xb[(xi * NBANDS + bi) * nchannels + ci];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Average of consecutive frames to make comparison slightly less sensitive */
|
||||
for (bi = 0; bi < ybands; bi++)
|
||||
{
|
||||
for (xj = BANDS[bi]; xj < BANDS[bi + 1]; xj++)
|
||||
{
|
||||
for (ci = 0; ci < nchannels; ci++)
|
||||
{
|
||||
float xtmp;
|
||||
float ytmp;
|
||||
xtmp = X[xj * nchannels + ci];
|
||||
ytmp = Y[xj * nchannels + ci];
|
||||
for (xi = 1; xi < nframes; xi++)
|
||||
{
|
||||
float xtmp2;
|
||||
float ytmp2;
|
||||
xtmp2 = X[(xi * NFREQS + xj) * nchannels + ci];
|
||||
ytmp2 = Y[(xi * yfreqs + xj) * nchannels + ci];
|
||||
X[(xi * NFREQS + xj) * nchannels + ci] += xtmp;
|
||||
Y[(xi * yfreqs + xj) * nchannels + ci] += ytmp;
|
||||
xtmp = xtmp2;
|
||||
ytmp = ytmp2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*If working at a lower sampling rate, don't take into account the last
|
||||
300 Hz to allow for different transition bands.
|
||||
For 12 kHz, we don't skip anything, because the last band already skips
|
||||
400 Hz.*/
|
||||
if (rate == 48000) max_compare = BANDS[NBANDS];
|
||||
else if (rate == 12000) max_compare = BANDS[ybands];
|
||||
else max_compare = BANDS[ybands] - 3;
|
||||
err = 0;
|
||||
for (xi = 0; xi < nframes; xi++)
|
||||
{
|
||||
double Ef;
|
||||
Ef = 0;
|
||||
for (bi = 0; bi < ybands; bi++)
|
||||
{
|
||||
double Eb;
|
||||
Eb = 0;
|
||||
for (xj = BANDS[bi]; xj < BANDS[bi + 1] && xj < max_compare; xj++)
|
||||
{
|
||||
for (ci = 0; ci < nchannels; ci++)
|
||||
{
|
||||
float re;
|
||||
float im;
|
||||
re = Y[(xi * yfreqs + xj) * nchannels + ci] / X[(xi * NFREQS + xj) * nchannels + ci];
|
||||
im = re - (float)Math.Log(re) - 1;
|
||||
/*Make comparison less sensitive around the SILK/CELT cross-over to
|
||||
allow for mode freedom in the filters.*/
|
||||
if (xj >= 79 && xj <= 81) im *= 0.1F;
|
||||
if (xj == 80) im *= 0.1F;
|
||||
Eb += im;
|
||||
}
|
||||
}
|
||||
Eb /= (BANDS[bi + 1] - BANDS[bi]) * nchannels;
|
||||
Ef += Eb * Eb;
|
||||
}
|
||||
/*Using a fixed normalization value means we're willing to accept slightly
|
||||
lower quality for lower sampling rates.*/
|
||||
Ef /= NBANDS;
|
||||
Ef *= Ef;
|
||||
err += Ef * Ef;
|
||||
}
|
||||
err = Math.Pow(err / nframes, 1.0 / 16);
|
||||
Q = (float)(100 * (1 - 0.5 * Math.Log(1 + err) / Math.Log(1.13)));
|
||||
|
||||
if (Q < 0)
|
||||
{
|
||||
Debug.WriteLine("Test vector FAILS");
|
||||
Debug.WriteLine(string.Format("Internal weighted error is {0}", err));
|
||||
}
|
||||
else {
|
||||
Debug.WriteLine("Test vector PASSES");
|
||||
Debug.WriteLine(string.Format("Opus quality metric: {0} (internal weighted error is {1})", Q, err));
|
||||
}
|
||||
|
||||
return Q;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Libraries/Concentus/CSharp/Concentus/Opus/OpusConstants.cs
Normal file
66
Libraries/Concentus/CSharp/Concentus/Opus/OpusConstants.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
public static class OpusConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Auto/default setting
|
||||
/// </summary>
|
||||
public const int OPUS_AUTO = -1000;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum bitrate
|
||||
/// </summary>
|
||||
public const int OPUS_BITRATE_MAX = -1;
|
||||
|
||||
// from analysis.c
|
||||
public const int NB_FRAMES = 8;
|
||||
public const int NB_TBANDS = 18;
|
||||
public const int NB_TOT_BANDS = 21;
|
||||
public const int NB_TONAL_SKIP_BANDS = 9;
|
||||
public const int ANALYSIS_BUF_SIZE = 720; /* 15 ms at 48 kHz */
|
||||
public const int DETECT_SIZE = 200;
|
||||
|
||||
public const int MAX_ENCODER_BUFFER = 480;
|
||||
}
|
||||
}
|
||||
46
Libraries/Concentus/CSharp/Concentus/Opus/OpusException.cs
Normal file
46
Libraries/Concentus/CSharp/Concentus/Opus/OpusException.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
/* Copyright (c) 2016 Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
public class OpusException : Exception
|
||||
{
|
||||
public OpusException() : base() { }
|
||||
public OpusException(string message) : base(message) { }
|
||||
public OpusException(string message, int opus_error_code) : base(message + ": " + CodecHelpers.opus_strerror(opus_error_code)) { }
|
||||
}
|
||||
}
|
||||
99
Libraries/Concentus/CSharp/Concentus/Opus/OpusMultistream.cs
Normal file
99
Libraries/Concentus/CSharp/Concentus/Opus/OpusMultistream.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Structs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
internal static class OpusMultistream
|
||||
{
|
||||
internal static int validate_layout(ChannelLayout layout)
|
||||
{
|
||||
int i, max_channel;
|
||||
|
||||
max_channel = layout.nb_streams + layout.nb_coupled_streams;
|
||||
if (max_channel > 255)
|
||||
return 0;
|
||||
for (i = 0; i < layout.nb_channels; i++)
|
||||
{
|
||||
if (layout.mapping[i] >= max_channel && layout.mapping[i] != 255)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
internal static int get_left_channel(ChannelLayout layout, int stream_id, int prev)
|
||||
{
|
||||
int i;
|
||||
i = (prev < 0) ? 0 : prev + 1;
|
||||
for (; i < layout.nb_channels; i++)
|
||||
{
|
||||
if (layout.mapping[i] == stream_id * 2)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal static int get_right_channel(ChannelLayout layout, int stream_id, int prev)
|
||||
{
|
||||
int i;
|
||||
i = (prev < 0) ? 0 : prev + 1;
|
||||
for (; i < layout.nb_channels; i++)
|
||||
{
|
||||
if (layout.mapping[i] == stream_id * 2 + 1)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal static int get_mono_channel(ChannelLayout layout, int stream_id, int prev)
|
||||
{
|
||||
int i;
|
||||
i = (prev < 0) ? 0 : prev + 1;
|
||||
for (; i < layout.nb_channels; i++)
|
||||
{
|
||||
if (layout.mapping[i] == stream_id + layout.nb_coupled_streams)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
internal class ChannelLayout
|
||||
{
|
||||
internal int nb_channels;
|
||||
internal int nb_streams;
|
||||
internal int nb_coupled_streams;
|
||||
internal readonly byte[] mapping = new byte[256];
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
nb_channels = 0;
|
||||
nb_streams = 0;
|
||||
nb_coupled_streams = 0;
|
||||
Arrays.MemSetByte(mapping, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Libraries/Concentus/CSharp/Concentus/Opus/Structs/MLP.cs
Normal file
52
Libraries/Concentus/CSharp/Concentus/Opus/Structs/MLP.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
/* Copyright (c) 2008-2011 Octasic Inc.
|
||||
Originally written by Jean-Marc Valin
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
/// <summary>
|
||||
/// state object for multi-layer perceptron
|
||||
/// </summary>
|
||||
internal class MLP
|
||||
{
|
||||
internal int layers;
|
||||
internal int[] topo;
|
||||
internal float[] weights;
|
||||
}
|
||||
}
|
||||
933
Libraries/Concentus/CSharp/Concentus/Opus/Structs/OpusDecoder.cs
Normal file
933
Libraries/Concentus/CSharp/Concentus/Opus/Structs/OpusDecoder.cs
Normal file
@@ -0,0 +1,933 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Celt;
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using Concentus.Silk;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
/// <summary>
|
||||
/// The Opus decoder structure.
|
||||
///
|
||||
/// Opus is a stateful codec with overlapping blocks and as a result Opus
|
||||
/// packets are not coded independently of each other. Packets must be
|
||||
/// passed into the decoder serially and in the correct order for a correct
|
||||
/// decode. Lost packets can be replaced with loss concealment by calling
|
||||
/// the decoder with a null reference and zero length for the missing packet.
|
||||
///
|
||||
/// A single codec state may only be accessed from a single thread at
|
||||
/// a time and any required locking must be performed by the caller. Separate
|
||||
/// streams must be decoded with separate decoder states and can be decoded
|
||||
/// in parallel.
|
||||
/// </summary>
|
||||
public class OpusDecoder
|
||||
{
|
||||
internal int channels;
|
||||
internal int Fs; /** Sampling rate (at the API level) */
|
||||
internal readonly DecControlState DecControl = new DecControlState();
|
||||
internal int decode_gain;
|
||||
|
||||
/* Everything beyond this point gets cleared on a reset */
|
||||
internal int stream_channels;
|
||||
internal OpusBandwidth bandwidth;
|
||||
internal OpusMode mode;
|
||||
internal OpusMode prev_mode;
|
||||
internal int frame_size;
|
||||
internal int prev_redundancy;
|
||||
internal int last_packet_duration;
|
||||
internal uint rangeFinal;
|
||||
internal SilkDecoder SilkDecoder = new SilkDecoder();
|
||||
internal CeltDecoder Celt_Decoder = new CeltDecoder();
|
||||
|
||||
// Used by multistream decoder
|
||||
internal OpusDecoder() { }
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
channels = 0;
|
||||
Fs = 0; /* Sampling rate (at the API level) */
|
||||
DecControl.Reset();
|
||||
decode_gain = 0;
|
||||
PartialReset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OPUS_DECODER_RESET_START
|
||||
/// </summary>
|
||||
internal void PartialReset()
|
||||
{
|
||||
stream_channels = 0;
|
||||
bandwidth = 0;
|
||||
mode = 0;
|
||||
prev_mode = 0;
|
||||
frame_size = 0;
|
||||
prev_redundancy = 0;
|
||||
last_packet_duration = 0;
|
||||
rangeFinal = 0;
|
||||
// fixme: do these get reset here? I don't think they do because init_celt and init_silk should both call RESET_STATE on their respective states
|
||||
//SilkDecoder.Reset();
|
||||
//CeltDecoder.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deprecated. Just use the regular constructor
|
||||
/// </summary>
|
||||
public static OpusDecoder Create(int Fs, int channels)
|
||||
{
|
||||
return new OpusDecoder(Fs, channels);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates and initializes a decoder state.
|
||||
/// Internally Opus stores data at 48000 Hz, so that should be the default
|
||||
/// value for Fs. However, the decoder can efficiently decode to buffers
|
||||
/// at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
|
||||
/// data at the full sample rate, or knows the compressed data doesn't
|
||||
/// use the full frequency range, it can request decoding at a reduced
|
||||
/// rate. Likewise, the decoder is capable of filling in either mono or
|
||||
/// interleaved stereo pcm buffers, at the caller's request.
|
||||
/// </summary>
|
||||
/// <param name="Fs">Sample rate to decode at (Hz). This must be one of 8000, 12000, 16000, 24000, or 48000.</param>
|
||||
/// <param name="channels">Number of channels (1 or 2) to decode</param>
|
||||
/// <returns>The created encoder</returns>
|
||||
public OpusDecoder(int Fs, int channels)
|
||||
{
|
||||
int ret;
|
||||
if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000))
|
||||
{
|
||||
throw new ArgumentException("Sample rate is invalid (must be 8/12/16/24/48 Khz)");
|
||||
}
|
||||
if (channels != 1 && channels != 2)
|
||||
{
|
||||
throw new ArgumentException("Number of channels must be 1 or 2");
|
||||
}
|
||||
|
||||
ret = this.opus_decoder_init(Fs, channels);
|
||||
if (ret != OpusError.OPUS_OK)
|
||||
{
|
||||
if (ret == OpusError.OPUS_BAD_ARG)
|
||||
throw new ArgumentException("OPUS_BAD_ARG when creating decoder");
|
||||
throw new OpusException("Error while initializing decoder", ret);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initializes a previously allocated decoder state.
|
||||
* The state must be at least the size returned by opus_decoder_get_size().
|
||||
* This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
|
||||
* To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusDecoder*</tt>: Decoder state.
|
||||
* @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz).
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
|
||||
* @retval #OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
internal int opus_decoder_init(int Fs, int channels)
|
||||
{
|
||||
SilkDecoder silk_dec;
|
||||
CeltDecoder celt_dec;
|
||||
int ret;
|
||||
|
||||
if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000)
|
||||
|| (channels != 1 && channels != 2))
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
this.Reset();
|
||||
|
||||
/* Initialize SILK encoder */
|
||||
silk_dec = this.SilkDecoder;
|
||||
celt_dec = this.Celt_Decoder;
|
||||
this.stream_channels = this.channels = channels;
|
||||
|
||||
this.Fs = Fs;
|
||||
this.DecControl.API_sampleRate = this.Fs;
|
||||
this.DecControl.nChannelsAPI = this.channels;
|
||||
|
||||
/* Reset decoder */
|
||||
ret = DecodeAPI.silk_InitDecoder(silk_dec);
|
||||
if (ret != 0) return OpusError.OPUS_INTERNAL_ERROR;
|
||||
|
||||
/* Initialize CELT decoder */
|
||||
ret = celt_dec.celt_decoder_init(Fs, channels);
|
||||
if (ret != OpusError.OPUS_OK)
|
||||
return OpusError.OPUS_INTERNAL_ERROR;
|
||||
|
||||
celt_dec.SetSignalling(0);
|
||||
|
||||
this.prev_mode = 0;
|
||||
this.frame_size = Fs / 400;
|
||||
return OpusError.OPUS_OK;
|
||||
}
|
||||
|
||||
private static readonly byte[] SILENCE = { 0xFF, 0xFF };
|
||||
|
||||
internal int opus_decode_frame(byte[] data, int data_ptr,
|
||||
int len, short[] pcm, int pcm_ptr, int frame_size, int decode_fec)
|
||||
{
|
||||
SilkDecoder silk_dec;
|
||||
CeltDecoder celt_dec;
|
||||
int i, silk_ret = 0, celt_ret = 0;
|
||||
EntropyCoder dec = new EntropyCoder(); // porting note: stack var
|
||||
int silk_frame_size;
|
||||
int pcm_silk_size;
|
||||
short[] pcm_silk;
|
||||
int pcm_transition_silk_size;
|
||||
short[] pcm_transition_silk;
|
||||
int pcm_transition_celt_size;
|
||||
short[] pcm_transition_celt;
|
||||
short[] pcm_transition = null;
|
||||
int redundant_audio_size;
|
||||
short[] redundant_audio;
|
||||
|
||||
int audiosize;
|
||||
OpusMode mode;
|
||||
int transition = 0;
|
||||
int start_band;
|
||||
int redundancy = 0;
|
||||
int redundancy_bytes = 0;
|
||||
int celt_to_silk = 0;
|
||||
int c;
|
||||
int F2_5, F5, F10, F20;
|
||||
int[] window;
|
||||
uint redundant_rng = 0;
|
||||
int celt_accum;
|
||||
|
||||
silk_dec = this.SilkDecoder;
|
||||
celt_dec = this.Celt_Decoder;
|
||||
F20 = this.Fs / 50;
|
||||
F10 = F20 >> 1;
|
||||
F5 = F10 >> 1;
|
||||
F2_5 = F5 >> 1;
|
||||
if (frame_size < F2_5)
|
||||
{
|
||||
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
/* Limit frame_size to avoid excessive stack allocations. */
|
||||
frame_size = Inlines.IMIN(frame_size, this.Fs / 25 * 3);
|
||||
/* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
|
||||
if (len <= 1)
|
||||
{
|
||||
data = null;
|
||||
/* In that case, don't conceal more than what the ToC says */
|
||||
frame_size = Inlines.IMIN(frame_size, this.frame_size);
|
||||
}
|
||||
if (data != null)
|
||||
{
|
||||
audiosize = this.frame_size;
|
||||
mode = this.mode;
|
||||
dec.dec_init(data, data_ptr, (uint)len);
|
||||
}
|
||||
else {
|
||||
audiosize = frame_size;
|
||||
mode = this.prev_mode;
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
/* If we haven't got any packet yet, all we can do is return zeros */
|
||||
for (i = pcm_ptr; i < pcm_ptr + (audiosize * this.channels); i++)
|
||||
pcm[i] = 0;
|
||||
|
||||
return audiosize;
|
||||
}
|
||||
|
||||
/* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
|
||||
10, or 20 (e.g. 12.5 or 30 ms). */
|
||||
if (audiosize > F20)
|
||||
{
|
||||
do
|
||||
{
|
||||
int ret = opus_decode_frame(null, 0, 0, pcm, pcm_ptr, Inlines.IMIN(audiosize, F20), 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
|
||||
return ret;
|
||||
}
|
||||
pcm_ptr += ret * this.channels;
|
||||
audiosize -= ret;
|
||||
} while (audiosize > 0);
|
||||
|
||||
return frame_size;
|
||||
}
|
||||
else if (audiosize < F20)
|
||||
{
|
||||
if (audiosize > F10)
|
||||
audiosize = F10;
|
||||
else if (mode != OpusMode.MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
|
||||
audiosize = F5;
|
||||
}
|
||||
}
|
||||
|
||||
/* In fixed-point, we can tell CELT to do the accumulation on top of the
|
||||
SILK PCM buffer. This saves some stack space. */
|
||||
celt_accum = ((mode != OpusMode.MODE_CELT_ONLY) && (frame_size >= F10)) ? 1 : 0;
|
||||
|
||||
pcm_transition_silk_size = 0;
|
||||
pcm_transition_celt_size = 0;
|
||||
if (data != null && this.prev_mode > 0 && (
|
||||
(mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY && (this.prev_redundancy == 0))
|
||||
|| (mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY))
|
||||
)
|
||||
{
|
||||
transition = 1;
|
||||
/* Decide where to allocate the stack memory for pcm_transition */
|
||||
if (mode == OpusMode.MODE_CELT_ONLY)
|
||||
pcm_transition_celt_size = F5 * this.channels;
|
||||
else
|
||||
pcm_transition_silk_size = F5 * this.channels;
|
||||
}
|
||||
pcm_transition_celt = new short[pcm_transition_celt_size];
|
||||
if (transition != 0 && mode == OpusMode.MODE_CELT_ONLY)
|
||||
{
|
||||
pcm_transition = pcm_transition_celt;
|
||||
opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0);
|
||||
}
|
||||
if (audiosize > frame_size)
|
||||
{
|
||||
/*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
|
||||
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
}
|
||||
else {
|
||||
frame_size = audiosize;
|
||||
}
|
||||
|
||||
/* Don't allocate any memory when in CELT-only mode */
|
||||
pcm_silk_size = (mode != OpusMode.MODE_CELT_ONLY && (celt_accum == 0)) ? Inlines.IMAX(F10, frame_size) * this.channels : 0;
|
||||
pcm_silk = new short[pcm_silk_size];
|
||||
|
||||
/* SILK processing */
|
||||
if (mode != OpusMode.MODE_CELT_ONLY)
|
||||
{
|
||||
int lost_flag, decoded_samples;
|
||||
short[] pcm_ptr2;
|
||||
int pcm_ptr2_ptr = 0;
|
||||
|
||||
if (celt_accum != 0)
|
||||
{
|
||||
pcm_ptr2 = pcm;
|
||||
pcm_ptr2_ptr = pcm_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcm_ptr2 = pcm_silk;
|
||||
pcm_ptr2_ptr = 0;
|
||||
}
|
||||
|
||||
if (this.prev_mode == OpusMode.MODE_CELT_ONLY)
|
||||
DecodeAPI.silk_InitDecoder(silk_dec);
|
||||
|
||||
/* The SILK PLC cannot produce frames of less than 10 ms */
|
||||
this.DecControl.payloadSize_ms = Inlines.IMAX(10, 1000 * audiosize / this.Fs);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
this.DecControl.nChannelsInternal = this.stream_channels;
|
||||
if (mode == OpusMode.MODE_SILK_ONLY)
|
||||
{
|
||||
if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND)
|
||||
{
|
||||
this.DecControl.internalSampleRate = 8000;
|
||||
}
|
||||
else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)
|
||||
{
|
||||
this.DecControl.internalSampleRate = 12000;
|
||||
}
|
||||
else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)
|
||||
{
|
||||
this.DecControl.internalSampleRate = 16000;
|
||||
}
|
||||
else {
|
||||
this.DecControl.internalSampleRate = 16000;
|
||||
Inlines.OpusAssert(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Hybrid mode */
|
||||
this.DecControl.internalSampleRate = 16000;
|
||||
}
|
||||
}
|
||||
|
||||
lost_flag = data == null ? 1 : 2 * decode_fec;
|
||||
decoded_samples = 0;
|
||||
do
|
||||
{
|
||||
/* Call SILK decoder */
|
||||
int first_frame = (decoded_samples == 0) ? 1 : 0;
|
||||
silk_ret = DecodeAPI.silk_Decode(silk_dec, this.DecControl,
|
||||
lost_flag, first_frame, dec, pcm_ptr2, pcm_ptr2_ptr, out silk_frame_size);
|
||||
if (silk_ret != 0)
|
||||
{
|
||||
if (lost_flag != 0)
|
||||
{
|
||||
/* PLC failure should not be fatal */
|
||||
silk_frame_size = frame_size;
|
||||
Arrays.MemSetWithOffset<short>(pcm_ptr2, 0, pcm_ptr2_ptr, frame_size * this.channels);
|
||||
}
|
||||
else {
|
||||
|
||||
return OpusError.OPUS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
pcm_ptr2_ptr += (silk_frame_size * this.channels);
|
||||
decoded_samples += silk_frame_size;
|
||||
} while (decoded_samples < frame_size);
|
||||
}
|
||||
|
||||
start_band = 0;
|
||||
if (decode_fec == 0 && mode != OpusMode.MODE_CELT_ONLY && data != null
|
||||
&& dec.tell() + 17 + 20 * (this.mode == OpusMode.MODE_HYBRID ? 1 : 0) <= 8 * len)
|
||||
{
|
||||
/* Check if we have a redundant 0-8 kHz band */
|
||||
if (mode == OpusMode.MODE_HYBRID)
|
||||
redundancy = dec.dec_bit_logp(12);
|
||||
else
|
||||
redundancy = 1;
|
||||
if (redundancy != 0)
|
||||
{
|
||||
celt_to_silk = dec.dec_bit_logp(1);
|
||||
/* redundancy_bytes will be at least two, in the non-hybrid
|
||||
case due to the ec_tell() check above */
|
||||
redundancy_bytes = mode == OpusMode.MODE_HYBRID ?
|
||||
(int)dec.dec_uint(256) + 2 :
|
||||
len - ((dec.tell() + 7) >> 3);
|
||||
len -= redundancy_bytes;
|
||||
/* This is a sanity check. It should never happen for a valid
|
||||
packet, so the exact behaviour is not normative. */
|
||||
if (len * 8 < dec.tell())
|
||||
{
|
||||
len = 0;
|
||||
redundancy_bytes = 0;
|
||||
redundancy = 0;
|
||||
}
|
||||
/* Shrink decoder because of raw bits */
|
||||
dec.storage = (uint)(dec.storage - redundancy_bytes);
|
||||
}
|
||||
}
|
||||
if (mode != OpusMode.MODE_CELT_ONLY)
|
||||
start_band = 17;
|
||||
|
||||
{
|
||||
int endband = 21;
|
||||
|
||||
switch (this.bandwidth)
|
||||
{
|
||||
case OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND:
|
||||
endband = 13;
|
||||
break;
|
||||
case OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND:
|
||||
case OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND:
|
||||
endband = 17;
|
||||
break;
|
||||
case OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND:
|
||||
endband = 19;
|
||||
break;
|
||||
case OpusBandwidth.OPUS_BANDWIDTH_FULLBAND:
|
||||
endband = 21;
|
||||
break;
|
||||
}
|
||||
celt_dec.SetEndBand(endband);
|
||||
celt_dec.SetChannels(this.stream_channels);
|
||||
}
|
||||
|
||||
if (redundancy != 0)
|
||||
{
|
||||
transition = 0;
|
||||
pcm_transition_silk_size = 0;
|
||||
}
|
||||
|
||||
pcm_transition_silk = new short[pcm_transition_silk_size];
|
||||
|
||||
if (transition != 0 && mode != OpusMode.MODE_CELT_ONLY)
|
||||
{
|
||||
pcm_transition = pcm_transition_silk;
|
||||
opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0);
|
||||
}
|
||||
|
||||
/* Only allocation memory for redundancy if/when needed */
|
||||
redundant_audio_size = redundancy != 0 ? F5 * this.channels : 0;
|
||||
redundant_audio = new short[redundant_audio_size];
|
||||
|
||||
/* 5 ms redundant frame for CELT->SILK*/
|
||||
if (redundancy != 0 && celt_to_silk != 0)
|
||||
{
|
||||
celt_dec.SetStartBand(0);
|
||||
celt_dec.celt_decode_with_ec(data, (data_ptr + len), redundancy_bytes,
|
||||
redundant_audio, 0, F5, null, 0);
|
||||
redundant_rng = celt_dec.GetFinalRange();
|
||||
}
|
||||
|
||||
/* MUST be after PLC */
|
||||
celt_dec.SetStartBand(start_band);
|
||||
|
||||
if (mode != OpusMode.MODE_SILK_ONLY)
|
||||
{
|
||||
int celt_frame_size = Inlines.IMIN(F20, frame_size);
|
||||
/* Make sure to discard any previous CELT state */
|
||||
if (mode != this.prev_mode && this.prev_mode > 0 && this.prev_redundancy == 0)
|
||||
celt_dec.ResetState();
|
||||
/* Decode CELT */
|
||||
celt_ret = celt_dec.celt_decode_with_ec(decode_fec != 0 ? null : data, data_ptr,
|
||||
len, pcm, pcm_ptr, celt_frame_size, dec, celt_accum);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (celt_accum == 0)
|
||||
{
|
||||
for (i = pcm_ptr; i < (frame_size * this.channels) + pcm_ptr; i++)
|
||||
pcm[i] = 0;
|
||||
}
|
||||
/* For hybrid -> SILK transitions, we let the CELT MDCT
|
||||
do a fade-out by decoding a silence frame */
|
||||
if (this.prev_mode == OpusMode.MODE_HYBRID && !(redundancy != 0 && celt_to_silk != 0 && this.prev_redundancy != 0))
|
||||
{
|
||||
celt_dec.SetStartBand(0);
|
||||
celt_dec.celt_decode_with_ec(SILENCE, 0, 2, pcm, pcm_ptr, F2_5, null, celt_accum);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != OpusMode.MODE_CELT_ONLY && celt_accum == 0)
|
||||
{
|
||||
for (i = 0; i < frame_size * this.channels; i++)
|
||||
pcm[pcm_ptr + i] = Inlines.SAT16(Inlines.ADD32(pcm[pcm_ptr + i], pcm_silk[i]));
|
||||
}
|
||||
|
||||
window = celt_dec.GetMode().window;
|
||||
|
||||
/* 5 ms redundant frame for SILK->CELT */
|
||||
if (redundancy != 0 && celt_to_silk == 0)
|
||||
{
|
||||
celt_dec.ResetState();
|
||||
celt_dec.SetStartBand(0);
|
||||
|
||||
celt_dec.celt_decode_with_ec(data, data_ptr + len, redundancy_bytes, redundant_audio, 0, F5, null, 0);
|
||||
redundant_rng = celt_dec.GetFinalRange();
|
||||
CodecHelpers.smooth_fade(pcm, pcm_ptr + this.channels * (frame_size - F2_5), redundant_audio, this.channels * F2_5,
|
||||
pcm, (pcm_ptr + this.channels * (frame_size - F2_5)), F2_5, this.channels, window, this.Fs);
|
||||
}
|
||||
if (redundancy != 0 && celt_to_silk != 0)
|
||||
{
|
||||
for (c = 0; c < this.channels; c++)
|
||||
{
|
||||
for (i = 0; i < F2_5; i++)
|
||||
pcm[this.channels * i + c + pcm_ptr] = redundant_audio[this.channels * i + c];
|
||||
}
|
||||
CodecHelpers.smooth_fade(redundant_audio,(this.channels * F2_5), pcm,(pcm_ptr + (this.channels * F2_5)),
|
||||
pcm, (pcm_ptr + (this.channels * F2_5)), F2_5, this.channels, window, this.Fs);
|
||||
}
|
||||
if (transition != 0)
|
||||
{
|
||||
if (audiosize >= F5)
|
||||
{
|
||||
for (i = 0; i < this.channels * F2_5; i++)
|
||||
pcm[i] = pcm_transition[i];
|
||||
CodecHelpers.smooth_fade(pcm_transition, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)),
|
||||
pcm, (pcm_ptr + (this.channels * F2_5)), F2_5,
|
||||
this.channels, window, this.Fs);
|
||||
}
|
||||
else {
|
||||
/* Not enough time to do a clean transition, but we do it anyway
|
||||
This will not preserve amplitude perfectly and may introduce
|
||||
a bit of temporal aliasing, but it shouldn't be too bad and
|
||||
that's pretty much the best we can do. In any case, generating this
|
||||
transition is pretty silly in the first place */
|
||||
CodecHelpers.smooth_fade(pcm_transition, 0, pcm, pcm_ptr,
|
||||
pcm, pcm_ptr, F2_5,
|
||||
this.channels, window, this.Fs);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.decode_gain != 0)
|
||||
{
|
||||
int gain;
|
||||
gain = Inlines.celt_exp2(Inlines.MULT16_16_P15(((short)(0.5 + (6.48814081e-4f) * (((int)1) << (25))))/*Inlines.QCONST16(6.48814081e-4f, 25)*/, this.decode_gain));
|
||||
for (i = pcm_ptr; i < pcm_ptr + (frame_size * this.channels); i++)
|
||||
{
|
||||
int x;
|
||||
x = Inlines.MULT16_32_P16(pcm[i], gain);
|
||||
pcm[i] = (short)Inlines.SATURATE(x, 32767);
|
||||
}
|
||||
}
|
||||
|
||||
if (len <= 1)
|
||||
this.rangeFinal = 0;
|
||||
else
|
||||
this.rangeFinal = dec.rng ^ redundant_rng;
|
||||
|
||||
this.prev_mode = mode;
|
||||
this.prev_redundancy = (redundancy != 0 && celt_to_silk == 0) ? 1 : 0;
|
||||
|
||||
return celt_ret < 0 ? celt_ret : audiosize;
|
||||
}
|
||||
|
||||
internal int opus_decode_native(byte[] data, int data_ptr,
|
||||
int len, short[] pcm_out, int pcm_out_ptr, int frame_size, int decode_fec,
|
||||
int self_delimited, out int packet_offset, int soft_clip)
|
||||
{
|
||||
int i, nb_samples;
|
||||
int count, offset;
|
||||
byte toc;
|
||||
int packet_frame_size, packet_stream_channels;
|
||||
packet_offset = 0;
|
||||
OpusBandwidth packet_bandwidth;
|
||||
OpusMode packet_mode;
|
||||
/* 48 x 2.5 ms = 120 ms */
|
||||
// fixme: make sure these values can fit in an int16
|
||||
short[] size = new short[48];
|
||||
if (decode_fec < 0 || decode_fec > 1)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
/* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
|
||||
if ((decode_fec != 0 || len == 0 || data == null) && frame_size % (this.Fs / 400) != 0)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
if (len == 0 || data == null)
|
||||
{
|
||||
int pcm_count = 0;
|
||||
do
|
||||
{
|
||||
int ret;
|
||||
ret = opus_decode_frame(null, 0, 0, pcm_out, pcm_out_ptr + (pcm_count * this.channels), frame_size - pcm_count, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pcm_count += ret;
|
||||
} while (pcm_count < frame_size);
|
||||
Inlines.OpusAssert(pcm_count == frame_size);
|
||||
this.last_packet_duration = pcm_count;
|
||||
return pcm_count;
|
||||
}
|
||||
else if (len < 0)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
|
||||
packet_mode = OpusPacketInfo.GetEncoderMode(data, data_ptr);
|
||||
packet_bandwidth = OpusPacketInfo.GetBandwidth(data, data_ptr);
|
||||
packet_frame_size = OpusPacketInfo.GetNumSamplesPerFrame(data, data_ptr, this.Fs);
|
||||
packet_stream_channels = OpusPacketInfo.GetNumEncodedChannels(data, data_ptr);
|
||||
|
||||
count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, out toc, null, null, 0,
|
||||
size, 0, out offset, out packet_offset);
|
||||
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
data_ptr += offset;
|
||||
|
||||
if (decode_fec != 0)
|
||||
{
|
||||
int dummy;
|
||||
int duration_copy;
|
||||
int ret;
|
||||
/* If no FEC can be present, run the PLC (recursive call) */
|
||||
if (frame_size < packet_frame_size || packet_mode == OpusMode.MODE_CELT_ONLY || this.mode == OpusMode.MODE_CELT_ONLY)
|
||||
return opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size, 0, 0, out dummy, soft_clip);
|
||||
/* Otherwise, run the PLC on everything except the size for which we might have FEC */
|
||||
duration_copy = this.last_packet_duration;
|
||||
if (frame_size - packet_frame_size != 0)
|
||||
{
|
||||
ret = opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size - packet_frame_size, 0, 0, out dummy, soft_clip);
|
||||
if (ret < 0)
|
||||
{
|
||||
this.last_packet_duration = duration_copy;
|
||||
return ret;
|
||||
}
|
||||
Inlines.OpusAssert(ret == frame_size - packet_frame_size);
|
||||
}
|
||||
/* Complete with FEC */
|
||||
this.mode = packet_mode;
|
||||
this.bandwidth = packet_bandwidth;
|
||||
this.frame_size = packet_frame_size;
|
||||
this.stream_channels = packet_stream_channels;
|
||||
ret = opus_decode_frame(data, data_ptr, size[0], pcm_out, pcm_out_ptr + (this.channels * (frame_size - packet_frame_size)),
|
||||
packet_frame_size, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else {
|
||||
this.last_packet_duration = frame_size;
|
||||
return frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (count * packet_frame_size > frame_size)
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
|
||||
/* Update the state as the last step to avoid updating it on an invalid packet */
|
||||
this.mode = packet_mode;
|
||||
this.bandwidth = packet_bandwidth;
|
||||
this.frame_size = packet_frame_size;
|
||||
this.stream_channels = packet_stream_channels;
|
||||
|
||||
nb_samples = 0;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
int ret;
|
||||
ret = opus_decode_frame(data, data_ptr, size[i], pcm_out, pcm_out_ptr + (nb_samples * this.channels), frame_size - nb_samples, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
Inlines.OpusAssert(ret == packet_frame_size);
|
||||
data_ptr += size[i];
|
||||
nb_samples += ret;
|
||||
}
|
||||
this.last_packet_duration = nb_samples;
|
||||
|
||||
return nb_samples;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an Opus packet.
|
||||
/// </summary>
|
||||
/// <param name="in_data">The input payload. This may be NULL if that previous packet was lost in transit (when PLC is enabled)</param>
|
||||
/// <param name="in_data_offset">The offset to use when reading the input payload. Usually 0</param>
|
||||
/// <param name="len">The number of bytes in the payload</param>
|
||||
/// <param name="out_pcm">A buffer to put the output PCM. The output size is (# of samples) * (# of channels).
|
||||
/// You can use the OpusPacketInfo helpers to get a hint of the frame size before you decode the packet if you need
|
||||
/// exact sizing. Otherwise, the minimum safe buffer size is 5760 samples</param>
|
||||
/// <param name="out_pcm_offset">The offset to use when writing to the output buffer</param>
|
||||
/// <param name="frame_size">The number of samples (per channel) of available space in the output PCM buf.
|
||||
/// If this is less than the maximum packet duration (120ms; 5760 for 48khz), this function will
|
||||
/// not be capable of decoding some packets. In the case of PLC (data == NULL) or FEC (decode_fec == true),
|
||||
/// then frame_size needs to be exactly the duration of the audio that is missing, otherwise the decoder will
|
||||
/// not be in an optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size *must*
|
||||
/// be a multiple of 10 ms.</param>
|
||||
/// <param name="decode_fec">Indicates that we want to recreate the PREVIOUS (lost) packet using FEC data from THIS packet. Using this packet
|
||||
/// recovery scheme, you will actually decode this packet twice, first with decode_fec TRUE and then again with FALSE. If FEC data is not
|
||||
/// available in this packet, the decoder will simply generate a best-effort recreation of the lost packet.</param>
|
||||
/// <returns>The number of decoded samples</returns>
|
||||
public int Decode(byte[] in_data, int in_data_offset,
|
||||
int len, short[] out_pcm, int out_pcm_offset, int frame_size, bool decode_fec = false)
|
||||
{
|
||||
if (frame_size <= 0)
|
||||
{
|
||||
throw new ArgumentException("Frame size must be > 0");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int dummy;
|
||||
int ret = opus_decode_native(in_data, in_data_offset, len, out_pcm, out_pcm_offset, frame_size, decode_fec ? 1 : 0, 0, out dummy, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
// An error happened; report it
|
||||
if (ret == OpusError.OPUS_BAD_ARG)
|
||||
throw new ArgumentException("OPUS_BAD_ARG while decoding");
|
||||
throw new OpusException("An error occurred during decoding", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
throw new OpusException("Internal error during decoding: " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an Opus packet, putting the output data into a floating-point buffer.
|
||||
/// </summary>
|
||||
/// <param name="in_data">The input payload. This may be NULL if that previous packet was lost in transit (when PLC is enabled)</param>
|
||||
/// <param name="in_data_offset">The offset to use when reading the input payload. Usually 0</param>
|
||||
/// <param name="len">The number of bytes in the payload</param>
|
||||
/// <param name="out_pcm">A buffer to put the output PCM. The output size is (# of samples) * (# of channels).
|
||||
/// You can use the OpusPacketInfo helpers to get a hint of the frame size before you decode the packet if you need
|
||||
/// exact sizing. Otherwise, the minimum safe buffer size is 5760 samples</param>
|
||||
/// <param name="out_pcm_offset">The offset to use when writing to the output buffer</param>
|
||||
/// <param name="frame_size">The number of samples (per channel) of available space in the output PCM buf.
|
||||
/// If this is less than the maximum packet duration (120ms; 5760 for 48khz), this function will
|
||||
/// not be capable of decoding some packets. In the case of PLC (data == NULL) or FEC (decode_fec == true),
|
||||
/// then frame_size needs to be exactly the duration of the audio that is missing, otherwise the decoder will
|
||||
/// not be in an optimal state to decode the next incoming packet. For the PLC and FEC cases, frame_size *must*
|
||||
/// be a multiple of 10 ms.</param>
|
||||
/// <param name="decode_fec">Indicates that we want to recreate the PREVIOUS (lost) packet using FEC data from THIS packet. Using this packet
|
||||
/// recovery scheme, you will actually decode this packet twice, first with decode_fec TRUE and then again with FALSE. If FEC data is not
|
||||
/// available in this packet, the decoder will simply generate a best-effort recreation of the lost packet. In that case,
|
||||
/// the length of frame_size must be EXACTLY the length of the audio that was lost, or else the decoder will be in an inconsistent state.</param>
|
||||
/// <returns>The number of decoded samples (per channel)</returns>
|
||||
public int Decode(byte[] in_data, int in_data_offset,
|
||||
int len, float[] out_pcm, int out_pcm_offset, int frame_size, bool decode_fec = false)
|
||||
{
|
||||
short[] output;
|
||||
int ret, i;
|
||||
int nb_samples;
|
||||
|
||||
if (frame_size <= 0)
|
||||
{
|
||||
throw new ArgumentException("Frame size must be > 0");
|
||||
}
|
||||
if (in_data != null && len > 0 && !decode_fec)
|
||||
{
|
||||
nb_samples = OpusPacketInfo.GetNumSamples(this, in_data, in_data_offset, len);
|
||||
if (nb_samples > 0)
|
||||
frame_size = Inlines.IMIN(frame_size, nb_samples);
|
||||
else
|
||||
throw new OpusException("An invalid packet was provided (unable to parse # of samples)");
|
||||
}
|
||||
output = new short[frame_size * this.channels];
|
||||
|
||||
try
|
||||
{
|
||||
int dummy;
|
||||
ret = opus_decode_native(in_data, in_data_offset, len, output, 0, frame_size, decode_fec ? 1 : 0, 0, out dummy, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
// An error happened; report it
|
||||
if (ret == OpusError.OPUS_BAD_ARG)
|
||||
throw new ArgumentException("OPUS_BAD_ARG when decoding");
|
||||
throw new OpusException("An error occurred during decoding", ret);
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
for (i = 0; i < ret * this.channels; i++)
|
||||
out_pcm[out_pcm_offset + i] = (1.0f / 32768.0f) * (output[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
throw new OpusException("Internal error during decoding: " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the encoded bandwidth of the last packet decoded. This may be lower than the actual decoding sample rate,
|
||||
/// and is only an indicator of the encoded audio's quality
|
||||
/// </summary>
|
||||
public OpusBandwidth Bandwidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return bandwidth;
|
||||
}
|
||||
}
|
||||
|
||||
public uint FinalRange
|
||||
{
|
||||
get
|
||||
{
|
||||
return rangeFinal;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate that this decoder decodes to. Always constant for the lifetime of the decoder
|
||||
/// </summary>
|
||||
public int SampleRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return Fs;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels that this decoder decodes to. Always constant for the lifetime of the decoder.
|
||||
/// </summary>
|
||||
public int NumChannels
|
||||
{
|
||||
get
|
||||
{
|
||||
return channels;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last estimated pitch value of the decoded audio
|
||||
/// </summary>
|
||||
public int Pitch
|
||||
{
|
||||
get
|
||||
{
|
||||
if (prev_mode == OpusMode.MODE_CELT_ONLY)
|
||||
{
|
||||
return Celt_Decoder.GetPitch();
|
||||
}
|
||||
else
|
||||
return DecControl.prevPitchLag;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the gain (Q8) to use in decoding
|
||||
/// </summary>
|
||||
public int Gain
|
||||
{
|
||||
get
|
||||
{
|
||||
return decode_gain;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value < -32768 || value > 32767)
|
||||
{
|
||||
throw new ArgumentException("Gain must be within the range of a signed int16");
|
||||
}
|
||||
|
||||
decode_gain = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the last packet, in PCM samples per channel
|
||||
/// </summary>
|
||||
public int LastPacketDuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return last_packet_duration;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets all buffers and prepares this decoder to process a fresh (unrelated) stream
|
||||
/// </summary>
|
||||
public void ResetState()
|
||||
{
|
||||
PartialReset();
|
||||
Celt_Decoder.ResetState();
|
||||
DecodeAPI.silk_InitDecoder(SilkDecoder);
|
||||
stream_channels = channels;
|
||||
frame_size = Fs / 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
2050
Libraries/Concentus/CSharp/Concentus/Opus/Structs/OpusEncoder.cs
Normal file
2050
Libraries/Concentus/CSharp/Concentus/Opus/Structs/OpusEncoder.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,438 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using Concentus.Structs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
public class OpusMSDecoder
|
||||
{
|
||||
internal ChannelLayout layout = new ChannelLayout();
|
||||
internal OpusDecoder[] decoders = null;
|
||||
|
||||
private OpusMSDecoder(int nb_streams, int nb_coupled_streams)
|
||||
{
|
||||
decoders = new OpusDecoder[nb_streams];
|
||||
for (int c = 0; c < nb_streams; c++)
|
||||
decoders[c] = new OpusDecoder();
|
||||
}
|
||||
|
||||
#region API functions
|
||||
|
||||
internal int opus_multistream_decoder_init(
|
||||
int Fs,
|
||||
int channels,
|
||||
int streams,
|
||||
int coupled_streams,
|
||||
byte[] mapping
|
||||
)
|
||||
{
|
||||
int i, ret;
|
||||
int decoder_ptr = 0;
|
||||
|
||||
if ((channels > 255) || (channels < 1) || (coupled_streams > streams) ||
|
||||
(streams < 1) || (coupled_streams < 0) || (streams > 255 - coupled_streams))
|
||||
throw new ArgumentException("Invalid channel or coupled stream count");
|
||||
|
||||
this.layout.nb_channels = channels;
|
||||
this.layout.nb_streams = streams;
|
||||
this.layout.nb_coupled_streams = coupled_streams;
|
||||
|
||||
for (i = 0; i < this.layout.nb_channels; i++)
|
||||
this.layout.mapping[i] = mapping[i];
|
||||
if (OpusMultistream.validate_layout(this.layout) == 0)
|
||||
throw new ArgumentException("Invalid surround channel layout");
|
||||
|
||||
for (i = 0; i < this.layout.nb_coupled_streams; i++)
|
||||
{
|
||||
ret = this.decoders[decoder_ptr].opus_decoder_init(Fs, 2);
|
||||
if (ret != OpusError.OPUS_OK) return ret;
|
||||
decoder_ptr++;
|
||||
}
|
||||
for (; i < this.layout.nb_streams; i++)
|
||||
{
|
||||
ret = this.decoders[decoder_ptr].opus_decoder_init(Fs, 1);
|
||||
if (ret != OpusError.OPUS_OK) return ret;
|
||||
decoder_ptr++;
|
||||
}
|
||||
return OpusError.OPUS_OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new multichannel decoder
|
||||
/// </summary>
|
||||
/// <param name="Fs"></param>
|
||||
/// <param name="channels"></param>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="coupled_streams"></param>
|
||||
/// <param name="mapping">A mapping family (just use { 0, 1, 255 })</param>
|
||||
/// <returns></returns>
|
||||
public OpusMSDecoder(
|
||||
int Fs,
|
||||
int channels,
|
||||
int streams,
|
||||
int coupled_streams,
|
||||
byte[] mapping) : this(streams, coupled_streams)
|
||||
{
|
||||
int ret;
|
||||
if ((channels > 255) || (channels < 1) || (coupled_streams > streams) ||
|
||||
(streams < 1) || (coupled_streams < 0) || (streams > 255 - coupled_streams))
|
||||
{
|
||||
throw new ArgumentException("Invalid channel / stream configuration");
|
||||
}
|
||||
|
||||
ret = this.opus_multistream_decoder_init(Fs, channels, streams, coupled_streams, mapping);
|
||||
if (ret != OpusError.OPUS_OK)
|
||||
{
|
||||
if (ret == OpusError.OPUS_BAD_ARG)
|
||||
throw new ArgumentException("Bad argument while creating MS decoder");
|
||||
throw new OpusException("Could not create MS decoder", ret);
|
||||
}
|
||||
}
|
||||
|
||||
internal delegate void opus_copy_channel_out_func<T>(
|
||||
T[] dst,
|
||||
int dst_ptr,
|
||||
int dst_stride,
|
||||
int dst_channel,
|
||||
short[] src,
|
||||
int src_ptr,
|
||||
int src_stride,
|
||||
int frame_size
|
||||
);
|
||||
|
||||
internal static int opus_multistream_packet_validate(byte[] data, int data_ptr,
|
||||
int len, int nb_streams, int Fs)
|
||||
{
|
||||
int s;
|
||||
int count;
|
||||
byte toc;
|
||||
short[] size = new short[48];
|
||||
int samples = 0;
|
||||
int packet_offset;
|
||||
int dummy;
|
||||
|
||||
for (s = 0; s < nb_streams; s++)
|
||||
{
|
||||
int tmp_samples;
|
||||
if (len <= 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
|
||||
count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, (s != nb_streams - 1) ? 1 : 0, out toc, null, null, 0,
|
||||
size, 0, out dummy, out packet_offset);
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
tmp_samples = OpusPacketInfo.GetNumSamples(data, data_ptr, packet_offset, Fs);
|
||||
if (s != 0 && samples != tmp_samples)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
samples = tmp_samples;
|
||||
data_ptr += packet_offset;
|
||||
len -= packet_offset;
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
internal int opus_multistream_decode_native<T>(
|
||||
byte[] data,
|
||||
int data_ptr,
|
||||
int len,
|
||||
T[] pcm,
|
||||
int pcm_ptr,
|
||||
opus_copy_channel_out_func<T> copy_channel_out,
|
||||
int frame_size,
|
||||
int decode_fec,
|
||||
int soft_clip
|
||||
)
|
||||
{
|
||||
int Fs;
|
||||
int s, c;
|
||||
int decoder_ptr;
|
||||
int do_plc = 0;
|
||||
short[] buf;
|
||||
|
||||
/* Limit frame_size to avoid excessive stack allocations. */
|
||||
Fs = this.SampleRate;
|
||||
frame_size = Inlines.IMIN(frame_size, Fs / 25 * 3);
|
||||
buf = new short[2 * frame_size];
|
||||
decoder_ptr = 0;
|
||||
|
||||
if (len == 0)
|
||||
do_plc = 1;
|
||||
if (len < 0)
|
||||
{
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
}
|
||||
if (do_plc == 0 && len < 2 * this.layout.nb_streams - 1)
|
||||
{
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
}
|
||||
if (do_plc == 0)
|
||||
{
|
||||
int ret = opus_multistream_packet_validate(data, data_ptr, len, this.layout.nb_streams, Fs);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
else if (ret > frame_size)
|
||||
{
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
for (s = 0; s < this.layout.nb_streams; s++)
|
||||
{
|
||||
OpusDecoder dec;
|
||||
int ret;
|
||||
|
||||
dec = this.decoders[decoder_ptr++];
|
||||
|
||||
if (do_plc == 0 && len <= 0)
|
||||
{
|
||||
return OpusError.OPUS_INTERNAL_ERROR;
|
||||
}
|
||||
int packet_offset;
|
||||
ret = dec.opus_decode_native(
|
||||
data, data_ptr, len, buf, 0, frame_size, decode_fec,
|
||||
(s != this.layout.nb_streams - 1) ? 1 : 0, out packet_offset, soft_clip);
|
||||
data_ptr += packet_offset;
|
||||
len -= packet_offset;
|
||||
if (ret <= 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
frame_size = ret;
|
||||
if (s < this.layout.nb_coupled_streams)
|
||||
{
|
||||
int chan, prev;
|
||||
prev = -1;
|
||||
/* Copy "left" audio to the channel(s) where it belongs */
|
||||
while ((chan = OpusMultistream.get_left_channel(this.layout, s, prev)) != -1)
|
||||
{
|
||||
copy_channel_out(pcm, pcm_ptr, this.layout.nb_channels, chan,
|
||||
buf, 0, 2, frame_size);
|
||||
prev = chan;
|
||||
}
|
||||
prev = -1;
|
||||
/* Copy "right" audio to the channel(s) where it belongs */
|
||||
while ((chan = OpusMultistream.get_right_channel(this.layout, s, prev)) != -1)
|
||||
{
|
||||
copy_channel_out(pcm, pcm_ptr, this.layout.nb_channels, chan,
|
||||
buf, 1, 2, frame_size);
|
||||
prev = chan;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int chan, prev;
|
||||
prev = -1;
|
||||
/* Copy audio to the channel(s) where it belongs */
|
||||
while ((chan = OpusMultistream.get_mono_channel(this.layout, s, prev)) != -1)
|
||||
{
|
||||
copy_channel_out(pcm, pcm_ptr, this.layout.nb_channels, chan,
|
||||
buf, 0, 1, frame_size);
|
||||
prev = chan;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Handle muted channels */
|
||||
for (c = 0; c < this.layout.nb_channels; c++)
|
||||
{
|
||||
if (this.layout.mapping[c] == 255)
|
||||
{
|
||||
copy_channel_out(pcm, pcm_ptr, this.layout.nb_channels, c,
|
||||
null, 0, 0, frame_size);
|
||||
}
|
||||
}
|
||||
|
||||
return frame_size;
|
||||
}
|
||||
|
||||
internal static void opus_copy_channel_out_float(
|
||||
float[] dst,
|
||||
int dst_ptr,
|
||||
int dst_stride,
|
||||
int dst_channel,
|
||||
short[] src,
|
||||
int src_ptr,
|
||||
int src_stride,
|
||||
int frame_size
|
||||
)
|
||||
{
|
||||
int i;
|
||||
if (src != null)
|
||||
{
|
||||
for (i = 0; i < frame_size; i++)
|
||||
dst[i * dst_stride + dst_channel + dst_ptr] = (1 / 32768.0f) * src[i * src_stride + src_ptr];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < frame_size; i++)
|
||||
dst[i * dst_stride + dst_channel + dst_ptr] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void opus_copy_channel_out_short(
|
||||
short[] dst,
|
||||
int dst_ptr,
|
||||
int dst_stride,
|
||||
int dst_channel,
|
||||
short[] src,
|
||||
int src_ptr,
|
||||
int src_stride,
|
||||
int frame_size
|
||||
)
|
||||
{
|
||||
int i;
|
||||
if (src != null)
|
||||
{
|
||||
for (i = 0; i < frame_size; i++)
|
||||
dst[i * dst_stride + dst_channel + dst_ptr] = src[i * src_stride + src_ptr];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < frame_size; i++)
|
||||
dst[i * dst_stride + dst_channel + dst_ptr] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int DecodeMultistream(
|
||||
byte[] data,
|
||||
int data_offset,
|
||||
int len,
|
||||
short[] out_pcm,
|
||||
int out_pcm_offset,
|
||||
int frame_size,
|
||||
int decode_fec
|
||||
)
|
||||
{
|
||||
return opus_multistream_decode_native<short>(data, data_offset, len,
|
||||
out_pcm, out_pcm_offset, opus_copy_channel_out_short, frame_size, decode_fec, 0);
|
||||
}
|
||||
|
||||
public int DecodeMultistream(byte[] data, int data_offset,
|
||||
int len, float[] out_pcm, int out_pcm_offset, int frame_size, int decode_fec)
|
||||
{
|
||||
return opus_multistream_decode_native<float>(data, data_offset, len,
|
||||
out_pcm, out_pcm_offset, opus_copy_channel_out_float, frame_size, decode_fec, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Getters and setters
|
||||
|
||||
public OpusBandwidth Bandwidth
|
||||
{
|
||||
get
|
||||
{
|
||||
if (decoders == null || decoders.Length == 0)
|
||||
throw new InvalidOperationException("Decoder not initialized");
|
||||
return decoders[0].Bandwidth;
|
||||
}
|
||||
}
|
||||
|
||||
public int SampleRate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (decoders == null || decoders.Length == 0)
|
||||
throw new InvalidOperationException("Decoder not initialized");
|
||||
return decoders[0].SampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
public int Gain
|
||||
{
|
||||
get
|
||||
{
|
||||
if (decoders == null || decoders.Length == 0)
|
||||
return OpusError.OPUS_INVALID_STATE;
|
||||
return decoders[0].Gain;
|
||||
}
|
||||
set
|
||||
{
|
||||
for (int s = 0; s < layout.nb_streams; s++)
|
||||
{
|
||||
decoders[s].Gain = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int LastPacketDuration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (decoders == null || decoders.Length == 0)
|
||||
return OpusError.OPUS_INVALID_STATE;
|
||||
return decoders[0].LastPacketDuration;
|
||||
}
|
||||
}
|
||||
|
||||
public uint FinalRange
|
||||
{
|
||||
get
|
||||
{
|
||||
uint value = 0;
|
||||
for (int s = 0; s < layout.nb_streams; s++)
|
||||
{
|
||||
value ^= decoders[s].FinalRange;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
for (int s = 0; s < layout.nb_streams; s++)
|
||||
{
|
||||
decoders[s].ResetState();
|
||||
}
|
||||
}
|
||||
|
||||
public OpusDecoder GetMultistreamDecoderState(int streamId)
|
||||
{
|
||||
return decoders[streamId];
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1168
Libraries/Concentus/CSharp/Concentus/Opus/Structs/OpusMSEncoder.cs
Normal file
1168
Libraries/Concentus/CSharp/Concentus/Opus/Structs/OpusMSEncoder.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,470 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
public class OpusPacketInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The Table of Contents byte for this packet. Contains info about modes, frame length, etc.
|
||||
/// </summary>
|
||||
public readonly byte TOCByte;
|
||||
|
||||
/// <summary>
|
||||
/// The list of subframes in this packet
|
||||
/// </summary>
|
||||
public readonly IList<byte[]> Frames;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the start of the payload within the packet
|
||||
/// </summary>
|
||||
public readonly int PayloadOffset;
|
||||
|
||||
private OpusPacketInfo(byte toc, IList<byte[]> frames, int payloadOffset)
|
||||
{
|
||||
TOCByte = toc;
|
||||
Frames = frames;
|
||||
PayloadOffset = payloadOffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an opus packet into a packetinfo object containing one or more frames.
|
||||
/// Opus_decode will perform this operation internally so most applications do
|
||||
/// not need to use this function.
|
||||
/// </summary>
|
||||
/// <param name="packet">The packet data to be parsed</param>
|
||||
/// <param name="packet_offset">The index of the beginning of the packet in the data array (usually 0)</param>
|
||||
/// <param name="len">The packet's length</param>
|
||||
/// <returns>A parsed packet info struct</returns>
|
||||
public static OpusPacketInfo ParseOpusPacket(byte[] packet, int packet_offset, int len)
|
||||
{
|
||||
// Find the number of frames first
|
||||
int numFrames = GetNumFrames(packet, packet_offset, len);
|
||||
|
||||
int payload_offset;
|
||||
byte out_toc;
|
||||
byte[][] frames = new byte[numFrames][];
|
||||
int[] frames_ptrs = new int[numFrames];
|
||||
short[] size = new short[numFrames];
|
||||
int packetOffset;
|
||||
int error = opus_packet_parse_impl(packet, packet_offset, len, 0, out out_toc, frames, frames_ptrs, 0, size, 0, out payload_offset, out packetOffset);
|
||||
if (error < 0)
|
||||
{
|
||||
throw new OpusException("An error occurred while parsing the packet", error);
|
||||
}
|
||||
|
||||
IList<byte[]> copiedFrames = new List<byte[]>();
|
||||
|
||||
for (int c = 0; c < numFrames; c++)
|
||||
{
|
||||
byte[] nextFrame = new byte[size[c]];
|
||||
Array.Copy(frames[c], frames_ptrs[c], nextFrame, 0, nextFrame.Length);
|
||||
copiedFrames.Add(nextFrame);
|
||||
}
|
||||
|
||||
return new OpusPacketInfo(out_toc, copiedFrames, payload_offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of samples per frame from an Opus packet.
|
||||
/// </summary>
|
||||
/// <param name="packet">Opus packet. This must contain at least one byte of data</param>
|
||||
/// <param name="Fs">Sampling rate in Hz. This must be a multiple of 400, or inaccurate results will be returned.</param>
|
||||
/// <returns>Number of samples per frame</returns>
|
||||
public static int GetNumSamplesPerFrame(byte[] packet, int packet_offset, int Fs)
|
||||
{
|
||||
int audiosize;
|
||||
if ((packet[packet_offset] & 0x80) != 0)
|
||||
{
|
||||
audiosize = ((packet[packet_offset] >> 3) & 0x3);
|
||||
audiosize = (Fs << audiosize) / 400;
|
||||
}
|
||||
else if ((packet[packet_offset] & 0x60) == 0x60)
|
||||
{
|
||||
audiosize = ((packet[packet_offset] & 0x08) != 0) ? Fs / 50 : Fs / 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
audiosize = ((packet[packet_offset] >> 3) & 0x3);
|
||||
if (audiosize == 3)
|
||||
audiosize = Fs * 60 / 1000;
|
||||
else
|
||||
audiosize = (Fs << audiosize) / 100;
|
||||
}
|
||||
return audiosize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the encoded bandwidth of an Opus packet. Note that you are not forced to decode at this bandwidth
|
||||
/// </summary>
|
||||
/// <param name="packet">An Opus packet (must be at least 1 byte)</param>.
|
||||
/// <returns>An OpusBandwidth value</returns>
|
||||
public static OpusBandwidth GetBandwidth(byte[] packet, int packet_offset)
|
||||
{
|
||||
OpusBandwidth bandwidth;
|
||||
if ((packet[packet_offset] & 0x80) != 0)
|
||||
{
|
||||
bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND + ((packet[packet_offset] >> 5) & 0x3);
|
||||
if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)
|
||||
bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND;
|
||||
}
|
||||
else if ((packet[packet_offset] & 0x60) == 0x60)
|
||||
{
|
||||
bandwidth = ((packet[packet_offset] & 0x10) != 0) ? OpusBandwidth.OPUS_BANDWIDTH_FULLBAND :
|
||||
OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND;
|
||||
}
|
||||
else {
|
||||
bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND + ((packet[packet_offset] >> 5) & 0x3);
|
||||
}
|
||||
return bandwidth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of encoded channels of an Opus packet. Note that you are not forced to decode with this channel count.
|
||||
/// </summary>
|
||||
/// <param name="packet">An opus packet (must be at least 1 byte)</param>
|
||||
/// <returns>The number of channels</returns>
|
||||
public static int GetNumEncodedChannels(byte[] packet, int packet_offset)
|
||||
{
|
||||
return ((packet[packet_offset] & 0x4) != 0) ? 2 : 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of frames in an Opus packet.
|
||||
/// </summary>
|
||||
/// <param name="packet">An Opus packet</param>
|
||||
/// <param name="len">The packet's length (must be at least 1)</param>
|
||||
/// <returns>The number of frames in the packet</returns>
|
||||
public static int GetNumFrames(byte[] packet, int packet_offset, int len)
|
||||
{
|
||||
int count;
|
||||
if (len < 1)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
count = packet[packet_offset] & 0x3;
|
||||
if (count == 0)
|
||||
return 1;
|
||||
else if (count != 3)
|
||||
return 2;
|
||||
else if (len < 2)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
else
|
||||
return packet[packet_offset + 1] & 0x3F;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of samples of an Opus packet.
|
||||
/// </summary>
|
||||
/// <param name="packet">An Opus packet</param>
|
||||
/// <param name="len">The packet's length</param>
|
||||
/// <param name="Fs">The decoder's sampling rate in Hz. This must be a multiple of 400</param>
|
||||
/// <returns>The size of the PCM samples that this packet will be decoded to at the specified sample rate</returns>
|
||||
public static int GetNumSamples(byte[] packet, int packet_offset, int len,
|
||||
int Fs)
|
||||
{
|
||||
int samples;
|
||||
int count = GetNumFrames(packet, packet_offset, len);
|
||||
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
samples = count * GetNumSamplesPerFrame(packet, packet_offset, Fs);
|
||||
/* Can't have more than 120 ms */
|
||||
if (samples * 25 > Fs * 3)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
else
|
||||
return samples;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of samples of an Opus packet.
|
||||
/// </summary>
|
||||
/// <param name="dec">Your current decoder state</param>
|
||||
/// <param name="packet">An Opus packet</param>
|
||||
/// <param name="len">The packet's length</param>
|
||||
/// <returns>The size of the PCM samples that this packet will be decoded to by the specified decoder</returns>
|
||||
public static int GetNumSamples(OpusDecoder dec,
|
||||
byte[] packet, int packet_offset, int len)
|
||||
{
|
||||
return GetNumSamples(packet, packet_offset, len, dec.Fs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mode that was used to encode this packet.
|
||||
/// Normally there is nothing you can really do with this, other than debugging.
|
||||
/// </summary>
|
||||
/// <param name="packet">An Opus packet</param>
|
||||
/// <returns>The OpusMode used by the encoder</returns>
|
||||
public static OpusMode GetEncoderMode(byte[] packet, int packet_offset)
|
||||
{
|
||||
OpusMode mode;
|
||||
if ((packet[packet_offset] & 0x80) != 0)
|
||||
{
|
||||
mode = OpusMode.MODE_CELT_ONLY;
|
||||
}
|
||||
else if ((packet[packet_offset] & 0x60) == 0x60)
|
||||
{
|
||||
mode = OpusMode.MODE_HYBRID;
|
||||
}
|
||||
else {
|
||||
mode = OpusMode.MODE_SILK_ONLY;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
internal static int encode_size(int size, byte[] data, int data_ptr)
|
||||
{
|
||||
if (size < 252)
|
||||
{
|
||||
data[data_ptr] = (byte)size;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
data[data_ptr] = (byte)(252 + (size & 0x3));
|
||||
data[data_ptr + 1] = (byte)((size - (int)data[data_ptr]) >> 2);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
internal static int parse_size(byte[] data, int data_ptr, int len, BoxedValueShort size)
|
||||
{
|
||||
if (len < 1)
|
||||
{
|
||||
size.Val = -1;
|
||||
return -1;
|
||||
}
|
||||
else if (data[data_ptr] < 252)
|
||||
{
|
||||
size.Val = data[data_ptr];
|
||||
return 1;
|
||||
}
|
||||
else if (len < 2)
|
||||
{
|
||||
size.Val = -1;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
size.Val = (short)(4 * data[data_ptr + 1] + data[data_ptr]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
internal static int opus_packet_parse_impl(byte[] data, int data_ptr, int len,
|
||||
int self_delimited, out byte out_toc,
|
||||
byte[][] frames, int[] frames_ptrs, int frames_ptr, short[] sizes, int sizes_ptr,
|
||||
out int payload_offset, out int packet_offset)
|
||||
{
|
||||
int i, bytes;
|
||||
int count;
|
||||
int cbr;
|
||||
byte ch, toc;
|
||||
int framesize;
|
||||
int last_size;
|
||||
int pad = 0;
|
||||
int data0 = data_ptr;
|
||||
out_toc = 0;
|
||||
payload_offset = 0;
|
||||
packet_offset = 0;
|
||||
|
||||
if (sizes == null || len < 0)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
if (len == 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
|
||||
framesize = GetNumSamplesPerFrame(data, data_ptr, 48000);
|
||||
|
||||
cbr = 0;
|
||||
toc = data[data_ptr++];
|
||||
len--;
|
||||
last_size = len;
|
||||
switch (toc & 0x3)
|
||||
{
|
||||
/* One frame */
|
||||
case 0:
|
||||
count = 1;
|
||||
break;
|
||||
/* Two CBR frames */
|
||||
case 1:
|
||||
count = 2;
|
||||
cbr = 1;
|
||||
if (self_delimited == 0)
|
||||
{
|
||||
if ((len & 0x1) != 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
last_size = len / 2;
|
||||
/* If last_size doesn't fit in size[0], we'll catch it later */
|
||||
sizes[sizes_ptr] = (short)last_size;
|
||||
}
|
||||
break;
|
||||
/* Two VBR frames */
|
||||
case 2:
|
||||
count = 2;
|
||||
BoxedValueShort boxed_size = new BoxedValueShort(sizes[sizes_ptr]);
|
||||
bytes = parse_size(data, data_ptr, len, boxed_size);
|
||||
sizes[sizes_ptr] = boxed_size.Val;
|
||||
len -= bytes;
|
||||
if (sizes[sizes_ptr] < 0 || sizes[sizes_ptr] > len)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
data_ptr += bytes;
|
||||
last_size = len - sizes[sizes_ptr];
|
||||
break;
|
||||
/* Multiple CBR/VBR frames (from 0 to 120 ms) */
|
||||
default: /*case 3:*/
|
||||
if (len < 1)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
/* Number of frames encoded in bits 0 to 5 */
|
||||
ch = data[data_ptr++];
|
||||
count = ch & 0x3F;
|
||||
if (count <= 0 || framesize * count > 5760)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
len--;
|
||||
/* Padding flag is bit 6 */
|
||||
if ((ch & 0x40) != 0)
|
||||
{
|
||||
int p;
|
||||
do
|
||||
{
|
||||
int tmp;
|
||||
if (len <= 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
p = data[data_ptr++];
|
||||
len--;
|
||||
tmp = p == 255 ? 254 : p;
|
||||
len -= tmp;
|
||||
pad += tmp;
|
||||
} while (p == 255);
|
||||
}
|
||||
if (len < 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
/* VBR flag is bit 7 */
|
||||
cbr = (ch & 0x80) != 0 ? 0 : 1;
|
||||
if (cbr == 0)
|
||||
{
|
||||
/* VBR case */
|
||||
last_size = len;
|
||||
for (i = 0; i < count - 1; i++)
|
||||
{
|
||||
boxed_size = new BoxedValueShort(sizes[sizes_ptr + i]);
|
||||
bytes = parse_size(data, data_ptr, len, boxed_size);
|
||||
sizes[sizes_ptr + i] = boxed_size.Val;
|
||||
len -= bytes;
|
||||
if (sizes[sizes_ptr + i] < 0 || sizes[sizes_ptr + i] > len)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
data_ptr += bytes;
|
||||
last_size -= bytes + sizes[sizes_ptr + i];
|
||||
}
|
||||
if (last_size < 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
}
|
||||
else if (self_delimited == 0)
|
||||
{
|
||||
/* CBR case */
|
||||
last_size = len / count;
|
||||
if (last_size * count != len)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
for (i = 0; i < count - 1; i++)
|
||||
sizes[sizes_ptr + i] = (short)last_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Self-delimited framing has an extra size for the last frame. */
|
||||
if (self_delimited != 0)
|
||||
{
|
||||
BoxedValueShort boxed_size = new BoxedValueShort(sizes[sizes_ptr + count - 1]);
|
||||
bytes = parse_size(data, data_ptr, len, boxed_size);
|
||||
sizes[sizes_ptr + count - 1] = boxed_size.Val;
|
||||
len -= bytes;
|
||||
if (sizes[sizes_ptr + count - 1] < 0 || sizes[sizes_ptr + count - 1] > len)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
data_ptr += bytes;
|
||||
/* For CBR packets, apply the size to all the frames. */
|
||||
if (cbr != 0)
|
||||
{
|
||||
if (sizes[sizes_ptr + count - 1] * count > len)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
for (i = 0; i < count - 1; i++)
|
||||
sizes[sizes_ptr + i] = sizes[sizes_ptr + count - 1];
|
||||
}
|
||||
else if (bytes + sizes[sizes_ptr + count - 1] > last_size)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Because it's not encoded explicitly, it's possible the size of the
|
||||
last packet (or all the packets, for the CBR case) is larger than
|
||||
1275. Reject them here.*/
|
||||
if (last_size > 1275)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
sizes[sizes_ptr + count - 1] = (short)last_size;
|
||||
}
|
||||
|
||||
payload_offset = (int)(data_ptr - data0);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (frames != null)
|
||||
frames[frames_ptr + i] = data;
|
||||
if (frames_ptrs != null)
|
||||
frames_ptrs[frames_ptr + i] = data_ptr;
|
||||
data_ptr += sizes[sizes_ptr + i];
|
||||
}
|
||||
|
||||
packet_offset = pad + (int)(data_ptr - data0);
|
||||
|
||||
out_toc = toc;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// used internally
|
||||
//internal static int opus_packet_parse(byte[] data, int data_ptr, int len,
|
||||
// out byte out_toc, Pointer<Pointer<byte>> frames,
|
||||
// short[] size, int size_ptr, out int payload_offset)
|
||||
//{
|
||||
// int dummy;
|
||||
// return OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, 0, out out_toc,
|
||||
// frames, size, size_ptr, out payload_offset, out dummy);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,573 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
public class OpusRepacketizer
|
||||
{
|
||||
internal byte toc = 0;
|
||||
internal int nb_frames = 0;
|
||||
internal readonly byte[][] frames = new byte[48][];
|
||||
internal readonly int[] frames_ptrs = new int[48];
|
||||
internal readonly short[] len = new short[48];
|
||||
internal int framesize = 0;
|
||||
|
||||
/** (Re)initializes a previously allocated repacketizer state.
|
||||
* The state must be at least the size returned by opus_repacketizer_get_size().
|
||||
* This can be used for applications which use their own allocator instead of
|
||||
* malloc().
|
||||
* It must also be called to reset the queue of packets waiting to be
|
||||
* repacketized, which is necessary if the maximum packet duration of 120 ms
|
||||
* is reached or if you wish to submit packets with a different Opus
|
||||
* configuration (coding mode, audio bandwidth, frame size, or channel count).
|
||||
* Failure to do so will prevent a new packet from being added with
|
||||
* opus_repacketizer_cat().
|
||||
* @see opus_repacketizer_create
|
||||
* @see opus_repacketizer_get_size
|
||||
* @see opus_repacketizer_cat
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to
|
||||
* (re)initialize.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
this.nb_frames = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new repacketizer
|
||||
/// </summary>
|
||||
public OpusRepacketizer()
|
||||
{
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
internal int opus_repacketizer_cat_impl(byte[] data, int data_ptr, int len, int self_delimited)
|
||||
{
|
||||
byte dummy_toc;
|
||||
int dummy_offset;
|
||||
int curr_nb_frames, ret;
|
||||
/* Set of check ToC */
|
||||
if (len < 1)
|
||||
{
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
}
|
||||
|
||||
if (this.nb_frames == 0)
|
||||
{
|
||||
this.toc = data[data_ptr];
|
||||
this.framesize = OpusPacketInfo.GetNumSamplesPerFrame(data, data_ptr, 8000);
|
||||
}
|
||||
else if ((this.toc & 0xFC) != (data[data_ptr] & 0xFC))
|
||||
{
|
||||
/*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp.toc, data[0]);*/
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
}
|
||||
curr_nb_frames = OpusPacketInfo.GetNumFrames(data, data_ptr, len);
|
||||
if (curr_nb_frames < 1)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
|
||||
/* Check the 120 ms maximum packet size */
|
||||
if ((curr_nb_frames + this.nb_frames) * this.framesize > 960)
|
||||
{
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
}
|
||||
|
||||
ret = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, out dummy_toc, this.frames, this.frames_ptrs, this.nb_frames, this.len, this.nb_frames, out dummy_offset, out dummy_offset);
|
||||
if (ret < 1) return ret;
|
||||
|
||||
this.nb_frames += curr_nb_frames;
|
||||
return OpusError.OPUS_OK;
|
||||
}
|
||||
|
||||
/** opus_repacketizer_cat. Add a packet to the current repacketizer state.
|
||||
* This packet must match the configuration of any packets already submitted
|
||||
* for repacketization since the last call to opus_repacketizer_init().
|
||||
* This means that it must have the same coding mode, audio bandwidth, frame
|
||||
* size, and channel count.
|
||||
* This can be checked in advance by examining the top 6 bits of the first
|
||||
* byte of the packet, and ensuring they match the top 6 bits of the first
|
||||
* byte of any previously submitted packet.
|
||||
* The total duration of audio in the repacketizer state also must not exceed
|
||||
* 120 ms, the maximum duration of a single packet, after adding this packet.
|
||||
*
|
||||
* The contents of the current repacketizer state can be extracted into new
|
||||
* packets using opus_repacketizer_out() or opus_repacketizer_out_range().
|
||||
*
|
||||
* In order to add a packet with a different configuration or to add more
|
||||
* audio beyond 120 ms, you must clear the repacketizer state by calling
|
||||
* opus_repacketizer_init().
|
||||
* If a packet is too large to add to the current repacketizer state, no part
|
||||
* of it is added, even if it contains multiple frames, some of which might
|
||||
* fit.
|
||||
* If you wish to be able to add parts of such packets, you should first use
|
||||
* another repacketizer to split the packet into pieces and add them
|
||||
* individually.
|
||||
* @see opus_repacketizer_out_range
|
||||
* @see opus_repacketizer_out
|
||||
* @see opus_repacketizer_init
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to which to
|
||||
* add the packet.
|
||||
* @param[in] data <tt>const unsigned char*</tt>: The packet data.
|
||||
* The application must ensure
|
||||
* this pointer remains valid
|
||||
* until the next call to
|
||||
* opus_repacketizer_init() or
|
||||
* opus_repacketizer_destroy().
|
||||
* @param len <tt>opus_int32</tt>: The number of bytes in the packet data.
|
||||
* @returns An error code indicating whether or not the operation succeeded.
|
||||
* @retval #OPUS_OK The packet's contents have been added to the repacketizer
|
||||
* state.
|
||||
* @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
|
||||
* the packet's TOC sequence was not compatible
|
||||
* with previously submitted packets (because
|
||||
* the coding mode, audio bandwidth, frame size,
|
||||
* or channel count did not match), or adding
|
||||
* this packet would increase the total amount of
|
||||
* audio stored in the repacketizer state to more
|
||||
* than 120 ms.
|
||||
*/
|
||||
public int AddPacket(byte[] data, int data_offset, int len)
|
||||
{
|
||||
return opus_repacketizer_cat_impl(data, data_offset, len, 0);
|
||||
}
|
||||
|
||||
/** Return the total number of frames contained in packet data submitted to
|
||||
* the repacketizer state so far via opus_repacketizer_cat() since the last
|
||||
* call to opus_repacketizer_init() or opus_repacketizer_create().
|
||||
* This defines the valid range of packets that can be extracted with
|
||||
* opus_repacketizer_out_range() or opus_repacketizer_out().
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state containing the
|
||||
* frames.
|
||||
* @returns The total number of frames contained in the packet data submitted
|
||||
* to the repacketizer state.
|
||||
*/
|
||||
public int GetNumFrames()
|
||||
{
|
||||
return this.nb_frames;
|
||||
}
|
||||
|
||||
internal int opus_repacketizer_out_range_impl(int begin, int end,
|
||||
byte[] data, int data_ptr, int maxlen, int self_delimited, int pad)
|
||||
{
|
||||
int i, count;
|
||||
int tot_size;
|
||||
int ptr;
|
||||
|
||||
if (begin < 0 || begin >= end || end > this.nb_frames)
|
||||
{
|
||||
/*fprintf(stderr, "%d %d %d\n", begin, end, rp.nb_frames);*/
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
}
|
||||
count = end - begin;
|
||||
|
||||
if (self_delimited != 0)
|
||||
tot_size = 1 + (this.len[count - 1] >= 252 ? 1 : 0);
|
||||
else
|
||||
tot_size = 0;
|
||||
|
||||
ptr = data_ptr;
|
||||
if (count == 1)
|
||||
{
|
||||
/* Code 0 */
|
||||
tot_size += this.len[0] + 1;
|
||||
if (tot_size > maxlen)
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
data[ptr++] = (byte)(this.toc & 0xFC);
|
||||
}
|
||||
else if (count == 2)
|
||||
{
|
||||
if (this.len[1] == this.len[0])
|
||||
{
|
||||
/* Code 1 */
|
||||
tot_size += 2 * this.len[0] + 1;
|
||||
if (tot_size > maxlen)
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
data[ptr++] = (byte)((this.toc & 0xFC) | 0x1);
|
||||
}
|
||||
else {
|
||||
/* Code 2 */
|
||||
tot_size += this.len[0] + this.len[1] + 2 + (this.len[0] >= 252 ? 1 : 0);
|
||||
if (tot_size > maxlen)
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
data[ptr++] = (byte)((this.toc & 0xFC) | 0x2);
|
||||
ptr += OpusPacketInfo.encode_size(this.len[0], data, ptr);
|
||||
}
|
||||
}
|
||||
if (count > 2 || (pad != 0 && tot_size < maxlen))
|
||||
{
|
||||
/* Code 3 */
|
||||
int vbr;
|
||||
int pad_amount = 0;
|
||||
|
||||
/* Restart the process for the padding case */
|
||||
ptr = data_ptr;
|
||||
if (self_delimited != 0)
|
||||
tot_size = 1 + (this.len[count - 1] >= 252 ? 1 : 0);
|
||||
else
|
||||
tot_size = 0;
|
||||
vbr = 0;
|
||||
for (i = 1; i < count; i++)
|
||||
{
|
||||
if (this.len[i] != this.len[0])
|
||||
{
|
||||
vbr = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vbr != 0)
|
||||
{
|
||||
tot_size += 2;
|
||||
for (i = 0; i < count - 1; i++)
|
||||
tot_size += 1 + (this.len[i] >= 252 ? 1 : 0) + this.len[i];
|
||||
tot_size += this.len[count - 1];
|
||||
|
||||
if (tot_size > maxlen)
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
data[ptr++] = (byte)((this.toc & 0xFC) | 0x3);
|
||||
data[ptr++] = (byte)(count | 0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
tot_size += count * this.len[0] + 2;
|
||||
if (tot_size > maxlen)
|
||||
return OpusError.OPUS_BUFFER_TOO_SMALL;
|
||||
data[ptr++] = (byte)((this.toc & 0xFC) | 0x3);
|
||||
data[ptr++] = (byte)(count);
|
||||
}
|
||||
|
||||
pad_amount = pad != 0 ? (maxlen - tot_size) : 0;
|
||||
|
||||
if (pad_amount != 0)
|
||||
{
|
||||
int nb_255s;
|
||||
data[data_ptr + 1] |= 0x40;
|
||||
nb_255s = (pad_amount - 1) / 255;
|
||||
for (i = 0; i < nb_255s; i++)
|
||||
{
|
||||
data[ptr++] = 255;
|
||||
}
|
||||
|
||||
data[ptr++] = (byte)(pad_amount - 255 * nb_255s - 1);
|
||||
tot_size += pad_amount;
|
||||
}
|
||||
|
||||
if (vbr != 0)
|
||||
{
|
||||
for (i = 0; i < count - 1; i++)
|
||||
ptr += (OpusPacketInfo.encode_size(this.len[i], data, ptr));
|
||||
}
|
||||
}
|
||||
|
||||
if (self_delimited != 0)
|
||||
{
|
||||
int sdlen = OpusPacketInfo.encode_size(this.len[count - 1], data, ptr);
|
||||
ptr += (sdlen);
|
||||
}
|
||||
|
||||
/* Copy the actual data */
|
||||
for (i = begin; i < count + begin; i++)
|
||||
{
|
||||
|
||||
if (this.frames[i] == data)
|
||||
{
|
||||
/* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
|
||||
padding from opus_packet_pad or opus_packet_unpad(). */
|
||||
Arrays.MemMove<byte>(data, frames_ptrs[i], ptr, this.len[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(this.frames[i], frames_ptrs[i], data, ptr, this.len[i]);
|
||||
}
|
||||
ptr += this.len[i];
|
||||
}
|
||||
|
||||
if (pad != 0)
|
||||
{
|
||||
/* Fill padding with zeros. */
|
||||
//Arrays.MemSetWithOffset<byte>(ptr.Data, 0, ptr.Offset, data.Offset + maxlen - ptr.Offset);
|
||||
// FIXME why did they not just use a MemSet(0) here?
|
||||
while (ptr < data_ptr + maxlen)
|
||||
{
|
||||
data[ptr++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return tot_size;
|
||||
}
|
||||
|
||||
/** Construct a new packet from data previously submitted to the repacketizer
|
||||
* state via opus_repacketizer_cat().
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
|
||||
* construct the new packet.
|
||||
* @param begin <tt>int</tt>: The index of the first frame in the current
|
||||
* repacketizer state to include in the output.
|
||||
* @param end <tt>int</tt>: One past the index of the last frame in the
|
||||
* current repacketizer state to include in the
|
||||
* output.
|
||||
* @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
|
||||
* store the output packet.
|
||||
* @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
|
||||
* the output buffer. In order to guarantee
|
||||
* success, this should be at least
|
||||
* <code>1276</code> for a single frame,
|
||||
* or for multiple frames,
|
||||
* <code>1277*(end-begin)</code>.
|
||||
* However, <code>1*(end-begin)</code> plus
|
||||
* the size of all packet data submitted to
|
||||
* the repacketizer since the last call to
|
||||
* opus_repacketizer_init() or
|
||||
* opus_repacketizer_create() is also
|
||||
* sufficient, and possibly much smaller.
|
||||
* @returns The total size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG <code>[begin,end)</code> was an invalid range of
|
||||
* frames (begin < 0, begin >= end, or end >
|
||||
* opus_repacketizer_get_nb_frames()).
|
||||
* @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
|
||||
* complete output packet.
|
||||
*/
|
||||
public int CreatePacket(int begin, int end, byte[] data, int data_offset, int maxlen)
|
||||
{
|
||||
return opus_repacketizer_out_range_impl(begin, end, data, data_offset, maxlen, 0, 0);
|
||||
}
|
||||
|
||||
/** Construct a new packet from data previously submitted to the repacketizer
|
||||
* state via opus_repacketizer_cat().
|
||||
* This is a convenience routine that returns all the data submitted so far
|
||||
* in a single packet.
|
||||
* It is equivalent to calling
|
||||
* @code
|
||||
* opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
|
||||
* data, maxlen)
|
||||
* @endcode
|
||||
* @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
|
||||
* construct the new packet.
|
||||
* @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
|
||||
* store the output packet.
|
||||
* @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
|
||||
* the output buffer. In order to guarantee
|
||||
* success, this should be at least
|
||||
* <code>1277*opus_repacketizer_get_nb_frames(rp)</code>.
|
||||
* However,
|
||||
* <code>1*opus_repacketizer_get_nb_frames(rp)</code>
|
||||
* plus the size of all packet data
|
||||
* submitted to the repacketizer since the
|
||||
* last call to opus_repacketizer_init() or
|
||||
* opus_repacketizer_create() is also
|
||||
* sufficient, and possibly much smaller.
|
||||
* @returns The total size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
|
||||
* complete output packet.
|
||||
*/
|
||||
public int CreatePacket(byte[] data, int data_offset, int maxlen)
|
||||
{
|
||||
return opus_repacketizer_out_range_impl(0, this.nb_frames, data, data_offset, maxlen, 0, 0);
|
||||
}
|
||||
|
||||
/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to pad.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
|
||||
* This must be at least as large as len.
|
||||
* @returns an error code
|
||||
* @retval #OPUS_OK \a on success.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
public static int PadPacket(byte[] data, int data_offset, int len, int new_len)
|
||||
{
|
||||
OpusRepacketizer rp = new OpusRepacketizer();
|
||||
int ret;
|
||||
if (len < 1)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
if (len == new_len)
|
||||
return OpusError.OPUS_OK;
|
||||
else if (len > new_len)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
rp.Reset();
|
||||
/* Moving payload to the end of the packet so we can do in-place padding */
|
||||
Arrays.MemMove<byte>(data, data_offset, data_offset + new_len - len, len);
|
||||
//data.MemMoveTo(data.Point(new_len - len), len);
|
||||
rp.AddPacket(data, data_offset + new_len - len, len);
|
||||
ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, new_len, 0, 1);
|
||||
if (ret > 0)
|
||||
return OpusError.OPUS_OK;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
|
||||
* minimize space usage.
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to strip.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @returns The new size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
public static int UnpadPacket(byte[] data, int data_offset, int len)
|
||||
{
|
||||
int ret;
|
||||
if (len < 1)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
|
||||
OpusRepacketizer rp = new OpusRepacketizer();
|
||||
rp.Reset();
|
||||
ret = rp.AddPacket(data, data_offset, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, len, 0, 0);
|
||||
Inlines.OpusAssert(ret > 0 && ret <= len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to pad.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
|
||||
* This must be at least 1.
|
||||
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
|
||||
* This must be at least as large as len.
|
||||
* @returns an error code
|
||||
* @retval #OPUS_OK \a on success.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
public static int PadMultistreamPacket(byte[] data, int data_offset, int len, int new_len, int nb_streams)
|
||||
{
|
||||
int s;
|
||||
int count;
|
||||
byte dummy_toc;
|
||||
short[] size = new short[48];
|
||||
int packet_offset;
|
||||
int dummy_offset;
|
||||
int amount;
|
||||
|
||||
if (len < 1)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
if (len == new_len)
|
||||
return OpusError.OPUS_OK;
|
||||
else if (len > new_len)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
amount = new_len - len;
|
||||
/* Seek to last stream */
|
||||
for (s = 0; s < nb_streams - 1; s++)
|
||||
{
|
||||
if (len <= 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
count = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, 1, out dummy_toc, null, null, 0,
|
||||
size, 0, out dummy_offset, out packet_offset);
|
||||
if (count < 0)
|
||||
return count;
|
||||
data_offset += packet_offset;
|
||||
len -= packet_offset;
|
||||
}
|
||||
return PadPacket(data, data_offset, len, len + amount);
|
||||
}
|
||||
|
||||
// FIXME THIS METHOD FAILS IN TEST_OPUS_ENCODE
|
||||
/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
|
||||
* minimize space usage.
|
||||
* @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
|
||||
* packet to strip.
|
||||
* @param len <tt>opus_int32</tt>: The size of the packet.
|
||||
* This must be at least 1.
|
||||
* @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
|
||||
* This must be at least 1.
|
||||
* @returns The new size of the output packet on success, or an error code
|
||||
* on failure.
|
||||
* @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
|
||||
* @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
|
||||
*/
|
||||
public static int UnpadMultistreamPacket(byte[] data, int data_offset, int len, int nb_streams)
|
||||
{
|
||||
int s;
|
||||
byte dummy_toc;
|
||||
short[] size = new short[48];
|
||||
int packet_offset;
|
||||
int dummy_offset;
|
||||
OpusRepacketizer rp = new OpusRepacketizer();
|
||||
int dst;
|
||||
int dst_len;
|
||||
|
||||
if (len < 1)
|
||||
return OpusError.OPUS_BAD_ARG;
|
||||
dst = data_offset;
|
||||
dst_len = 0;
|
||||
/* Unpad all frames */
|
||||
for (s = 0; s < nb_streams; s++)
|
||||
{
|
||||
int ret;
|
||||
int self_delimited = ((s != nb_streams) ? 1 : 0) - 1;
|
||||
if (len <= 0)
|
||||
return OpusError.OPUS_INVALID_PACKET;
|
||||
rp.Reset();
|
||||
ret = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, self_delimited, out dummy_toc, null, null, 0,
|
||||
size, 0, out dummy_offset, out packet_offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = rp.opus_repacketizer_cat_impl(data, data_offset, packet_offset, self_delimited);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, dst, len, self_delimited, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
dst_len += ret;
|
||||
dst += ret;
|
||||
data_offset += packet_offset;
|
||||
len -= packet_offset;
|
||||
}
|
||||
return dst_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
internal class StereoWidthState
|
||||
{
|
||||
internal int XX;
|
||||
internal int XY;
|
||||
internal int YY;
|
||||
internal int smoothed_width;
|
||||
internal int max_follower;
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
XX = 0;
|
||||
XY = 0;
|
||||
YY = 0;
|
||||
smoothed_width = 0;
|
||||
max_follower = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Celt.Structs;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
internal class TonalityAnalysisState
|
||||
{
|
||||
internal bool enabled = false;
|
||||
internal readonly float[] angle = new float[240];
|
||||
internal readonly float[] d_angle = new float[240];
|
||||
internal readonly float[] d2_angle = new float[240];
|
||||
internal readonly int[] inmem = new int[OpusConstants.ANALYSIS_BUF_SIZE];
|
||||
internal int mem_fill; /* number of usable samples in the buffer */
|
||||
internal readonly float[] prev_band_tonality = new float[OpusConstants.NB_TBANDS];
|
||||
internal float prev_tonality;
|
||||
internal readonly float[][] E = Arrays.InitTwoDimensionalArray<float>(OpusConstants.NB_FRAMES, OpusConstants.NB_TBANDS);
|
||||
internal readonly float[] lowE = new float[OpusConstants.NB_TBANDS];
|
||||
internal readonly float[] highE = new float[OpusConstants.NB_TBANDS];
|
||||
internal readonly float[] meanE = new float[OpusConstants.NB_TOT_BANDS];
|
||||
internal readonly float[] mem = new float[32];
|
||||
internal readonly float[] cmean = new float[8];
|
||||
internal readonly float[] std = new float[9];
|
||||
internal float music_prob;
|
||||
internal float Etracker;
|
||||
internal float lowECount;
|
||||
internal int E_count;
|
||||
internal int last_music;
|
||||
internal int last_transition;
|
||||
internal int count;
|
||||
internal readonly float[] subframe_mem = new float[3];
|
||||
internal int analysis_offset;
|
||||
/** Probability of having speech for time i to DETECT_SIZE-1 (and music before).
|
||||
pspeech[0] is the probability that all frames in the window are speech. */
|
||||
internal readonly float[] pspeech = new float[OpusConstants.DETECT_SIZE];
|
||||
/** Probability of having music for time i to DETECT_SIZE-1 (and speech before).
|
||||
pmusic[0] is the probability that all frames in the window are music. */
|
||||
internal readonly float[] pmusic = new float[OpusConstants.DETECT_SIZE];
|
||||
internal float speech_confidence;
|
||||
internal float music_confidence;
|
||||
internal int speech_confidence_count;
|
||||
internal int music_confidence_count;
|
||||
internal int write_pos;
|
||||
internal int read_pos;
|
||||
internal int read_subframe;
|
||||
internal readonly AnalysisInfo[] info = new AnalysisInfo[OpusConstants.DETECT_SIZE];
|
||||
|
||||
internal TonalityAnalysisState()
|
||||
{
|
||||
for (int c = 0; c < OpusConstants.DETECT_SIZE; c++)
|
||||
{
|
||||
info[c] = new AnalysisInfo();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
Arrays.MemSetFloat(angle,0, 240);
|
||||
Arrays.MemSetFloat(d_angle,0, 240);
|
||||
Arrays.MemSetFloat(d2_angle,0, 240);
|
||||
Arrays.MemSetInt(inmem, 0, OpusConstants.ANALYSIS_BUF_SIZE);
|
||||
mem_fill = 0;
|
||||
Arrays.MemSetFloat(prev_band_tonality,0, OpusConstants.NB_TBANDS);
|
||||
prev_tonality = 0;
|
||||
for (int c = 0; c < OpusConstants.NB_FRAMES; c++)
|
||||
{
|
||||
Arrays.MemSetFloat(E[c], 0, OpusConstants.NB_TBANDS);
|
||||
}
|
||||
Arrays.MemSetFloat(lowE,0, OpusConstants.NB_TBANDS);
|
||||
Arrays.MemSetFloat(highE,0, OpusConstants.NB_TBANDS);
|
||||
Arrays.MemSetFloat(meanE,0, OpusConstants.NB_TOT_BANDS);
|
||||
Arrays.MemSetFloat(mem,0, 32);
|
||||
Arrays.MemSetFloat(cmean,0, 8);
|
||||
Arrays.MemSetFloat(std,0, 9);
|
||||
music_prob = 0;
|
||||
Etracker = 0;
|
||||
lowECount = 0;
|
||||
E_count = 0;
|
||||
last_music = 0;
|
||||
last_transition = 0;
|
||||
count = 0;
|
||||
Arrays.MemSetFloat(subframe_mem,0, 3);
|
||||
analysis_offset = 0;
|
||||
Arrays.MemSetFloat(pspeech,0, OpusConstants.DETECT_SIZE);
|
||||
Arrays.MemSetFloat(pmusic,0, OpusConstants.DETECT_SIZE);
|
||||
speech_confidence = 0;
|
||||
music_confidence = 0;
|
||||
speech_confidence_count = 0;
|
||||
music_confidence_count = 0;
|
||||
write_pos = 0;
|
||||
read_pos = 0;
|
||||
read_subframe = 0;
|
||||
for (int c = 0; c < OpusConstants.DETECT_SIZE; c++)
|
||||
{
|
||||
info[c].Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus.Structs
|
||||
{
|
||||
internal class VorbisLayout
|
||||
{
|
||||
internal VorbisLayout(int streams, int coupled_streams, byte[] map)
|
||||
{
|
||||
nb_streams = streams;
|
||||
nb_coupled_streams = coupled_streams;
|
||||
mapping = map;
|
||||
}
|
||||
|
||||
internal int nb_streams;
|
||||
internal int nb_coupled_streams;
|
||||
internal byte[] mapping;
|
||||
|
||||
/* Index is nb_channel-1*/
|
||||
internal static readonly VorbisLayout[] vorbis_mappings = {
|
||||
new VorbisLayout(1, 0, new byte[] {0}), /* 1: mono */
|
||||
new VorbisLayout(1, 1, new byte[] {0, 1}), /* 2: stereo */
|
||||
new VorbisLayout(2, 1, new byte[] {0, 2, 1}), /* 3: 1-d surround */
|
||||
new VorbisLayout(2, 2, new byte[] {0, 1, 2, 3}), /* 4: quadraphonic surround */
|
||||
new VorbisLayout(3, 2, new byte[] {0, 4, 1, 2, 3}), /* 5: 5-channel surround */
|
||||
new VorbisLayout(4, 2, new byte[] {0, 4, 1, 2, 3, 5}), /* 6: 5.1 surround */
|
||||
new VorbisLayout(4, 3, new byte[] {0, 4, 1, 2, 3, 5, 6}), /* 7: 6.1 surround */
|
||||
new VorbisLayout(5, 3, new byte[] {0, 6, 1, 2, 3, 4, 5, 7}), /* 8: 7.1 surround */
|
||||
};
|
||||
}
|
||||
}
|
||||
298
Libraries/Concentus/CSharp/Concentus/Opus/Tables.cs
Normal file
298
Libraries/Concentus/CSharp/Concentus/Opus/Tables.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2011 Xiph.Org Foundation
|
||||
Originally written by Jean-Marc Valin, Gregory Maxwell, Koen Vos,
|
||||
Timothy B. Terriberry, and the Opus open-source contributors
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Structs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Concentus
|
||||
{
|
||||
internal static class Tables
|
||||
{
|
||||
internal static readonly float[] dct_table = {
|
||||
0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
|
||||
0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
|
||||
0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
|
||||
-0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f,
|
||||
0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f,
|
||||
-0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
|
||||
0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f,
|
||||
0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f,
|
||||
0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
|
||||
0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
|
||||
0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f,
|
||||
-0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f,
|
||||
0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f,
|
||||
-0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f,
|
||||
0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f,
|
||||
0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f,
|
||||
};
|
||||
|
||||
internal static readonly float[] analysis_window = {
|
||||
0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
|
||||
0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
|
||||
0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
|
||||
0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
|
||||
0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
|
||||
0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
|
||||
0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
|
||||
0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
|
||||
0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
|
||||
0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
|
||||
0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
|
||||
0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
|
||||
0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
|
||||
0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
|
||||
0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
|
||||
0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
|
||||
0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
|
||||
0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
|
||||
0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
|
||||
0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
|
||||
0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
|
||||
0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
|
||||
0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
|
||||
0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
|
||||
0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
|
||||
0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
|
||||
0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
|
||||
0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
|
||||
0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
|
||||
0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,
|
||||
};
|
||||
|
||||
internal static readonly int[] tbands/*[NB_TBANDS + 1]*/ = {
|
||||
2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120
|
||||
};
|
||||
|
||||
internal static readonly int[] extra_bands/*[NB_TOT_BANDS + 1]*/ = {
|
||||
1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200
|
||||
};
|
||||
|
||||
/*static const float tweight[NB_TBANDS+1] = {
|
||||
.3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5
|
||||
};*/
|
||||
|
||||
/* RMS error was 0.138320, seed was 1361535663 */
|
||||
|
||||
internal static readonly float[] weights/*[422]*/ = {
|
||||
/* hidden layer */
|
||||
-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f,
|
||||
-0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f,
|
||||
-0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f,
|
||||
0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f,
|
||||
0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f,
|
||||
24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f,
|
||||
-0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f,
|
||||
-0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f,
|
||||
-0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f,
|
||||
1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f,
|
||||
15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f,
|
||||
0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f,
|
||||
-0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f,
|
||||
0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f,
|
||||
0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f,
|
||||
-1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f,
|
||||
-0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f,
|
||||
-0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f,
|
||||
0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f,
|
||||
-0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f,
|
||||
2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f,
|
||||
0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f,
|
||||
-0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f,
|
||||
0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f,
|
||||
0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f,
|
||||
-4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f,
|
||||
5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f,
|
||||
-0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f,
|
||||
-0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f,
|
||||
-0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f,
|
||||
1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f,
|
||||
-7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f,
|
||||
-0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f,
|
||||
0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f,
|
||||
0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f,
|
||||
-0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f,
|
||||
10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f,
|
||||
-0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f,
|
||||
-0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f,
|
||||
-0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f,
|
||||
0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f,
|
||||
-0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f,
|
||||
0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f,
|
||||
0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f,
|
||||
-0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f,
|
||||
0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f,
|
||||
-0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f,
|
||||
-0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f,
|
||||
-0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f,
|
||||
-0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f,
|
||||
-0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f,
|
||||
5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f,
|
||||
1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f,
|
||||
0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f,
|
||||
-0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f,
|
||||
0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f,
|
||||
-0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f,
|
||||
-975268.0f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f,
|
||||
0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f,
|
||||
-0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f,
|
||||
-2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f,
|
||||
0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f,
|
||||
-6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f,
|
||||
0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f,
|
||||
-0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f,
|
||||
-0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f,
|
||||
0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f,
|
||||
-0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f,
|
||||
0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f,
|
||||
-0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f,
|
||||
0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f,
|
||||
-2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f,
|
||||
4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f,
|
||||
0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f,
|
||||
-0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f,
|
||||
0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f,
|
||||
0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f,
|
||||
3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f,
|
||||
|
||||
/* output layer */
|
||||
-0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f,
|
||||
0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f,
|
||||
0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f,
|
||||
0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f,
|
||||
4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f,
|
||||
-1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f,
|
||||
3.87308f, 3.52558f};
|
||||
|
||||
internal static readonly int[] topo = { 25, 15, 2 };
|
||||
|
||||
// fixme: move this into an MLP class singleton or something?
|
||||
internal static readonly MLP net = new MLP()
|
||||
{
|
||||
layers = 3,
|
||||
topo = topo,
|
||||
weights = weights
|
||||
};
|
||||
|
||||
internal static readonly float[] tansig_table/*[201]*/ = {
|
||||
0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f,
|
||||
0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
|
||||
0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f,
|
||||
0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f,
|
||||
0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f,
|
||||
0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
|
||||
0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f,
|
||||
0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f,
|
||||
0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f,
|
||||
0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f,
|
||||
0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f,
|
||||
0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
|
||||
0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
|
||||
0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f,
|
||||
0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f,
|
||||
0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
|
||||
0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f,
|
||||
0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
|
||||
0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f,
|
||||
0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
|
||||
0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f,
|
||||
0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
|
||||
0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f,
|
||||
0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
|
||||
0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f,
|
||||
0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
|
||||
0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f,
|
||||
0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f,
|
||||
0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f,
|
||||
0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
|
||||
0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f,
|
||||
0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
|
||||
0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f,
|
||||
0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
|
||||
0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f,
|
||||
0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
|
||||
0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
|
||||
0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
|
||||
1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
|
||||
1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
|
||||
1.000000f,
|
||||
};
|
||||
|
||||
// from opus_encoder.c
|
||||
/* Transition tables for the voice and music. First column is the
|
||||
middle (memoriless) threshold. The second column is the hysteresis
|
||||
(difference with the middle) */
|
||||
internal static readonly int[] mono_voice_bandwidth_thresholds = {
|
||||
11000, 1000, /* NB<->MB */
|
||||
14000, 1000, /* MB<->WB */
|
||||
17000, 1000, /* WB<->SWB */
|
||||
21000, 2000, /* SWB<->FB */
|
||||
};
|
||||
internal static readonly int[] mono_music_bandwidth_thresholds = {
|
||||
12000, 1000, /* NB<->MB */
|
||||
15000, 1000, /* MB<->WB */
|
||||
18000, 2000, /* WB<->SWB */
|
||||
22000, 2000, /* SWB<->FB */
|
||||
};
|
||||
internal static readonly int[] stereo_voice_bandwidth_thresholds = {
|
||||
11000, 1000, /* NB<->MB */
|
||||
14000, 1000, /* MB<->WB */
|
||||
21000, 2000, /* WB<->SWB */
|
||||
28000, 2000, /* SWB<->FB */
|
||||
};
|
||||
internal static readonly int[] stereo_music_bandwidth_thresholds = {
|
||||
12000, 1000, /* NB<->MB */
|
||||
18000, 2000, /* MB<->WB */
|
||||
21000, 2000, /* WB<->SWB */
|
||||
30000, 2000, /* SWB<->FB */
|
||||
};
|
||||
|
||||
/* Threshold bit-rates for switching between mono and stereo */
|
||||
public const int stereo_voice_threshold = 30000;
|
||||
public const int stereo_music_threshold = 30000;
|
||||
|
||||
/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */
|
||||
internal static readonly int[][] mode_thresholds = {
|
||||
/* voice */ /* music */
|
||||
new int[]{ 64000, 16000}, /* mono */
|
||||
new int[]{ 36000, 16000}, /* stereo */
|
||||
};
|
||||
}
|
||||
}
|
||||
52
Libraries/Concentus/CSharp/Concentus/Readme.txt
Normal file
52
Libraries/Concentus/CSharp/Concentus/Readme.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
Hi there, welcome to the Concentus package. You're about to ask me for sample code, so I'll get straight to it:
|
||||
|
||||
If you're already using something like P/Opus then your code probably looks like this:
|
||||
|
||||
[DllImport(OPUS_TARGET_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr opus_encoder_create(int Fs, int channels, int application, out IntPtr error);
|
||||
|
||||
[DllImport(OPUS_TARGET_DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int opus_encode(IntPtr st, byte[] pcm, int frame_size, IntPtr data, int max_data_bytes);
|
||||
|
||||
// Initialize
|
||||
IntPtr error;
|
||||
IntPtr _encoder = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, out error);
|
||||
opus_encoder_ctl(_encoder, OPUS_SET_BITRATE_REQUEST, 12000);
|
||||
|
||||
// Encoding loop
|
||||
byte[] inputAudioSamplesInterleaved; // 16-bit pcm data interleaved into a byte array
|
||||
byte[] outputBuffer[1000];
|
||||
int frameSize = 960;
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* benc = outputBuffer)
|
||||
{
|
||||
IntPtr encodedPtr = new IntPtr(benc);
|
||||
int thisPacketSizeOrSometimesAnErrorCode = opus_encode(_encoder, inputAudioSamplesInterleaved, frameSize, encodedPtr, outputBuffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
Here is what you can replace it with:
|
||||
|
||||
// Initialize
|
||||
OpusEncoder encoder = OpusEncoder.Create(48000, 1, OpusApplication.OPUS_APPLICATION_AUDIO);
|
||||
encoder.Bitrate = 12000;
|
||||
|
||||
// Encoding loop
|
||||
short[] inputAudioSamples
|
||||
byte[] outputBuffer[1000];
|
||||
int frameSize = 960;
|
||||
|
||||
int thisPacketSize = encoder.Encode(inputAudioSamples, 0, frameSize, outputBuffer, 0, outputBuffer.Length); // this throws OpusException on a failure, rather than returning a negative number
|
||||
|
||||
And here is the decoder path:
|
||||
|
||||
OpusDecoder decoder = OpusDecoder.Create(48000, 1);
|
||||
|
||||
// Decoding loop
|
||||
byte[] compressedPacket;
|
||||
int frameSize = 960; // must be same as framesize used in input, you can use OpusPacketInfo.GetNumSamples() to determine this dynamically
|
||||
short[] outputBuffer = new short[frameSize];
|
||||
|
||||
int thisFrameSize = _decoder.Decode(compressedPacket, 0, compressedPacket.Length, outputBuffer, 0, frameSize, false);
|
||||
118
Libraries/Concentus/CSharp/Concentus/Silk/ApplySineWindow.cs
Normal file
118
Libraries/Concentus/CSharp/Concentus/Silk/ApplySineWindow.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
|
||||
internal static class ApplySineWindow
|
||||
{
|
||||
/* Apply sine window to signal vector. */
|
||||
/* Window types: */
|
||||
/* 1 . sine window from 0 to pi/2 */
|
||||
/* 2 . sine window from pi/2 to pi */
|
||||
/* Every other sample is linearly interpolated, for speed. */
|
||||
/* Window length must be between 16 and 120 (incl) and a multiple of 4. */
|
||||
|
||||
/* Matlab code for table:
|
||||
for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end
|
||||
*/
|
||||
private static readonly short[] freq_table_Q16 = {
|
||||
12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202,
|
||||
3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422,
|
||||
2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702,
|
||||
};
|
||||
|
||||
internal static void silk_apply_sine_window(
|
||||
short[] px_win, /* O Pointer to windowed signal */
|
||||
int px_win_ptr,
|
||||
short[] px, /* I Pointer to input signal */
|
||||
int px_ptr,
|
||||
int win_type, /* I Selects a window type */
|
||||
int length /* I Window length, multiple of 4 */
|
||||
)
|
||||
{
|
||||
int k, f_Q16, c_Q16;
|
||||
int S0_Q16, S1_Q16;
|
||||
|
||||
Inlines.OpusAssert(win_type == 1 || win_type == 2);
|
||||
|
||||
/* Length must be in a range from 16 to 120 and a multiple of 4 */
|
||||
Inlines.OpusAssert(length >= 16 && length <= 120);
|
||||
Inlines.OpusAssert((length & 3) == 0);
|
||||
|
||||
/* Frequency */
|
||||
k = (length >> 2) - 4;
|
||||
Inlines.OpusAssert(k >= 0 && k <= 26);
|
||||
f_Q16 = (int)freq_table_Q16[k];
|
||||
|
||||
/* Factor used for cosine approximation */
|
||||
c_Q16 = Inlines.silk_SMULWB((int)f_Q16, -f_Q16);
|
||||
Inlines.OpusAssert(c_Q16 >= -32768);
|
||||
|
||||
/* initialize state */
|
||||
if (win_type == 1)
|
||||
{
|
||||
/* start from 0 */
|
||||
S0_Q16 = 0;
|
||||
/* approximation of sin(f) */
|
||||
S1_Q16 = f_Q16 + Inlines.silk_RSHIFT(length, 3);
|
||||
}
|
||||
else {
|
||||
/* start from 1 */
|
||||
S0_Q16 = ((int)1 << 16);
|
||||
/* approximation of cos(f) */
|
||||
S1_Q16 = ((int)1 << 16) + Inlines.silk_RSHIFT(c_Q16, 1) + Inlines.silk_RSHIFT(length, 4);
|
||||
}
|
||||
|
||||
/* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
|
||||
/* 4 samples at a time */
|
||||
for (k = 0; k < length; k += 4)
|
||||
{
|
||||
int pxwk = px_win_ptr + k;
|
||||
int pxk = px_ptr + k;
|
||||
px_win[pxwk] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(S0_Q16 + S1_Q16, 1), px[pxk]);
|
||||
px_win[pxwk + 1] = (short)Inlines.silk_SMULWB(S1_Q16, px[pxk + 1]);
|
||||
S0_Q16 = Inlines.silk_SMULWB(S1_Q16, c_Q16) + Inlines.silk_LSHIFT(S1_Q16, 1) - S0_Q16 + 1;
|
||||
S0_Q16 = Inlines.silk_min(S0_Q16, ((int)1 << 16));
|
||||
|
||||
px_win[pxwk + 2] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(S0_Q16 + S1_Q16, 1), px[pxk + 2]);
|
||||
px_win[pxwk + 3] = (short)Inlines.silk_SMULWB(S0_Q16, px[pxk + 3]);
|
||||
S1_Q16 = Inlines.silk_SMULWB(S0_Q16, c_Q16) + Inlines.silk_LSHIFT(S0_Q16, 1) - S1_Q16;
|
||||
S1_Q16 = Inlines.silk_min(S1_Q16, ((int)1 << 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Libraries/Concentus/CSharp/Concentus/Silk/BWExpander.cs
Normal file
90
Libraries/Concentus/CSharp/Concentus/Silk/BWExpander.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class BWExpander
|
||||
{
|
||||
/// <summary>
|
||||
/// Chirp (bw expand) LP AR filter (Fixed point implementation)
|
||||
/// </summary>
|
||||
/// <param name="ar">I/O AR filter to be expanded (without leading 1)</param>
|
||||
/// <param name="d">I length of ar</param>
|
||||
/// <param name="chirp_Q16">I chirp factor (typically in range (0..1) )</param>
|
||||
internal static void silk_bwexpander_32(
|
||||
int[] ar, /* I/O AR filter to be expanded (without leading 1) */
|
||||
int d, /* I Length of ar */
|
||||
int chirp_Q16 /* I Chirp factor in Q16 */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int chirp_minus_one_Q16 = chirp_Q16 - 65536;
|
||||
|
||||
for (i = 0; i < d - 1; i++)
|
||||
{
|
||||
ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]);
|
||||
chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16);
|
||||
}
|
||||
ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chirp (bw expand) LP AR filter (Fixed point implementation)
|
||||
/// </summary>
|
||||
/// <param name="ar">I/O AR filter to be expanded (without leading 1)</param>
|
||||
/// <param name="d">I length of ar</param>
|
||||
/// <param name="chirp_Q16">I chirp factor (typically in range (0..1) )</param>
|
||||
internal static void silk_bwexpander(
|
||||
short[] ar,
|
||||
int d,
|
||||
int chirp_Q16)
|
||||
{
|
||||
int i;
|
||||
int chirp_minus_one_Q16 = chirp_Q16 - 65536;
|
||||
|
||||
/* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */
|
||||
/* Bias in silk_SMULWB can lead to unstable filters */
|
||||
for (i = 0; i < d - 1; i++)
|
||||
{
|
||||
ar[i] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[i]), 16);
|
||||
chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16);
|
||||
}
|
||||
ar[d - 1] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[d - 1]), 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
326
Libraries/Concentus/CSharp/Concentus/Silk/BurgModified.cs
Normal file
326
Libraries/Concentus/CSharp/Concentus/Silk/BurgModified.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class BurgModified
|
||||
{
|
||||
/* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
|
||||
private const int MAX_FRAME_SIZE = 384;
|
||||
private const int QA = 25;
|
||||
private const int N_BITS_HEAD_ROOM = 2;
|
||||
private const int MIN_RSHIFTS = -16;
|
||||
private const int MAX_RSHIFTS = (32 - QA);
|
||||
|
||||
/* Compute reflection coefficients from input signal */
|
||||
internal static void silk_burg_modified(
|
||||
BoxedValueInt res_nrg, /* O Residual energy */
|
||||
BoxedValueInt res_nrg_Q, /* O Residual energy Q value */
|
||||
int[] A_Q16, /* O Prediction coefficients (length order) */
|
||||
short[] x, /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
|
||||
int x_ptr,
|
||||
int minInvGain_Q30, /* I Inverse of max prediction gain */
|
||||
int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
|
||||
int nb_subfr, /* I Number of subframes stacked in x */
|
||||
int D /* I Order */
|
||||
)
|
||||
{
|
||||
int k, n, s, lz, rshifts, reached_max_gain;
|
||||
int C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
|
||||
int x_offset;
|
||||
int[] C_first_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] C_last_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] Af_QA = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] CAf = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] CAb = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] xcorr = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
long C0_64;
|
||||
|
||||
Inlines.OpusAssert(subfr_length * nb_subfr <= MAX_FRAME_SIZE);
|
||||
|
||||
/* Compute autocorrelations, added over subframes */
|
||||
C0_64 = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr);
|
||||
lz = Inlines.silk_CLZ64(C0_64);
|
||||
rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
|
||||
if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
|
||||
if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
|
||||
|
||||
if (rshifts > 0)
|
||||
{
|
||||
C0 = (int)Inlines.silk_RSHIFT64(C0_64, rshifts);
|
||||
}
|
||||
else {
|
||||
C0 = Inlines.silk_LSHIFT32((int)C0_64, -rshifts);
|
||||
}
|
||||
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
Arrays.MemSetInt(C_first_row, 0, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += (int)Inlines.silk_RSHIFT64(
|
||||
Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset + n, subfr_length - n), rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
int i;
|
||||
int d;
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
CeltPitchXCorr.pitch_xcorr(x, x_offset, x, x_offset + 1, xcorr, subfr_length - D, D);
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
for (i = n + subfr_length - D, d = 0; i < subfr_length; i++)
|
||||
d = Inlines.MAC16_16(d, x[x_offset + i], x[x_offset + i - n]);
|
||||
xcorr[n - 1] += d;
|
||||
}
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += Inlines.silk_LSHIFT32(xcorr[n - 1], -rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
Array.Copy(C_first_row, C_last_row, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
|
||||
/* Initialize */
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
|
||||
invGain_Q30 = (int)1 << 30;
|
||||
reached_max_gain = 0;
|
||||
for (n = 0; n < D; n++)
|
||||
{
|
||||
/* Update first row of correlation matrix (without first element) */
|
||||
/* Update last row of correlation matrix (without last element, stored in reversed order) */
|
||||
/* Update C * Af */
|
||||
/* Update C * flipud(Af) (stored in reversed order) */
|
||||
if (rshifts > -2)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)x[x_offset + n], 16 - rshifts); /* Q(16-rshifts) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], 16 - rshifts); /* Q(16-rshifts) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)x[x_offset + n], QA - 16); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], QA - 16); /* Q(QA-16) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_SMLAWB(C_first_row[k], x1, x[x_offset + n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_SMLAWB(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp_QA = Af_QA[k];
|
||||
tmp1 = Inlines.silk_SMLAWB(tmp1, Atmp_QA, x[x_offset + n - k - 1]); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_SMLAWB(tmp2, Atmp_QA, x[x_offset + subfr_length - n + k]); /* Q(QA-16) */
|
||||
}
|
||||
tmp1 = Inlines.silk_LSHIFT32(-tmp1, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
tmp2 = Inlines.silk_LSHIFT32(-tmp2, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWB(CAf[k], tmp1, x[x_offset + n - k]); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWB(CAb[k], tmp2, x[x_offset + subfr_length - n + k - 1]); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)x[x_offset + n], -rshifts); /* Q( -rshifts ) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], -rshifts); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)x[x_offset + n], 17); /* Q17 */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], 17); /* Q17 */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_MLA(C_first_row[k], x1, x[x_offset + n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_MLA(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 17); /* Q17 */
|
||||
tmp1 = Inlines.silk_MLA(tmp1, x[x_offset + n - k - 1], Atmp1); /* Q17 */
|
||||
tmp2 = Inlines.silk_MLA(tmp2, x[x_offset + subfr_length - n + k], Atmp1); /* Q17 */
|
||||
}
|
||||
tmp1 = -tmp1; /* Q17 */
|
||||
tmp2 = -tmp2; /* Q17 */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWW(CAf[k], tmp1,
|
||||
Inlines.silk_LSHIFT32((int)x[x_offset + n - k], -rshifts - 1)); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWW(CAb[k], tmp2,
|
||||
Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n + k - 1], -rshifts - 1)); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
|
||||
tmp1 = C_first_row[n]; /* Q( -rshifts ) */
|
||||
tmp2 = C_last_row[n]; /* Q( -rshifts ) */
|
||||
num = 0; /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD32(CAb[0], CAf[0]); /* Q( 1-rshifts ) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
Atmp_QA = Af_QA[k];
|
||||
lz = Inlines.silk_CLZ32(Inlines.silk_abs(Atmp_QA)) - 1;
|
||||
lz = Inlines.silk_min(32 - QA, lz);
|
||||
Atmp1 = Inlines.silk_LSHIFT32(Atmp_QA, lz); /* Q( QA + lz ) */
|
||||
|
||||
tmp1 = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(C_last_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
tmp2 = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(C_first_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD_LSHIFT32(num, Inlines.silk_SMMUL(CAb[n - k], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD_LSHIFT32(nrg, Inlines.silk_SMMUL(Inlines.silk_ADD32(CAb[k + 1], CAf[k + 1]),
|
||||
Atmp1), 32 - QA - lz); /* Q( 1-rshifts ) */
|
||||
}
|
||||
CAf[n + 1] = tmp1; /* Q( -rshifts ) */
|
||||
CAb[n + 1] = tmp2; /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD32(num, tmp2); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_LSHIFT32(-num, 1); /* Q( 1-rshifts ) */
|
||||
|
||||
/* Calculate the next order reflection (parcor) coefficient */
|
||||
if (Inlines.silk_abs(num) < nrg)
|
||||
{
|
||||
rc_Q31 = Inlines.silk_DIV32_varQ(num, nrg, 31);
|
||||
}
|
||||
else {
|
||||
rc_Q31 = (num > 0) ? int.MaxValue : int.MinValue;
|
||||
}
|
||||
|
||||
/* Update inverse prediction gain */
|
||||
tmp1 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
tmp1 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, tmp1), 2);
|
||||
if (tmp1 <= minInvGain_Q30)
|
||||
{
|
||||
/* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
|
||||
tmp2 = ((int)1 << 30) - Inlines.silk_DIV32_varQ(minInvGain_Q30, invGain_Q30, 30); /* Q30 */
|
||||
rc_Q31 = Inlines.silk_SQRT_APPROX(tmp2); /* Q15 */
|
||||
/* Newton-Raphson iteration */
|
||||
rc_Q31 = Inlines.silk_RSHIFT32(rc_Q31 + Inlines.silk_DIV32(tmp2, rc_Q31), 1); /* Q15 */
|
||||
rc_Q31 = Inlines.silk_LSHIFT32(rc_Q31, 16); /* Q31 */
|
||||
if (num < 0)
|
||||
{
|
||||
/* Ensure adjusted reflection coefficients has the original sign */
|
||||
rc_Q31 = -rc_Q31;
|
||||
}
|
||||
invGain_Q30 = minInvGain_Q30;
|
||||
reached_max_gain = 1;
|
||||
}
|
||||
else {
|
||||
invGain_Q30 = tmp1;
|
||||
}
|
||||
|
||||
/* Update the AR coefficients */
|
||||
for (k = 0; k < (n + 1) >> 1; k++)
|
||||
{
|
||||
tmp1 = Af_QA[k]; /* QA */
|
||||
tmp2 = Af_QA[n - k - 1]; /* QA */
|
||||
Af_QA[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* QA */
|
||||
Af_QA[n - k - 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* QA */
|
||||
}
|
||||
Af_QA[n] = Inlines.silk_RSHIFT32(rc_Q31, 31 - QA); /* QA */
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
/* Reached max prediction gain; set remaining coefficients to zero and exit loop */
|
||||
for (k = n + 1; k < D; k++)
|
||||
{
|
||||
Af_QA[k] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update C * Af and C * Ab */
|
||||
for (k = 0; k <= n + 1; k++)
|
||||
{
|
||||
tmp1 = CAf[k]; /* Q( -rshifts ) */
|
||||
tmp2 = CAb[n - k + 1]; /* Q( -rshifts ) */
|
||||
CAf[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
CAb[n - k + 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
}
|
||||
}
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
/* Scale coefficients */
|
||||
A_Q16[k] = -Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16);
|
||||
}
|
||||
/* Subtract energy of preceding samples from C0 */
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset, D), rshifts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, x_offset, D), -rshifts);
|
||||
}
|
||||
}
|
||||
/* Approximate residual energy */
|
||||
res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, C0), 2);
|
||||
res_nrg_Q.Val = 0 - rshifts;
|
||||
}
|
||||
else {
|
||||
/* Return residual energy */
|
||||
nrg = CAf[0]; /* Q( -rshifts ) */
|
||||
tmp1 = (int)1 << 16; /* Q16 */
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16); /* Q16 */
|
||||
nrg = Inlines.silk_SMLAWW(nrg, CAf[k + 1], Atmp1); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_SMLAWW(tmp1, Atmp1, Atmp1); /* Q16 */
|
||||
A_Q16[k] = -Atmp1;
|
||||
}
|
||||
res_nrg.Val = Inlines.silk_SMLAWW(nrg, Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0), -tmp1);/* Q( -rshifts ) */
|
||||
res_nrg_Q.Val = -rshifts;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
336
Libraries/Concentus/CSharp/Concentus/Silk/BurgModifiedUnsafe.cs
Normal file
336
Libraries/Concentus/CSharp/Concentus/Silk/BurgModifiedUnsafe.cs
Normal file
@@ -0,0 +1,336 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if UNSAFE
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class BurgModified
|
||||
{
|
||||
/* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
|
||||
private const int MAX_FRAME_SIZE = 384;
|
||||
private const int QA = 25;
|
||||
private const int N_BITS_HEAD_ROOM = 2;
|
||||
private const int MIN_RSHIFTS = -16;
|
||||
private const int MAX_RSHIFTS = (32 - QA);
|
||||
|
||||
/* Compute reflection coefficients from input signal */
|
||||
internal static unsafe void silk_burg_modified(
|
||||
BoxedValueInt res_nrg, /* O Residual energy */
|
||||
BoxedValueInt res_nrg_Q, /* O Residual energy Q value */
|
||||
int[] A_Q16, /* O Prediction coefficients (length order) */
|
||||
short[] x, /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
|
||||
int x_ptr,
|
||||
int minInvGain_Q30, /* I Inverse of max prediction gain */
|
||||
int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
|
||||
int nb_subfr, /* I Number of subframes stacked in x */
|
||||
int D /* I Order */
|
||||
)
|
||||
{
|
||||
int k, n, s, lz, rshifts, reached_max_gain;
|
||||
int C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
|
||||
int x_offset;
|
||||
int[] C_first_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] C_last_row = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] Af_QA = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
int[] CAf = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] CAb = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1];
|
||||
int[] xcorr = new int[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
long C0_64;
|
||||
|
||||
Inlines.OpusAssert(subfr_length * nb_subfr <= MAX_FRAME_SIZE);
|
||||
|
||||
fixed (short* px_base = x)
|
||||
{
|
||||
short* px = px_base + x_ptr;
|
||||
/* Compute autocorrelations, added over subframes */
|
||||
C0_64 = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr);
|
||||
lz = Inlines.silk_CLZ64(C0_64);
|
||||
rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
|
||||
if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
|
||||
if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
|
||||
|
||||
if (rshifts > 0)
|
||||
{
|
||||
C0 = (int)Inlines.silk_RSHIFT64(C0_64, rshifts);
|
||||
}
|
||||
else
|
||||
{
|
||||
C0 = Inlines.silk_LSHIFT32((int)C0_64, -rshifts);
|
||||
}
|
||||
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
Arrays.MemSetInt(C_first_row, 0, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
short* px2 = px + s * subfr_length;
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += (int)Inlines.silk_RSHIFT64(
|
||||
Inlines.silk_inner_prod16_aligned_64(px2, px2 + n, subfr_length - n), rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
int i;
|
||||
int d;
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
CeltPitchXCorr.pitch_xcorr(x, x_offset, x, x_offset + 1, xcorr, subfr_length - D, D);
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
for (i = n + subfr_length - D, d = 0; i < subfr_length; i++)
|
||||
d = Inlines.MAC16_16(d, x[x_offset + i], x[x_offset + i - n]);
|
||||
xcorr[n - 1] += d;
|
||||
}
|
||||
for (n = 1; n < D + 1; n++)
|
||||
{
|
||||
C_first_row[n - 1] += Inlines.silk_LSHIFT32(xcorr[n - 1], -rshifts);
|
||||
}
|
||||
}
|
||||
}
|
||||
Array.Copy(C_first_row, C_last_row, SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
|
||||
/* Initialize */
|
||||
CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */
|
||||
|
||||
invGain_Q30 = (int)1 << 30;
|
||||
reached_max_gain = 0;
|
||||
for (n = 0; n < D; n++)
|
||||
{
|
||||
/* Update first row of correlation matrix (without first element) */
|
||||
/* Update last row of correlation matrix (without last element, stored in reversed order) */
|
||||
/* Update C * Af */
|
||||
/* Update C * flipud(Af) (stored in reversed order) */
|
||||
if (rshifts > -2)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
short* px2 = px + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)px2[n], 16 - rshifts); /* Q(16-rshifts) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], 16 - rshifts); /* Q(16-rshifts) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)px2[n], QA - 16); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], QA - 16); /* Q(QA-16) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_SMLAWB(C_first_row[k], x1, px2[n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_SMLAWB(C_last_row[k], x2, px2[subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp_QA = Af_QA[k];
|
||||
tmp1 = Inlines.silk_SMLAWB(tmp1, Atmp_QA, px2[n - k - 1]); /* Q(QA-16) */
|
||||
tmp2 = Inlines.silk_SMLAWB(tmp2, Atmp_QA, px2[subfr_length - n + k]); /* Q(QA-16) */
|
||||
}
|
||||
tmp1 = Inlines.silk_LSHIFT32(-tmp1, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
tmp2 = Inlines.silk_LSHIFT32(-tmp2, 32 - QA - rshifts); /* Q(16-rshifts) */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWB(CAf[k], tmp1, px2[n - k]); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWB(CAb[k], tmp2, px2[subfr_length - n + k - 1]); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
short* px2 = px + s * subfr_length;
|
||||
x1 = -Inlines.silk_LSHIFT32((int)px2[n], -rshifts); /* Q( -rshifts ) */
|
||||
x2 = -Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], -rshifts); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_LSHIFT32((int)px2[n], 17); /* Q17 */
|
||||
tmp2 = Inlines.silk_LSHIFT32((int)px2[subfr_length - n - 1], 17); /* Q17 */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
C_first_row[k] = Inlines.silk_MLA(C_first_row[k], x1, px2[n - k - 1]); /* Q( -rshifts ) */
|
||||
C_last_row[k] = Inlines.silk_MLA(C_last_row[k], x2, px2[subfr_length - n + k]); /* Q( -rshifts ) */
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 17); /* Q17 */
|
||||
tmp1 = Inlines.silk_MLA(tmp1, px2[n - k - 1], Atmp1); /* Q17 */
|
||||
tmp2 = Inlines.silk_MLA(tmp2, px2[subfr_length - n + k], Atmp1); /* Q17 */
|
||||
}
|
||||
tmp1 = -tmp1; /* Q17 */
|
||||
tmp2 = -tmp2; /* Q17 */
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
CAf[k] = Inlines.silk_SMLAWW(CAf[k], tmp1,
|
||||
Inlines.silk_LSHIFT32((int)px2[n - k], -rshifts - 1)); /* Q( -rshift ) */
|
||||
CAb[k] = Inlines.silk_SMLAWW(CAb[k], tmp2,
|
||||
Inlines.silk_LSHIFT32((int)px2[subfr_length - n + k - 1], -rshifts - 1)); /* Q( -rshift ) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
|
||||
tmp1 = C_first_row[n]; /* Q( -rshifts ) */
|
||||
tmp2 = C_last_row[n]; /* Q( -rshifts ) */
|
||||
num = 0; /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD32(CAb[0], CAf[0]); /* Q( 1-rshifts ) */
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
Atmp_QA = Af_QA[k];
|
||||
lz = Inlines.silk_CLZ32(Inlines.silk_abs(Atmp_QA)) - 1;
|
||||
lz = Inlines.silk_min(32 - QA, lz);
|
||||
Atmp1 = Inlines.silk_LSHIFT32(Atmp_QA, lz); /* Q( QA + lz ) */
|
||||
|
||||
tmp1 = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(C_last_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
tmp2 = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(C_first_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD_LSHIFT32(num, Inlines.silk_SMMUL(CAb[n - k], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */
|
||||
nrg = Inlines.silk_ADD_LSHIFT32(nrg, Inlines.silk_SMMUL(Inlines.silk_ADD32(CAb[k + 1], CAf[k + 1]),
|
||||
Atmp1), 32 - QA - lz); /* Q( 1-rshifts ) */
|
||||
}
|
||||
CAf[n + 1] = tmp1; /* Q( -rshifts ) */
|
||||
CAb[n + 1] = tmp2; /* Q( -rshifts ) */
|
||||
num = Inlines.silk_ADD32(num, tmp2); /* Q( -rshifts ) */
|
||||
num = Inlines.silk_LSHIFT32(-num, 1); /* Q( 1-rshifts ) */
|
||||
|
||||
/* Calculate the next order reflection (parcor) coefficient */
|
||||
if (Inlines.silk_abs(num) < nrg)
|
||||
{
|
||||
rc_Q31 = Inlines.silk_DIV32_varQ(num, nrg, 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc_Q31 = (num > 0) ? int.MaxValue : int.MinValue;
|
||||
}
|
||||
|
||||
/* Update inverse prediction gain */
|
||||
tmp1 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
tmp1 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, tmp1), 2);
|
||||
if (tmp1 <= minInvGain_Q30)
|
||||
{
|
||||
/* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
|
||||
tmp2 = ((int)1 << 30) - Inlines.silk_DIV32_varQ(minInvGain_Q30, invGain_Q30, 30); /* Q30 */
|
||||
rc_Q31 = Inlines.silk_SQRT_APPROX(tmp2); /* Q15 */
|
||||
/* Newton-Raphson iteration */
|
||||
rc_Q31 = Inlines.silk_RSHIFT32(rc_Q31 + Inlines.silk_DIV32(tmp2, rc_Q31), 1); /* Q15 */
|
||||
rc_Q31 = Inlines.silk_LSHIFT32(rc_Q31, 16); /* Q31 */
|
||||
if (num < 0)
|
||||
{
|
||||
/* Ensure adjusted reflection coefficients has the original sign */
|
||||
rc_Q31 = -rc_Q31;
|
||||
}
|
||||
invGain_Q30 = minInvGain_Q30;
|
||||
reached_max_gain = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
invGain_Q30 = tmp1;
|
||||
}
|
||||
|
||||
/* Update the AR coefficients */
|
||||
for (k = 0; k < (n + 1) >> 1; k++)
|
||||
{
|
||||
tmp1 = Af_QA[k]; /* QA */
|
||||
tmp2 = Af_QA[n - k - 1]; /* QA */
|
||||
Af_QA[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* QA */
|
||||
Af_QA[n - k - 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* QA */
|
||||
}
|
||||
Af_QA[n] = Inlines.silk_RSHIFT32(rc_Q31, 31 - QA); /* QA */
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
/* Reached max prediction gain; set remaining coefficients to zero and exit loop */
|
||||
for (k = n + 1; k < D; k++)
|
||||
{
|
||||
Af_QA[k] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update C * Af and C * Ab */
|
||||
for (k = 0; k <= n + 1; k++)
|
||||
{
|
||||
tmp1 = CAf[k]; /* Q( -rshifts ) */
|
||||
tmp2 = CAb[n - k + 1]; /* Q( -rshifts ) */
|
||||
CAf[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
CAb[n - k + 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* Q( -rshifts ) */
|
||||
}
|
||||
}
|
||||
|
||||
if (reached_max_gain != 0)
|
||||
{
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
/* Scale coefficients */
|
||||
A_Q16[k] = -Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16);
|
||||
}
|
||||
/* Subtract energy of preceding samples from C0 */
|
||||
if (rshifts > 0)
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset, D), rshifts);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s = 0; s < nb_subfr; s++)
|
||||
{
|
||||
x_offset = x_ptr + s * subfr_length;
|
||||
C0 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, x_offset, D), -rshifts);
|
||||
}
|
||||
}
|
||||
/* Approximate residual energy */
|
||||
res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, C0), 2);
|
||||
res_nrg_Q.Val = 0 - rshifts;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return residual energy */
|
||||
nrg = CAf[0]; /* Q( -rshifts ) */
|
||||
tmp1 = (int)1 << 16; /* Q16 */
|
||||
for (k = 0; k < D; k++)
|
||||
{
|
||||
Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16); /* Q16 */
|
||||
nrg = Inlines.silk_SMLAWW(nrg, CAf[k + 1], Atmp1); /* Q( -rshifts ) */
|
||||
tmp1 = Inlines.silk_SMLAWW(tmp1, Atmp1, Atmp1); /* Q16 */
|
||||
A_Q16[k] = -Atmp1;
|
||||
}
|
||||
res_nrg.Val = Inlines.silk_SMLAWW(nrg, Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0), -tmp1);/* Q( -rshifts ) */
|
||||
res_nrg_Q.Val = -rshifts;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
232
Libraries/Concentus/CSharp/Concentus/Silk/CNG.cs
Normal file
232
Libraries/Concentus/CSharp/Concentus/Silk/CNG.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// <summary>
|
||||
/// Comfort noise generation and estimation
|
||||
/// </summary>
|
||||
internal static class CNG
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates excitation for CNG LPC synthesis
|
||||
/// </summary>
|
||||
/// <param name="exc_Q10">O CNG excitation signal Q10</param>
|
||||
/// <param name="exc_buf_Q14">I Random samples buffer Q10</param>
|
||||
/// <param name="Gain_Q16">I Gain to apply</param>
|
||||
/// <param name="length">I Length</param>
|
||||
/// <param name="rand_seed">I/O Seed to random index generator</param>
|
||||
internal static void silk_CNG_exc(
|
||||
int[] exc_Q10,
|
||||
int exc_Q10_ptr,
|
||||
int[] exc_buf_Q14,
|
||||
int Gain_Q16,
|
||||
int length,
|
||||
ref int rand_seed)
|
||||
{
|
||||
int seed;
|
||||
int i, idx, exc_mask;
|
||||
|
||||
exc_mask = SilkConstants.CNG_BUF_MASK_MAX;
|
||||
|
||||
while (exc_mask > length)
|
||||
{
|
||||
exc_mask = Inlines.silk_RSHIFT(exc_mask, 1);
|
||||
}
|
||||
|
||||
seed = rand_seed;
|
||||
for (i = exc_Q10_ptr; i < exc_Q10_ptr + length; i++)
|
||||
{
|
||||
seed = Inlines.silk_RAND(seed);
|
||||
idx = (int)(Inlines.silk_RSHIFT(seed, 24) & exc_mask);
|
||||
Inlines.OpusAssert(idx >= 0);
|
||||
Inlines.OpusAssert(idx <= SilkConstants.CNG_BUF_MASK_MAX);
|
||||
exc_Q10[i] = (short)Inlines.silk_SAT16(Inlines.silk_SMULWW(exc_buf_Q14[idx], Gain_Q16 >> 4));
|
||||
}
|
||||
|
||||
rand_seed = seed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets CNG state
|
||||
/// </summary>
|
||||
/// <param name="psDec">I/O Decoder state</param>
|
||||
internal static void silk_CNG_Reset(SilkChannelDecoder psDec)
|
||||
{
|
||||
int i, NLSF_step_Q15, NLSF_acc_Q15;
|
||||
|
||||
NLSF_step_Q15 = Inlines.silk_DIV32_16(short.MaxValue, (short)(psDec.LPC_order + 1));
|
||||
NLSF_acc_Q15 = 0;
|
||||
for (i = 0; i < psDec.LPC_order; i++)
|
||||
{
|
||||
NLSF_acc_Q15 += NLSF_step_Q15;
|
||||
psDec.sCNG.CNG_smth_NLSF_Q15[i] = (short)(NLSF_acc_Q15);
|
||||
}
|
||||
psDec.sCNG.CNG_smth_Gain_Q16 = 0;
|
||||
psDec.sCNG.rand_seed = 3176576;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates CNG estimate, and applies the CNG when packet was lost
|
||||
/// </summary>
|
||||
/// <param name="psDec">I/O Decoder state</param>
|
||||
/// <param name="psDecCtrl">I/O Decoder control</param>
|
||||
/// <param name="frame">I/O Signal</param>
|
||||
/// <param name="length">I Length of residual</param>
|
||||
internal static void silk_CNG(
|
||||
SilkChannelDecoder psDec,
|
||||
SilkDecoderControl psDecCtrl,
|
||||
short[] frame,
|
||||
int frame_ptr,
|
||||
int length)
|
||||
{
|
||||
int i, subfr;
|
||||
int sum_Q6, max_Gain_Q16, gain_Q16;
|
||||
short[] A_Q12 = new short[psDec.LPC_order];
|
||||
CNGState psCNG = psDec.sCNG;
|
||||
|
||||
if (psDec.fs_kHz != psCNG.fs_kHz)
|
||||
{
|
||||
/* Reset state */
|
||||
silk_CNG_Reset(psDec);
|
||||
|
||||
psCNG.fs_kHz = psDec.fs_kHz;
|
||||
}
|
||||
|
||||
if (psDec.lossCnt == 0 && psDec.prevSignalType == SilkConstants.TYPE_NO_VOICE_ACTIVITY)
|
||||
{
|
||||
/* Update CNG parameters */
|
||||
|
||||
/* Smoothing of LSF's */
|
||||
for (i = 0; i < psDec.LPC_order; i++)
|
||||
{
|
||||
psCNG.CNG_smth_NLSF_Q15[i] += (short)(Inlines.silk_SMULWB((int)psDec.prevNLSF_Q15[i] - (int)psCNG.CNG_smth_NLSF_Q15[i], SilkConstants.CNG_NLSF_SMTH_Q16));
|
||||
}
|
||||
|
||||
/* Find the subframe with the highest gain */
|
||||
max_Gain_Q16 = 0;
|
||||
subfr = 0;
|
||||
for (i = 0; i < psDec.nb_subfr; i++)
|
||||
{
|
||||
if (psDecCtrl.Gains_Q16[i] > max_Gain_Q16)
|
||||
{
|
||||
max_Gain_Q16 = psDecCtrl.Gains_Q16[i];
|
||||
subfr = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update CNG excitation buffer with excitation from this subframe */
|
||||
Arrays.MemMoveInt(psCNG.CNG_exc_buf_Q14, 0, psDec.subfr_length, (psDec.nb_subfr - 1) * psDec.subfr_length);
|
||||
|
||||
/* Smooth gains */
|
||||
for (i = 0; i < psDec.nb_subfr; i++)
|
||||
{
|
||||
psCNG.CNG_smth_Gain_Q16 += Inlines.silk_SMULWB(psDecCtrl.Gains_Q16[i] - psCNG.CNG_smth_Gain_Q16, SilkConstants.CNG_GAIN_SMTH_Q16);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add CNG when packet is lost or during DTX */
|
||||
if (psDec.lossCnt != 0)
|
||||
{
|
||||
int[] CNG_sig_Q10 = new int[length + SilkConstants.MAX_LPC_ORDER];
|
||||
|
||||
/* Generate CNG excitation */
|
||||
gain_Q16 = Inlines.silk_SMULWW(psDec.sPLC.randScale_Q14, psDec.sPLC.prevGain_Q16[1]);
|
||||
if (gain_Q16 >= (1 << 21) || psCNG.CNG_smth_Gain_Q16 > (1 << 23))
|
||||
{
|
||||
gain_Q16 = Inlines.silk_SMULTT(gain_Q16, gain_Q16);
|
||||
gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULTT(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5);
|
||||
gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
gain_Q16 = Inlines.silk_SMULWW(gain_Q16, gain_Q16);
|
||||
gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULWW(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5);
|
||||
gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 8);
|
||||
}
|
||||
silk_CNG_exc(CNG_sig_Q10, SilkConstants.MAX_LPC_ORDER, psCNG.CNG_exc_buf_Q14, gain_Q16, length, ref psCNG.rand_seed);
|
||||
|
||||
/* Convert CNG NLSF to filter representation */
|
||||
NLSF.silk_NLSF2A(A_Q12, psCNG.CNG_smth_NLSF_Q15, psDec.LPC_order);
|
||||
|
||||
/* Generate CNG signal, by synthesis filtering */
|
||||
Array.Copy(psCNG.CNG_synth_state, CNG_sig_Q10, SilkConstants.MAX_LPC_ORDER);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
int lpci = SilkConstants.MAX_LPC_ORDER + i;
|
||||
Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16);
|
||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||
sum_Q6 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 1], A_Q12[0]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 2], A_Q12[1]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 3], A_Q12[2]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 4], A_Q12[3]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 5], A_Q12[4]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 6], A_Q12[5]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 7], A_Q12[6]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 8], A_Q12[7]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 9], A_Q12[8]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 10], A_Q12[9]);
|
||||
|
||||
if (psDec.LPC_order == 16)
|
||||
{
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 11], A_Q12[10]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 12], A_Q12[11]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 13], A_Q12[12]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 14], A_Q12[13]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 15], A_Q12[14]);
|
||||
sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 16], A_Q12[15]);
|
||||
}
|
||||
|
||||
/* Update states */
|
||||
CNG_sig_Q10[lpci] = Inlines.silk_ADD_LSHIFT(CNG_sig_Q10[lpci], sum_Q6, 4);
|
||||
|
||||
frame[frame_ptr + i] = Inlines.silk_ADD_SAT16(frame[frame_ptr + i], (short)(Inlines.silk_RSHIFT_ROUND(CNG_sig_Q10[lpci], 10)));
|
||||
}
|
||||
|
||||
Array.Copy(CNG_sig_Q10, length, psCNG.CNG_synth_state, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetInt(psCNG.CNG_synth_state, 0, psDec.LPC_order);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
150
Libraries/Concentus/CSharp/Concentus/Silk/CodeSigns.cs
Normal file
150
Libraries/Concentus/CSharp/Concentus/Silk/CodeSigns.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class CodeSigns
|
||||
{
|
||||
private static int silk_enc_map(int a)
|
||||
{
|
||||
return (Inlines.silk_RSHIFT((a), 15) + 1);
|
||||
}
|
||||
|
||||
private static int silk_dec_map(int a)
|
||||
{
|
||||
return (Inlines.silk_LSHIFT((a), 1) - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes signs of excitation
|
||||
/// </summary>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="pulses">I pulse signal</param>
|
||||
/// <param name="length">I length of input</param>
|
||||
/// <param name="signalType">I Signal type</param>
|
||||
/// <param name="quantOffsetType">I Quantization offset type</param>
|
||||
/// <param name="sum_pulses">I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]</param>
|
||||
internal static void silk_encode_signs(
|
||||
EntropyCoder psRangeEnc,
|
||||
sbyte[] pulses,
|
||||
int length,
|
||||
int signalType,
|
||||
int quantOffsetType,
|
||||
int[] sum_pulses)
|
||||
{
|
||||
int i, j, p;
|
||||
byte[] icdf = new byte[2];
|
||||
int q_ptr;
|
||||
byte[] sign_icdf = Tables.silk_sign_iCDF;
|
||||
int icdf_ptr;
|
||||
|
||||
icdf[1] = 0;
|
||||
q_ptr = 0;
|
||||
i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1));
|
||||
icdf_ptr = i;
|
||||
length = Inlines.silk_RSHIFT(length + (SilkConstants.SHELL_CODEC_FRAME_LENGTH / 2), SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
p = sum_pulses[i];
|
||||
if (p > 0)
|
||||
{
|
||||
icdf[0] = sign_icdf[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)];
|
||||
for (j = q_ptr; j < q_ptr + SilkConstants.SHELL_CODEC_FRAME_LENGTH; j++)
|
||||
{
|
||||
if (pulses[j] != 0)
|
||||
{
|
||||
psRangeEnc.enc_icdf( silk_enc_map(pulses[j]), icdf, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes signs of excitation
|
||||
/// </summary>
|
||||
/// <param name="psRangeDec">I/O Compressor data structure</param>
|
||||
/// <param name="pulses">I/O pulse signal</param>
|
||||
/// <param name="length">I length of input</param>
|
||||
/// <param name="signalType">I Signal type</param>
|
||||
/// <param name="quantOffsetType">I Quantization offset type</param>
|
||||
/// <param name="sum_pulses">I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]</param>
|
||||
internal static void silk_decode_signs(
|
||||
EntropyCoder psRangeDec,
|
||||
short[] pulses,
|
||||
int length,
|
||||
int signalType,
|
||||
int quantOffsetType,
|
||||
int[] sum_pulses)
|
||||
{
|
||||
int i, j, p;
|
||||
byte[] icdf = new byte[2];
|
||||
int q_ptr;
|
||||
byte[] icdf_table = Tables.silk_sign_iCDF;
|
||||
int icdf_ptr;
|
||||
|
||||
icdf[1] = 0;
|
||||
q_ptr = 0;
|
||||
i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1));
|
||||
icdf_ptr = i;
|
||||
length = Inlines.silk_RSHIFT(length + SilkConstants.SHELL_CODEC_FRAME_LENGTH / 2, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
p = sum_pulses[i];
|
||||
|
||||
if (p > 0)
|
||||
{
|
||||
icdf[0] = icdf_table[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)];
|
||||
for (j = 0; j < SilkConstants.SHELL_CODEC_FRAME_LENGTH; j++)
|
||||
{
|
||||
if (pulses[q_ptr + j] > 0)
|
||||
{
|
||||
/* attach sign */
|
||||
pulses[q_ptr + j] *= (short)(silk_dec_map(psRangeDec.dec_icdf(icdf, 8)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
186
Libraries/Concentus/CSharp/Concentus/Silk/CorrelateMatrix.cs
Normal file
186
Libraries/Concentus/CSharp/Concentus/Silk/CorrelateMatrix.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
/**********************************************************************
|
||||
* Correlation Matrix Computations for LS estimate.
|
||||
**********************************************************************/
|
||||
internal static class CorrelateMatrix
|
||||
{
|
||||
/* Calculates correlation vector X'*t */
|
||||
internal static void silk_corrVector(
|
||||
short[] x, /* I x vector [L + order - 1] used to form data matrix X */
|
||||
int x_ptr,
|
||||
short[] t, /* I Target vector [L] */
|
||||
int t_ptr,
|
||||
int L, /* I Length of vectors */
|
||||
int order, /* I Max lag for correlation */
|
||||
int[] Xt, /* O Pointer to X'*t correlation vector [order] */
|
||||
int rshifts /* I Right shifts of correlations */
|
||||
)
|
||||
{
|
||||
int lag, i;
|
||||
int ptr1;
|
||||
int ptr2;
|
||||
int inner_prod;
|
||||
|
||||
ptr1 = x_ptr + order - 1; /* Points to first sample of column 0 of X: X[:,0] */
|
||||
ptr2 = t_ptr;
|
||||
/* Calculate X'*t */
|
||||
if (rshifts > 0)
|
||||
{
|
||||
/* Right shifting used */
|
||||
for (lag = 0; lag < order; lag++)
|
||||
{
|
||||
inner_prod = 0;
|
||||
for (i = 0; i < L; i++)
|
||||
{
|
||||
inner_prod += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + i], t[ptr2 + i]), rshifts);
|
||||
}
|
||||
Xt[lag] = inner_prod; /* X[:,lag]'*t */
|
||||
ptr1--; /* Go to next column of X */
|
||||
}
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(rshifts == 0);
|
||||
for (lag = 0; lag < order; lag++)
|
||||
{
|
||||
Xt[lag] = Inlines.silk_inner_prod(x, ptr1, t, ptr2, L); /* X[:,lag]'*t */
|
||||
ptr1--; /* Go to next column of X */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates correlation matrix X'*X */
|
||||
internal static void silk_corrMatrix(
|
||||
short[] x, /* I x vector [L + order - 1] used to form data matrix X */
|
||||
int x_ptr,
|
||||
int L, /* I Length of vectors */
|
||||
int order, /* I Max lag for correlation */
|
||||
int head_room, /* I Desired headroom */
|
||||
int[] XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
|
||||
int XX_ptr,
|
||||
BoxedValueInt rshifts /* I/O Right shifts of correlations */
|
||||
)
|
||||
{
|
||||
int i, j, lag, head_room_rshifts;
|
||||
int energy, rshifts_local;
|
||||
int ptr1, ptr2;
|
||||
|
||||
/* Calculate energy to find shift used to fit in 32 bits */
|
||||
SumSqrShift.silk_sum_sqr_shift(out energy, out rshifts_local, x, x_ptr, L + order - 1);
|
||||
/* Add shifts to get the desired head room */
|
||||
head_room_rshifts = Inlines.silk_max(head_room - Inlines.silk_CLZ32(energy), 0);
|
||||
|
||||
energy = Inlines.silk_RSHIFT32(energy, head_room_rshifts);
|
||||
rshifts_local += head_room_rshifts;
|
||||
|
||||
/* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */
|
||||
/* Remove contribution of first order - 1 samples */
|
||||
for (i = x_ptr; i < x_ptr + order - 1; i++)
|
||||
{
|
||||
energy -= Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[i], x[i]), rshifts_local);
|
||||
}
|
||||
if (rshifts_local < rshifts.Val)
|
||||
{
|
||||
/* Adjust energy */
|
||||
energy = Inlines.silk_RSHIFT32(energy, rshifts.Val - rshifts_local);
|
||||
rshifts_local = rshifts.Val;
|
||||
}
|
||||
|
||||
/* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */
|
||||
/* Fill out the diagonal of the correlation matrix */
|
||||
Inlines.MatrixSet(XX, XX_ptr, 0, 0, order, energy);
|
||||
ptr1 = x_ptr + order - 1; /* First sample of column 0 of X */
|
||||
for (j = 1; j < order; j++)
|
||||
{
|
||||
energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr1 + L - j]), rshifts_local));
|
||||
energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 - j], x[ptr1 - j]), rshifts_local));
|
||||
Inlines.MatrixSet(XX, XX_ptr, j, j, order, energy);
|
||||
}
|
||||
|
||||
ptr2 = x_ptr + order - 2; /* First sample of column 1 of X */
|
||||
/* Calculate the remaining elements of the correlation matrix */
|
||||
if (rshifts_local > 0)
|
||||
{
|
||||
/* Right shifting used */
|
||||
for (lag = 1; lag < order; lag++)
|
||||
{
|
||||
/* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
|
||||
energy = 0;
|
||||
for (i = 0; i < L; i++)
|
||||
{
|
||||
energy += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + i], x[ptr2 + i]), rshifts_local);
|
||||
}
|
||||
/* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag, 0, order, energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, 0, lag, order, energy);
|
||||
for (j = 1; j < (order - lag); j++)
|
||||
{
|
||||
energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr2 + L - j]), rshifts_local));
|
||||
energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[ptr1 - j], x[ptr2 - j]), rshifts_local));
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag + j, j, order, energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, j, lag + j, order, energy);
|
||||
}
|
||||
ptr2--; /* Update pointer to first sample of next column (lag) in X */
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (lag = 1; lag < order; lag++)
|
||||
{
|
||||
/* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
|
||||
energy = Inlines.silk_inner_prod(x, ptr1, x, ptr2, L);
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag, 0, order,energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, 0, lag, order, energy);
|
||||
/* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
|
||||
for (j = 1; j < (order - lag); j++)
|
||||
{
|
||||
energy = Inlines.silk_SUB32(energy, Inlines.silk_SMULBB(x[ptr1 + L - j], x[ptr2 + L - j]));
|
||||
energy = Inlines.silk_SMLABB(energy, x[ptr1 - j], x[ptr2 - j]);
|
||||
Inlines.MatrixSet(XX, XX_ptr, lag + j, j, order, energy);
|
||||
Inlines.MatrixSet(XX, XX_ptr, j, lag + j, order, energy);
|
||||
}
|
||||
ptr2--;/* Update pointer to first sample of next column (lag) in X */
|
||||
}
|
||||
}
|
||||
rshifts.Val = rshifts_local;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
461
Libraries/Concentus/CSharp/Concentus/Silk/DecodeAPI.cs
Normal file
461
Libraries/Concentus/CSharp/Concentus/Silk/DecodeAPI.cs
Normal file
@@ -0,0 +1,461 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodeAPI
|
||||
{
|
||||
/// <summary>
|
||||
/// Reset decoder state
|
||||
/// </summary>
|
||||
/// <param name="decState">I/O Stat</param>
|
||||
/// <returns>Returns error code</returns>
|
||||
internal static int silk_InitDecoder(SilkDecoder decState)
|
||||
{
|
||||
/* Reset decoder */
|
||||
decState.Reset();
|
||||
|
||||
int n, ret = SilkError.SILK_NO_ERROR;
|
||||
SilkChannelDecoder[] channel_states = decState.channel_state;
|
||||
|
||||
for (n = 0; n < SilkConstants.DECODER_NUM_CHANNELS; n++)
|
||||
{
|
||||
ret = channel_states[n].silk_init_decoder();
|
||||
}
|
||||
|
||||
decState.sStereo.Reset();
|
||||
|
||||
/* Not strictly needed, but it's cleaner that way */
|
||||
decState.prev_decode_only_middle = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Decode a frame */
|
||||
internal static int silk_Decode( /* O Returns error code */
|
||||
SilkDecoder psDec, /* I/O State */
|
||||
DecControlState decControl, /* I/O Control Structure */
|
||||
int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
|
||||
int newPacketFlag, /* I Indicates first decoder call for this packet */
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
short[] samplesOut, /* O Decoded output speech vector */
|
||||
int samplesOut_ptr,
|
||||
out int nSamplesOut /* O Number of samples decoded */
|
||||
)
|
||||
{
|
||||
int i, n, decode_only_middle = 0, ret = SilkError.SILK_NO_ERROR;
|
||||
int LBRR_symbol;
|
||||
BoxedValueInt nSamplesOutDec = new BoxedValueInt();
|
||||
short[] samplesOut_tmp;
|
||||
int[] samplesOut_tmp_ptrs = new int[2];
|
||||
short[] samplesOut1_tmp_storage1;
|
||||
short[] samplesOut1_tmp_storage2;
|
||||
short[] samplesOut2_tmp;
|
||||
int[] MS_pred_Q13 = new int[] { 0, 0 };
|
||||
short[] resample_out;
|
||||
int resample_out_ptr;
|
||||
SilkChannelDecoder[] channel_state = psDec.channel_state;
|
||||
int has_side;
|
||||
int stereo_to_mono;
|
||||
int delay_stack_alloc;
|
||||
nSamplesOut = 0;
|
||||
|
||||
Inlines.OpusAssert(decControl.nChannelsInternal == 1 || decControl.nChannelsInternal == 2);
|
||||
|
||||
/**********************************/
|
||||
/* Test if first frame in payload */
|
||||
/**********************************/
|
||||
if (newPacketFlag != 0)
|
||||
{
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
channel_state[n].nFramesDecoded = 0; /* Used to count frames in packet */
|
||||
}
|
||||
}
|
||||
|
||||
/* If Mono . Stereo transition in bitstream: init state of second channel */
|
||||
if (decControl.nChannelsInternal > psDec.nChannelsInternal)
|
||||
{
|
||||
ret += channel_state[1].silk_init_decoder();
|
||||
}
|
||||
|
||||
stereo_to_mono = (decControl.nChannelsInternal == 1 && psDec.nChannelsInternal == 2 &&
|
||||
(decControl.internalSampleRate == 1000 * channel_state[0].fs_kHz)) ? 1 : 0;
|
||||
|
||||
if (channel_state[0].nFramesDecoded == 0)
|
||||
{
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
int fs_kHz_dec;
|
||||
if (decControl.payloadSize_ms == 0)
|
||||
{
|
||||
/* Assuming packet loss, use 10 ms */
|
||||
channel_state[n].nFramesPerPacket = 1;
|
||||
channel_state[n].nb_subfr = 2;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 10)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 1;
|
||||
channel_state[n].nb_subfr = 2;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 20)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 1;
|
||||
channel_state[n].nb_subfr = 4;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 40)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 2;
|
||||
channel_state[n].nb_subfr = 4;
|
||||
}
|
||||
else if (decControl.payloadSize_ms == 60)
|
||||
{
|
||||
channel_state[n].nFramesPerPacket = 3;
|
||||
channel_state[n].nb_subfr = 4;
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_DEC_INVALID_FRAME_SIZE;
|
||||
}
|
||||
fs_kHz_dec = (decControl.internalSampleRate >> 10) + 1;
|
||||
if (fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY;
|
||||
}
|
||||
ret += channel_state[n].silk_decoder_set_fs(fs_kHz_dec, decControl.API_sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2 && (psDec.nChannelsAPI == 1 || psDec.nChannelsInternal == 1))
|
||||
{
|
||||
Arrays.MemSetShort(psDec.sStereo.pred_prev_Q13, 0, 2);
|
||||
Arrays.MemSetShort(psDec.sStereo.sSide, 0, 2);
|
||||
channel_state[1].resampler_state.Assign(channel_state[0].resampler_state);
|
||||
}
|
||||
psDec.nChannelsAPI = decControl.nChannelsAPI;
|
||||
psDec.nChannelsInternal = decControl.nChannelsInternal;
|
||||
|
||||
if (decControl.API_sampleRate > (int)SilkConstants.MAX_API_FS_KHZ * 1000 || decControl.API_sampleRate < 8000)
|
||||
{
|
||||
ret = SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (lostFlag != DecoderAPIFlag.FLAG_PACKET_LOST && channel_state[0].nFramesDecoded == 0)
|
||||
{
|
||||
/* First decoder call for this payload */
|
||||
/* Decode VAD flags and LBRR flag */
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
for (i = 0; i < channel_state[n].nFramesPerPacket; i++)
|
||||
{
|
||||
channel_state[n].VAD_flags[i] = psRangeDec.dec_bit_logp(1);
|
||||
}
|
||||
channel_state[n].LBRR_flag = psRangeDec.dec_bit_logp(1);
|
||||
}
|
||||
/* Decode LBRR flags */
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
Arrays.MemSetInt(channel_state[n].LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
|
||||
if (channel_state[n].LBRR_flag != 0)
|
||||
{
|
||||
if (channel_state[n].nFramesPerPacket == 1)
|
||||
{
|
||||
channel_state[n].LBRR_flags[0] = 1;
|
||||
}
|
||||
else {
|
||||
LBRR_symbol = psRangeDec.dec_icdf(Tables.silk_LBRR_flags_iCDF_ptr[channel_state[n].nFramesPerPacket - 2], 8) + 1;
|
||||
for (i = 0; i < channel_state[n].nFramesPerPacket; i++)
|
||||
{
|
||||
channel_state[n].LBRR_flags[i] = Inlines.silk_RSHIFT(LBRR_symbol, i) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL)
|
||||
{
|
||||
/* Regular decoding: skip all LBRR data */
|
||||
for (i = 0; i < channel_state[0].nFramesPerPacket; i++)
|
||||
{
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
if (channel_state[n].LBRR_flags[i] != 0)
|
||||
{
|
||||
short[] pulses = new short[SilkConstants.MAX_FRAME_LENGTH];
|
||||
int condCoding;
|
||||
|
||||
if (decControl.nChannelsInternal == 2 && n == 0)
|
||||
{
|
||||
Stereo.silk_stereo_decode_pred(psRangeDec, MS_pred_Q13);
|
||||
if (channel_state[1].LBRR_flags[i] == 0)
|
||||
{
|
||||
BoxedValueInt decodeOnlyMiddleBoxed = new BoxedValueInt(decode_only_middle);
|
||||
Stereo.silk_stereo_decode_mid_only(psRangeDec, decodeOnlyMiddleBoxed);
|
||||
decode_only_middle = decodeOnlyMiddleBoxed.Val;
|
||||
}
|
||||
}
|
||||
/* Use conditional coding if previous frame available */
|
||||
if (i > 0 && (channel_state[n].LBRR_flags[i - 1] != 0))
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
DecodeIndices.silk_decode_indices(channel_state[n], psRangeDec, i, 1, condCoding);
|
||||
DecodePulses.silk_decode_pulses(psRangeDec, pulses, channel_state[n].indices.signalType,
|
||||
channel_state[n].indices.quantOffsetType, channel_state[n].frame_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get MS predictor index */
|
||||
if (decControl.nChannelsInternal == 2)
|
||||
{
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL ||
|
||||
(lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR && channel_state[0].LBRR_flags[channel_state[0].nFramesDecoded] == 1))
|
||||
{
|
||||
Stereo.silk_stereo_decode_pred(psRangeDec, MS_pred_Q13);
|
||||
/* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */
|
||||
if ((lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL && channel_state[1].VAD_flags[channel_state[0].nFramesDecoded] == 0) ||
|
||||
(lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[channel_state[0].nFramesDecoded] == 0))
|
||||
{
|
||||
BoxedValueInt decodeOnlyMiddleBoxed = new BoxedValueInt(decode_only_middle);
|
||||
Stereo.silk_stereo_decode_mid_only(psRangeDec, decodeOnlyMiddleBoxed);
|
||||
decode_only_middle = decodeOnlyMiddleBoxed.Val;
|
||||
}
|
||||
else
|
||||
{
|
||||
decode_only_middle = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (n = 0; n < 2; n++)
|
||||
{
|
||||
MS_pred_Q13[n] = psDec.sStereo.pred_prev_Q13[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset side channel decoder prediction memory for first frame with side coding */
|
||||
if (decControl.nChannelsInternal == 2 && decode_only_middle == 0 && psDec.prev_decode_only_middle == 1)
|
||||
{
|
||||
Arrays.MemSetShort(psDec.channel_state[1].outBuf, 0, SilkConstants.MAX_FRAME_LENGTH + 2 * SilkConstants.MAX_SUB_FRAME_LENGTH);
|
||||
Arrays.MemSetInt(psDec.channel_state[1].sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
psDec.channel_state[1].lagPrev = 100;
|
||||
psDec.channel_state[1].LastGainIndex = 10;
|
||||
psDec.channel_state[1].prevSignalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY;
|
||||
psDec.channel_state[1].first_frame_after_reset = 1;
|
||||
}
|
||||
|
||||
/* Check if the temp buffer fits into the output PCM buffer. If it fits,
|
||||
we can delay allocating the temp buffer until after the SILK peak stack
|
||||
usage. We need to use a < and not a <= because of the two extra samples. */
|
||||
delay_stack_alloc = (decControl.internalSampleRate * decControl.nChannelsInternal
|
||||
< decControl.API_sampleRate * decControl.nChannelsAPI) ? 1 : 0;
|
||||
|
||||
if (delay_stack_alloc != 0)
|
||||
{
|
||||
samplesOut_tmp = samplesOut;
|
||||
samplesOut_tmp_ptrs[0] = samplesOut_ptr;
|
||||
samplesOut_tmp_ptrs[1] = samplesOut_ptr + channel_state[0].frame_length + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
samplesOut1_tmp_storage1 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)];
|
||||
samplesOut_tmp = samplesOut1_tmp_storage1;
|
||||
samplesOut_tmp_ptrs[0] = 0;
|
||||
samplesOut_tmp_ptrs[1] = channel_state[0].frame_length + 2;
|
||||
}
|
||||
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_DECODE_NORMAL)
|
||||
{
|
||||
has_side = (decode_only_middle == 0) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_side = (psDec.prev_decode_only_middle == 0
|
||||
|| (decControl.nChannelsInternal == 2 &&
|
||||
lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR &&
|
||||
channel_state[1].LBRR_flags[channel_state[1].nFramesDecoded] == 1)) ? 1 : 0;
|
||||
}
|
||||
/* Call decoder for one frame */
|
||||
for (n = 0; n < decControl.nChannelsInternal; n++)
|
||||
{
|
||||
if (n == 0 || (has_side != 0))
|
||||
{
|
||||
int FrameIndex;
|
||||
int condCoding;
|
||||
|
||||
FrameIndex = channel_state[0].nFramesDecoded - n;
|
||||
/* Use independent coding if no previous frame available */
|
||||
if (FrameIndex <= 0)
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
else if (lostFlag == DecoderAPIFlag.FLAG_DECODE_LBRR)
|
||||
{
|
||||
condCoding = (channel_state[n].LBRR_flags[FrameIndex - 1] != 0) ? SilkConstants.CODE_CONDITIONALLY : SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
else if (n > 0 && (psDec.prev_decode_only_middle != 0))
|
||||
{
|
||||
/* If we skipped a side frame in this packet, we don't
|
||||
need LTP scaling; the LTP state is well-defined. */
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY_NO_LTP_SCALING;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
ret += channel_state[n].silk_decode_frame(psRangeDec, samplesOut_tmp, samplesOut_tmp_ptrs[n] + 2, nSamplesOutDec, lostFlag, condCoding);
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetWithOffset<short>(samplesOut_tmp, 0, samplesOut_tmp_ptrs[n] + 2, nSamplesOutDec.Val);
|
||||
}
|
||||
channel_state[n].nFramesDecoded++;
|
||||
}
|
||||
|
||||
if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2)
|
||||
{
|
||||
/* Convert Mid/Side to Left/Right */
|
||||
Stereo.silk_stereo_MS_to_LR(psDec.sStereo, samplesOut_tmp, samplesOut_tmp_ptrs[0], samplesOut_tmp, samplesOut_tmp_ptrs[1], MS_pred_Q13, channel_state[0].fs_kHz, nSamplesOutDec.Val);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffering */
|
||||
Array.Copy(psDec.sStereo.sMid, 0, samplesOut_tmp, samplesOut_tmp_ptrs[0], 2);
|
||||
Array.Copy(samplesOut_tmp, samplesOut_tmp_ptrs[0] + nSamplesOutDec.Val, psDec.sStereo.sMid, 0, 2);
|
||||
}
|
||||
|
||||
/* Number of output samples */
|
||||
nSamplesOut = Inlines.silk_DIV32(nSamplesOutDec.Val * decControl.API_sampleRate, Inlines.silk_SMULBB(channel_state[0].fs_kHz, 1000));
|
||||
|
||||
/* Set up pointers to temp buffers */
|
||||
if (decControl.nChannelsAPI == 2)
|
||||
{
|
||||
samplesOut2_tmp = new short[nSamplesOut];
|
||||
resample_out = samplesOut2_tmp;
|
||||
resample_out_ptr = 0;
|
||||
}
|
||||
else {
|
||||
resample_out = samplesOut;
|
||||
resample_out_ptr = samplesOut_ptr;
|
||||
}
|
||||
|
||||
if (delay_stack_alloc != 0)
|
||||
{
|
||||
samplesOut1_tmp_storage2 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)];
|
||||
Array.Copy(samplesOut, samplesOut_ptr, samplesOut1_tmp_storage2, 0, decControl.nChannelsInternal * (channel_state[0].frame_length + 2));
|
||||
samplesOut_tmp = samplesOut1_tmp_storage2;
|
||||
samplesOut_tmp_ptrs[0] = 0;
|
||||
samplesOut_tmp_ptrs[1] = channel_state[0].frame_length + 2;
|
||||
}
|
||||
for (n = 0; n < Inlines.silk_min(decControl.nChannelsAPI, decControl.nChannelsInternal); n++)
|
||||
{
|
||||
|
||||
/* Resample decoded signal to API_sampleRate */
|
||||
ret += Resampler.silk_resampler(channel_state[n].resampler_state, resample_out, resample_out_ptr, samplesOut_tmp, samplesOut_tmp_ptrs[n] + 1, nSamplesOutDec.Val);
|
||||
|
||||
/* Interleave if stereo output and stereo stream */
|
||||
if (decControl.nChannelsAPI == 2)
|
||||
{
|
||||
int nptr = samplesOut_ptr + n;
|
||||
for (i = 0; i < nSamplesOut; i++)
|
||||
{
|
||||
samplesOut[nptr + 2 * i] = resample_out[resample_out_ptr + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create two channel output from mono stream */
|
||||
if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 1)
|
||||
{
|
||||
if (stereo_to_mono != 0)
|
||||
{
|
||||
/* Resample right channel for newly collapsed stereo just in case
|
||||
we weren't doing collapsing when switching to mono */
|
||||
ret += Resampler.silk_resampler(channel_state[1].resampler_state, resample_out, resample_out_ptr, samplesOut_tmp, samplesOut_tmp_ptrs[0] + 1, nSamplesOutDec.Val);
|
||||
|
||||
for (i = 0; i < nSamplesOut; i++)
|
||||
{
|
||||
samplesOut[samplesOut_ptr + 1 + 2 * i] = resample_out[resample_out_ptr + i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < nSamplesOut; i++)
|
||||
{
|
||||
samplesOut[samplesOut_ptr + 1 + 2 * i] = samplesOut[samplesOut_ptr + 2 * i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Export pitch lag, measured at 48 kHz sampling rate */
|
||||
if (channel_state[0].prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
int[] mult_tab = { 6, 4, 3 };
|
||||
decControl.prevPitchLag = channel_state[0].lagPrev * mult_tab[(channel_state[0].fs_kHz - 8) >> 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
decControl.prevPitchLag = 0;
|
||||
}
|
||||
|
||||
if (lostFlag == DecoderAPIFlag.FLAG_PACKET_LOST)
|
||||
{
|
||||
/* On packet loss, remove the gain clamping to prevent having the energy "bounce back"
|
||||
if we lose packets when the energy is going down */
|
||||
for (i = 0; i < psDec.nChannelsInternal; i++)
|
||||
psDec.channel_state[i].LastGainIndex = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
psDec.prev_decode_only_middle = decode_only_middle;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
278
Libraries/Concentus/CSharp/Concentus/Silk/DecodeCore.cs
Normal file
278
Libraries/Concentus/CSharp/Concentus/Silk/DecodeCore.cs
Normal file
@@ -0,0 +1,278 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodeCore
|
||||
{
|
||||
/**********************************************************/
|
||||
/* Core decoder. Performs inverse NSQ operation LTP + LPC */
|
||||
/**********************************************************/
|
||||
internal static void silk_decode_core(
|
||||
SilkChannelDecoder psDec, /* I/O Decoder state */
|
||||
SilkDecoderControl psDecCtrl, /* I Decoder control */
|
||||
short[] xq, /* O Decoded speech */
|
||||
int xq_ptr,
|
||||
short[] pulses /* I Pulse signal [MAX_FRAME_LENGTH] */
|
||||
)
|
||||
{
|
||||
int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType;
|
||||
short[] A_Q12;
|
||||
short[] B_Q14 = psDecCtrl.LTPCoef_Q14;
|
||||
int B_Q14_ptr;
|
||||
int pxq;
|
||||
short[] sLTP;
|
||||
int[] sLTP_Q15;
|
||||
int LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10;
|
||||
int pred_lag_ptr;
|
||||
int pexc_Q14;
|
||||
int[] pres_Q14;
|
||||
int pres_Q14_ptr;
|
||||
int[] res_Q14;
|
||||
int[] sLPC_Q14;
|
||||
|
||||
Inlines.OpusAssert(psDec.prev_gain_Q16 != 0);
|
||||
|
||||
sLTP= new short[psDec.ltp_mem_length];
|
||||
sLTP_Q15 = new int[psDec.ltp_mem_length + psDec.frame_length];
|
||||
res_Q14 = new int[psDec.subfr_length];
|
||||
sLPC_Q14 = new int[psDec.subfr_length + SilkConstants.MAX_LPC_ORDER];
|
||||
|
||||
offset_Q10 = Tables.silk_Quantization_Offsets_Q10[psDec.indices.signalType >> 1][psDec.indices.quantOffsetType];
|
||||
|
||||
if (psDec.indices.NLSFInterpCoef_Q2 < 1 << 2)
|
||||
{
|
||||
NLSF_interpolation_flag = 1;
|
||||
}
|
||||
else {
|
||||
NLSF_interpolation_flag = 0;
|
||||
}
|
||||
|
||||
/* Decode excitation */
|
||||
rand_seed = psDec.indices.Seed;
|
||||
for (i = 0; i < psDec.frame_length; i++)
|
||||
{
|
||||
rand_seed = Inlines.silk_RAND(rand_seed);
|
||||
psDec.exc_Q14[i] = Inlines.silk_LSHIFT((int)pulses[i], 14);
|
||||
if (psDec.exc_Q14[i] > 0)
|
||||
{
|
||||
psDec.exc_Q14[i] -= SilkConstants.QUANT_LEVEL_ADJUST_Q10 << 4;
|
||||
}
|
||||
else
|
||||
if (psDec.exc_Q14[i] < 0)
|
||||
{
|
||||
psDec.exc_Q14[i] += SilkConstants.QUANT_LEVEL_ADJUST_Q10 << 4;
|
||||
}
|
||||
psDec.exc_Q14[i] += offset_Q10 << 4;
|
||||
if (rand_seed < 0)
|
||||
{
|
||||
psDec.exc_Q14[i] = -psDec.exc_Q14[i];
|
||||
}
|
||||
|
||||
rand_seed = Inlines.silk_ADD32_ovflw(rand_seed, pulses[i]);
|
||||
}
|
||||
|
||||
/* Copy LPC state */
|
||||
Array.Copy(psDec.sLPC_Q14_buf, sLPC_Q14, SilkConstants.MAX_LPC_ORDER);
|
||||
|
||||
pexc_Q14 = 0;
|
||||
pxq = xq_ptr;
|
||||
sLTP_buf_idx = psDec.ltp_mem_length;
|
||||
/* Loop over subframes */
|
||||
for (k = 0; k < psDec.nb_subfr; k++)
|
||||
{
|
||||
pres_Q14 = res_Q14;
|
||||
pres_Q14_ptr = 0;
|
||||
A_Q12 = psDecCtrl.PredCoef_Q12[k >> 1];
|
||||
B_Q14_ptr = k * SilkConstants.LTP_ORDER;
|
||||
signalType = psDec.indices.signalType;
|
||||
|
||||
Gain_Q10 = Inlines.silk_RSHIFT(psDecCtrl.Gains_Q16[k], 6);
|
||||
inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(psDecCtrl.Gains_Q16[k], 47);
|
||||
|
||||
/* Calculate gain adjustment factor */
|
||||
if (psDecCtrl.Gains_Q16[k] != psDec.prev_gain_Q16)
|
||||
{
|
||||
gain_adj_Q16 = Inlines.silk_DIV32_varQ(psDec.prev_gain_Q16, psDecCtrl.Gains_Q16[k], 16);
|
||||
|
||||
/* Scale short term state */
|
||||
for (i = 0; i < SilkConstants.MAX_LPC_ORDER; i++)
|
||||
{
|
||||
sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLPC_Q14[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gain_adj_Q16 = (int)1 << 16;
|
||||
}
|
||||
|
||||
/* Save inv_gain */
|
||||
Inlines.OpusAssert(inv_gain_Q31 != 0);
|
||||
psDec.prev_gain_Q16 = psDecCtrl.Gains_Q16[k];
|
||||
|
||||
/* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */
|
||||
if (psDec.lossCnt != 0 && psDec.prevSignalType == SilkConstants.TYPE_VOICED &&
|
||||
psDec.indices.signalType != SilkConstants.TYPE_VOICED && k < SilkConstants.MAX_NB_SUBFR / 2)
|
||||
{
|
||||
|
||||
Arrays.MemSetWithOffset<short>(B_Q14, 0, B_Q14_ptr, SilkConstants.LTP_ORDER);
|
||||
B_Q14[B_Q14_ptr + (SilkConstants.LTP_ORDER / 2)] = (short)(((int)((0.25f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(0.25f, 14)*/);
|
||||
|
||||
signalType = SilkConstants.TYPE_VOICED;
|
||||
psDecCtrl.pitchL[k] = psDec.lagPrev;
|
||||
}
|
||||
|
||||
if (signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Voiced */
|
||||
lag = psDecCtrl.pitchL[k];
|
||||
|
||||
/* Re-whitening */
|
||||
if (k == 0 || (k == 2 && (NLSF_interpolation_flag != 0)))
|
||||
{
|
||||
/* Rewhiten with new A coefs */
|
||||
start_idx = psDec.ltp_mem_length - lag - psDec.LPC_order - SilkConstants.LTP_ORDER / 2;
|
||||
Inlines.OpusAssert(start_idx > 0);
|
||||
|
||||
if (k == 2)
|
||||
{
|
||||
Array.Copy(xq, xq_ptr, psDec.outBuf, psDec.ltp_mem_length, 2 * psDec.subfr_length);
|
||||
}
|
||||
|
||||
Filters.silk_LPC_analysis_filter(sLTP, start_idx, psDec.outBuf, (start_idx + k * psDec.subfr_length),
|
||||
A_Q12, 0, psDec.ltp_mem_length - start_idx, psDec.LPC_order);
|
||||
|
||||
/* After rewhitening the LTP state is unscaled */
|
||||
if (k == 0)
|
||||
{
|
||||
/* Do LTP downscaling to reduce inter-packet dependency */
|
||||
inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, psDecCtrl.LTP_scale_Q14), 2);
|
||||
}
|
||||
for (i = 0; i < lag + SilkConstants.LTP_ORDER / 2; i++)
|
||||
{
|
||||
sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[psDec.ltp_mem_length - i - 1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Update LTP state when Gain changes */
|
||||
if (gain_adj_Q16 != (int)1 << 16)
|
||||
{
|
||||
for (i = 0; i < lag + SilkConstants.LTP_ORDER / 2; i++)
|
||||
{
|
||||
sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[sLTP_buf_idx - i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Long-term prediction */
|
||||
if (signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Set up pointer */
|
||||
pred_lag_ptr = sLTP_buf_idx - lag + SilkConstants.LTP_ORDER / 2;
|
||||
for (i = 0; i < psDec.subfr_length; i++)
|
||||
{
|
||||
/* Unrolled loop */
|
||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||
LTP_pred_Q13 = 2;
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr], B_Q14[B_Q14_ptr]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 1], B_Q14[B_Q14_ptr + 1]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 2], B_Q14[B_Q14_ptr + 2]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 3], B_Q14[B_Q14_ptr + 3]);
|
||||
LTP_pred_Q13 = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 4], B_Q14[B_Q14_ptr + 4]);
|
||||
pred_lag_ptr += 1;
|
||||
|
||||
/* Generate LPC excitation */
|
||||
pres_Q14[pres_Q14_ptr + i] = Inlines.silk_ADD_LSHIFT32(psDec.exc_Q14[pexc_Q14 + i], LTP_pred_Q13, 1);
|
||||
|
||||
/* Update states */
|
||||
sLTP_Q15[sLTP_buf_idx] = Inlines.silk_LSHIFT(pres_Q14[pres_Q14_ptr + i], 1);
|
||||
sLTP_buf_idx++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pres_Q14 = psDec.exc_Q14;
|
||||
pres_Q14_ptr = pexc_Q14;
|
||||
}
|
||||
|
||||
for (i = 0; i < psDec.subfr_length; i++)
|
||||
{
|
||||
/* Short-term prediction */
|
||||
Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16);
|
||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||
LPC_pred_Q10 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 1], A_Q12[0]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 2], A_Q12[1]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 3], A_Q12[2]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 4], A_Q12[3]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 5], A_Q12[4]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 6], A_Q12[5]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 7], A_Q12[6]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 8], A_Q12[7]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 9], A_Q12[8]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 10], A_Q12[9]);
|
||||
if (psDec.LPC_order == 16)
|
||||
{
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 11], A_Q12[10]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 12], A_Q12[11]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 13], A_Q12[12]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 14], A_Q12[13]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 15], A_Q12[14]);
|
||||
LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 16], A_Q12[15]);
|
||||
}
|
||||
|
||||
/* Add prediction to LPC excitation */
|
||||
sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i] = Inlines.silk_ADD_LSHIFT32(pres_Q14[pres_Q14_ptr + i], LPC_pred_Q10, 4);
|
||||
|
||||
/* Scale with gain */
|
||||
xq[pxq + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i], Gain_Q10), 8));
|
||||
}
|
||||
|
||||
/* DEBUG_STORE_DATA( dec.pcm, pxq, psDec.subfr_length * sizeof( short ) ) */
|
||||
|
||||
/* Update LPC filter state */
|
||||
Array.Copy(sLPC_Q14, psDec.subfr_length, sLPC_Q14, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
pexc_Q14 += psDec.subfr_length;
|
||||
pxq += psDec.subfr_length;
|
||||
}
|
||||
|
||||
/* Save LPC state */
|
||||
Array.Copy(sLPC_Q14, 0, psDec.sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
}
|
||||
}
|
||||
179
Libraries/Concentus/CSharp/Concentus/Silk/DecodeIndices.cs
Normal file
179
Libraries/Concentus/CSharp/Concentus/Silk/DecodeIndices.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodeIndices
|
||||
{
|
||||
/* Decode side-information parameters from payload */
|
||||
internal static void silk_decode_indices(
|
||||
SilkChannelDecoder psDec, /* I/O State */
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
int FrameIndex, /* I Frame number */
|
||||
int decode_LBRR, /* I Flag indicating LBRR data is being decoded */
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
int i, k, Ix;
|
||||
int decode_absolute_lagIndex, delta_lagIndex;
|
||||
short[] ec_ix = new short[psDec.LPC_order];
|
||||
byte[] pred_Q8 = new byte[psDec.LPC_order];
|
||||
|
||||
/*******************************************/
|
||||
/* Decode signal type and quantizer offset */
|
||||
/*******************************************/
|
||||
if (decode_LBRR != 0 || psDec.VAD_flags[FrameIndex] != 0)
|
||||
{
|
||||
Ix = psRangeDec.dec_icdf(Tables.silk_type_offset_VAD_iCDF, 8) + 2;
|
||||
}
|
||||
else {
|
||||
Ix = psRangeDec.dec_icdf(Tables.silk_type_offset_no_VAD_iCDF, 8);
|
||||
}
|
||||
psDec.indices.signalType = (sbyte)Inlines.silk_RSHIFT(Ix, 1);
|
||||
psDec.indices.quantOffsetType = (sbyte)(Ix & 1);
|
||||
|
||||
/****************/
|
||||
/* Decode gains */
|
||||
/****************/
|
||||
/* First subframe */
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY)
|
||||
{
|
||||
/* Conditional coding */
|
||||
psDec.indices.GainsIndices[0] = (sbyte)psRangeDec.dec_icdf(Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
else {
|
||||
/* Independent coding, in two stages: MSB bits followed by 3 LSBs */
|
||||
psDec.indices.GainsIndices[0] = (sbyte)Inlines.silk_LSHIFT(psRangeDec.dec_icdf(Tables.silk_gain_iCDF[psDec.indices.signalType], 8), 3);
|
||||
psDec.indices.GainsIndices[0] += (sbyte)psRangeDec.dec_icdf(Tables.silk_uniform8_iCDF, 8);
|
||||
}
|
||||
|
||||
/* Remaining subframes */
|
||||
for (i = 1; i < psDec.nb_subfr; i++)
|
||||
{
|
||||
psDec.indices.GainsIndices[i] = (sbyte)psRangeDec.dec_icdf(Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Decode LSF Indices */
|
||||
/**********************/
|
||||
psDec.indices.NLSFIndices[0] = (sbyte)psRangeDec.dec_icdf(psDec.psNLSF_CB.CB1_iCDF, (psDec.indices.signalType >> 1) * psDec.psNLSF_CB.nVectors, 8);
|
||||
NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psDec.psNLSF_CB, psDec.indices.NLSFIndices[0]);
|
||||
Inlines.OpusAssert(psDec.psNLSF_CB.order == psDec.LPC_order);
|
||||
for (i = 0; i < psDec.psNLSF_CB.order; i++)
|
||||
{
|
||||
Ix = psRangeDec.dec_icdf(psDec.psNLSF_CB.ec_iCDF, (ec_ix[i]), 8);
|
||||
if (Ix == 0)
|
||||
{
|
||||
Ix -= psRangeDec.dec_icdf(Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
else if (Ix == 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE)
|
||||
{
|
||||
Ix += psRangeDec.dec_icdf(Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
psDec.indices.NLSFIndices[i + 1] = (sbyte)(Ix - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE);
|
||||
}
|
||||
|
||||
/* Decode LSF interpolation factor */
|
||||
if (psDec.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
psDec.indices.NLSFInterpCoef_Q2 = (sbyte)psRangeDec.dec_icdf(Tables.silk_NLSF_interpolation_factor_iCDF, 8);
|
||||
}
|
||||
else {
|
||||
psDec.indices.NLSFInterpCoef_Q2 = 4;
|
||||
}
|
||||
|
||||
if (psDec.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/*********************/
|
||||
/* Decode pitch lags */
|
||||
/*********************/
|
||||
/* Get lag index */
|
||||
decode_absolute_lagIndex = 1;
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY && psDec.ec_prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Decode Delta index */
|
||||
delta_lagIndex = (short)psRangeDec.dec_icdf(Tables.silk_pitch_delta_iCDF, 8);
|
||||
if (delta_lagIndex > 0)
|
||||
{
|
||||
delta_lagIndex = delta_lagIndex - 9;
|
||||
psDec.indices.lagIndex = (short)(psDec.ec_prevLagIndex + delta_lagIndex);
|
||||
decode_absolute_lagIndex = 0;
|
||||
}
|
||||
}
|
||||
if (decode_absolute_lagIndex != 0)
|
||||
{
|
||||
/* Absolute decoding */
|
||||
psDec.indices.lagIndex = (short)(psRangeDec.dec_icdf(Tables.silk_pitch_lag_iCDF, 8) * Inlines.silk_RSHIFT(psDec.fs_kHz, 1));
|
||||
psDec.indices.lagIndex += (short)psRangeDec.dec_icdf(psDec.pitch_lag_low_bits_iCDF, 8);
|
||||
}
|
||||
psDec.ec_prevLagIndex = psDec.indices.lagIndex;
|
||||
|
||||
/* Get countour index */
|
||||
psDec.indices.contourIndex = (sbyte)psRangeDec.dec_icdf(psDec.pitch_contour_iCDF, 8);
|
||||
|
||||
/********************/
|
||||
/* Decode LTP gains */
|
||||
/********************/
|
||||
/* Decode PERIndex value */
|
||||
psDec.indices.PERIndex = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTP_per_index_iCDF, 8);
|
||||
|
||||
for (k = 0; k < psDec.nb_subfr; k++)
|
||||
{
|
||||
psDec.indices.LTPIndex[k] = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTP_gain_iCDF_ptrs[psDec.indices.PERIndex], 8);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Decode LTP scaling */
|
||||
/**********************/
|
||||
if (condCoding == SilkConstants.CODE_INDEPENDENTLY)
|
||||
{
|
||||
psDec.indices.LTP_scaleIndex = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTPscale_iCDF, 8);
|
||||
}
|
||||
else {
|
||||
psDec.indices.LTP_scaleIndex = 0;
|
||||
}
|
||||
}
|
||||
psDec.ec_prevSignalType = psDec.indices.signalType;
|
||||
|
||||
/***************/
|
||||
/* Decode seed */
|
||||
/***************/
|
||||
psDec.indices.Seed = (sbyte)psRangeDec.dec_icdf(Tables.silk_uniform4_iCDF, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
141
Libraries/Concentus/CSharp/Concentus/Silk/DecodeParameters.cs
Normal file
141
Libraries/Concentus/CSharp/Concentus/Silk/DecodeParameters.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal class DecodeParameters
|
||||
{
|
||||
/* Decode parameters from payload */
|
||||
internal static void silk_decode_parameters(
|
||||
SilkChannelDecoder psDec, /* I/O State */
|
||||
SilkDecoderControl psDecCtrl, /* I/O Decoder control */
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
int i, k, Ix;
|
||||
short[] pNLSF_Q15 = new short[psDec.LPC_order];
|
||||
short[] pNLSF0_Q15 = new short[psDec.LPC_order];
|
||||
sbyte[][] cbk_ptr_Q7;
|
||||
|
||||
/* Dequant Gains */
|
||||
BoxedValueSbyte boxedLastGainIndex = new BoxedValueSbyte(psDec.LastGainIndex);
|
||||
GainQuantization.silk_gains_dequant(psDecCtrl.Gains_Q16, psDec.indices.GainsIndices,
|
||||
boxedLastGainIndex, condCoding == SilkConstants.CODE_CONDITIONALLY ? 1 : 0, psDec.nb_subfr);
|
||||
psDec.LastGainIndex = boxedLastGainIndex.Val;
|
||||
|
||||
/****************/
|
||||
/* Decode NLSFs */
|
||||
/****************/
|
||||
NLSF.silk_NLSF_decode(pNLSF_Q15, psDec.indices.NLSFIndices, psDec.psNLSF_CB);
|
||||
|
||||
/* Convert NLSF parameters to AR prediction filter coefficients */
|
||||
NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[1], pNLSF_Q15, psDec.LPC_order);
|
||||
|
||||
/* If just reset, e.g., because internal Fs changed, do not allow interpolation */
|
||||
/* improves the case of packet loss in the first frame after a switch */
|
||||
if (psDec.first_frame_after_reset == 1)
|
||||
{
|
||||
psDec.indices.NLSFInterpCoef_Q2 = 4;
|
||||
}
|
||||
|
||||
if (psDec.indices.NLSFInterpCoef_Q2 < 4)
|
||||
{
|
||||
/* Calculation of the interpolated NLSF0 vector from the interpolation factor, */
|
||||
/* the previous NLSF1, and the current NLSF1 */
|
||||
for (i = 0; i < psDec.LPC_order; i++)
|
||||
{
|
||||
pNLSF0_Q15[i] = (short)(psDec.prevNLSF_Q15[i] + Inlines.silk_RSHIFT(Inlines.silk_MUL(psDec.indices.NLSFInterpCoef_Q2,
|
||||
pNLSF_Q15[i] - psDec.prevNLSF_Q15[i]), 2));
|
||||
}
|
||||
|
||||
/* Convert NLSF parameters to AR prediction filter coefficients */
|
||||
NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[0], pNLSF0_Q15, psDec.LPC_order);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy LPC coefficients for first half from second half */
|
||||
Array.Copy(psDecCtrl.PredCoef_Q12[1], psDecCtrl.PredCoef_Q12[0], psDec.LPC_order);
|
||||
}
|
||||
|
||||
Array.Copy(pNLSF_Q15, psDec.prevNLSF_Q15, psDec.LPC_order);
|
||||
|
||||
/* After a packet loss do BWE of LPC coefs */
|
||||
if (psDec.lossCnt != 0)
|
||||
{
|
||||
BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[0], psDec.LPC_order, SilkConstants.BWE_AFTER_LOSS_Q16);
|
||||
BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[1], psDec.LPC_order, SilkConstants.BWE_AFTER_LOSS_Q16);
|
||||
}
|
||||
|
||||
if (psDec.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/*********************/
|
||||
/* Decode pitch lags */
|
||||
/*********************/
|
||||
|
||||
/* Decode pitch values */
|
||||
DecodePitch.silk_decode_pitch(psDec.indices.lagIndex, psDec.indices.contourIndex, psDecCtrl.pitchL, psDec.fs_kHz, psDec.nb_subfr);
|
||||
|
||||
/* Decode Codebook Index */
|
||||
cbk_ptr_Q7 = Tables.silk_LTP_vq_ptrs_Q7[psDec.indices.PERIndex]; /* set pointer to start of codebook */
|
||||
|
||||
for (k = 0; k < psDec.nb_subfr; k++)
|
||||
{
|
||||
Ix = psDec.indices.LTPIndex[k];
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
psDecCtrl.LTPCoef_Q14[k * SilkConstants.LTP_ORDER + i] = (short)(Inlines.silk_LSHIFT(cbk_ptr_Q7[Ix][i], 7));
|
||||
}
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Decode LTP scaling */
|
||||
/**********************/
|
||||
Ix = psDec.indices.LTP_scaleIndex;
|
||||
psDecCtrl.LTP_scale_Q14 = Tables.silk_LTPScales_table_Q14[Ix];
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetInt(psDecCtrl.pitchL, 0, psDec.nb_subfr);
|
||||
Arrays.MemSetShort(psDecCtrl.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER * psDec.nb_subfr);
|
||||
psDec.indices.PERIndex = 0;
|
||||
psDecCtrl.LTP_scale_Q14 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Libraries/Concentus/CSharp/Concentus/Silk/DecodePitch.cs
Normal file
90
Libraries/Concentus/CSharp/Concentus/Silk/DecodePitch.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodePitch
|
||||
{
|
||||
internal static void silk_decode_pitch(
|
||||
short lagIndex, /* I */
|
||||
sbyte contourIndex, /* O */
|
||||
int[] pitch_lags, /* O 4 pitch values */
|
||||
int Fs_kHz, /* I sampling frequency (kHz) */
|
||||
int nb_subfr /* I number of sub frames */
|
||||
)
|
||||
{
|
||||
int lag, k, min_lag, max_lag;
|
||||
sbyte[][] Lag_CB_ptr;
|
||||
|
||||
if (Fs_kHz == 8)
|
||||
{
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage2_10_ms;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR)
|
||||
{
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1);
|
||||
Lag_CB_ptr = Tables.silk_CB_lags_stage3_10_ms;
|
||||
}
|
||||
}
|
||||
|
||||
min_lag = Inlines.silk_SMULBB(SilkConstants.PE_MIN_LAG_MS, Fs_kHz);
|
||||
max_lag = Inlines.silk_SMULBB(SilkConstants.PE_MAX_LAG_MS, Fs_kHz);
|
||||
lag = min_lag + lagIndex;
|
||||
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
pitch_lags[k] = lag + Lag_CB_ptr[k][contourIndex];
|
||||
pitch_lags[k] = Inlines.silk_LIMIT(pitch_lags[k], min_lag, max_lag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Libraries/Concentus/CSharp/Concentus/Silk/DecodePulses.cs
Normal file
136
Libraries/Concentus/CSharp/Concentus/Silk/DecodePulses.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DecodePulses
|
||||
{
|
||||
/*********************************************/
|
||||
/* Decode quantization indices of excitation */
|
||||
/*********************************************/
|
||||
internal static void silk_decode_pulses(
|
||||
EntropyCoder psRangeDec, /* I/O Compressor data structure */
|
||||
short[] pulses, /* O Excitation signal */
|
||||
int signalType, /* I Sigtype */
|
||||
int quantOffsetType, /* I quantOffsetType */
|
||||
int frame_length /* I Frame length */
|
||||
)
|
||||
{
|
||||
int i, j, k, iter, abs_q, nLS, RateLevelIndex;
|
||||
int[] sum_pulses = new int[SilkConstants.MAX_NB_SHELL_BLOCKS];
|
||||
int[] nLshifts = new int[SilkConstants.MAX_NB_SHELL_BLOCKS];
|
||||
int pulses_ptr;
|
||||
|
||||
/*********************/
|
||||
/* Decode rate level */
|
||||
/*********************/
|
||||
RateLevelIndex = psRangeDec.dec_icdf(Tables.silk_rate_levels_iCDF[signalType >> 1], 8);
|
||||
|
||||
/* Calculate number of shell blocks */
|
||||
Inlines.OpusAssert(1 << SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH == SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
iter = Inlines.silk_RSHIFT(frame_length, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
if (iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH < frame_length)
|
||||
{
|
||||
Inlines.OpusAssert(frame_length == 12 * 10); /* Make sure only happens for 10 ms @ 12 kHz */
|
||||
iter++;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/* Sum-Weighted-Pulses Decoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
nLshifts[i] = 0;
|
||||
sum_pulses[i] = psRangeDec.dec_icdf(Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
|
||||
|
||||
/* LSB indication */
|
||||
while (sum_pulses[i] == SilkConstants.SILK_MAX_PULSES + 1)
|
||||
{
|
||||
nLshifts[i]++;
|
||||
/* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */
|
||||
sum_pulses[i] = psRangeDec.dec_icdf(
|
||||
Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], (nLshifts[i] == 10 ? 1 : 0), 8);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/* Shell decoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (sum_pulses[i] > 0)
|
||||
{
|
||||
ShellCoder.silk_shell_decoder(pulses, Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH), psRangeDec, sum_pulses[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.MemSetWithOffset<short>(pulses, 0, Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH), SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
/* LSB Decoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nLshifts[i] > 0)
|
||||
{
|
||||
nLS = nLshifts[i];
|
||||
pulses_ptr = Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
for (k = 0; k < SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++)
|
||||
{
|
||||
abs_q = pulses[pulses_ptr + k];
|
||||
for (j = 0; j < nLS; j++)
|
||||
{
|
||||
abs_q = Inlines.silk_LSHIFT(abs_q, 1);
|
||||
abs_q += psRangeDec.dec_icdf(Tables.silk_lsb_iCDF, 8);
|
||||
}
|
||||
pulses[pulses_ptr + k] = (short)(abs_q);
|
||||
}
|
||||
/* Mark the number of pulses non-zero for sign decoding. */
|
||||
sum_pulses[i] |= nLS << 5;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
/* Decode and add signs to pulse signal */
|
||||
/****************************************/
|
||||
CodeSigns.silk_decode_signs(psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses);
|
||||
}
|
||||
}
|
||||
}
|
||||
740
Libraries/Concentus/CSharp/Concentus/Silk/EncodeAPI.cs
Normal file
740
Libraries/Concentus/CSharp/Concentus/Silk/EncodeAPI.cs
Normal file
@@ -0,0 +1,740 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class EncodeAPI
|
||||
{
|
||||
/// <summary>
|
||||
/// Init or Reset encoder
|
||||
/// </summary>
|
||||
/// <param name="encState">I/O State</param>
|
||||
/// <param name="encStatus">O Encoder Status</param>
|
||||
/// <returns>O Returns error code</returns>
|
||||
internal static int silk_InitEncoder(SilkEncoder encState, EncControlState encStatus)
|
||||
{
|
||||
int ret = SilkError.SILK_NO_ERROR;
|
||||
|
||||
/* Reset encoder */
|
||||
encState.Reset();
|
||||
|
||||
for (int n = 0; n < SilkConstants.ENCODER_NUM_CHANNELS; n++)
|
||||
{
|
||||
ret += SilkEncoder.silk_init_encoder(encState.state_Fxx[n]);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
}
|
||||
|
||||
encState.nChannelsAPI = 1;
|
||||
encState.nChannelsInternal = 1;
|
||||
|
||||
/* Read control structure */
|
||||
ret += silk_QueryEncoder(encState, encStatus);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read control structure from encode
|
||||
/// </summary>
|
||||
/// <param name="encState">I State</param>
|
||||
/// <param name="encStatus">O Encoder Status</param>
|
||||
/// <returns>Returns error code</returns>
|
||||
internal static int silk_QueryEncoder(SilkEncoder encState, EncControlState encStatus)
|
||||
{
|
||||
int ret = SilkError.SILK_NO_ERROR;
|
||||
SilkChannelEncoder state_Fxx = encState.state_Fxx[0];
|
||||
|
||||
encStatus.Reset();
|
||||
|
||||
encStatus.nChannelsAPI = encState.nChannelsAPI;
|
||||
encStatus.nChannelsInternal = encState.nChannelsInternal;
|
||||
encStatus.API_sampleRate = state_Fxx.API_fs_Hz;
|
||||
encStatus.maxInternalSampleRate = state_Fxx.maxInternal_fs_Hz;
|
||||
encStatus.minInternalSampleRate = state_Fxx.minInternal_fs_Hz;
|
||||
encStatus.desiredInternalSampleRate = state_Fxx.desiredInternal_fs_Hz;
|
||||
encStatus.payloadSize_ms = state_Fxx.PacketSize_ms;
|
||||
encStatus.bitRate = state_Fxx.TargetRate_bps;
|
||||
encStatus.packetLossPercentage = state_Fxx.PacketLoss_perc;
|
||||
encStatus.complexity = state_Fxx.Complexity;
|
||||
encStatus.useInBandFEC = state_Fxx.useInBandFEC;
|
||||
encStatus.useDTX = state_Fxx.useDTX;
|
||||
encStatus.useCBR = state_Fxx.useCBR;
|
||||
encStatus.internalSampleRate = Inlines.silk_SMULBB(state_Fxx.fs_kHz, 1000);
|
||||
encStatus.allowBandwidthSwitch = state_Fxx.allow_bandwidth_switch;
|
||||
encStatus.inWBmodeWithoutVariableLP = (state_Fxx.fs_kHz == 16 && state_Fxx.sLP.mode == 0) ? 1 : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode frame with Silk
|
||||
/// Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what
|
||||
/// encControl.payloadSize_ms is set to
|
||||
/// </summary>
|
||||
/// <param name="psEnc">I/O State</param>
|
||||
/// <param name="encControl">I Control status</param>
|
||||
/// <param name="samplesIn">I Speech sample input vector</param>
|
||||
/// <param name="nSamplesIn">I Number of samples in input vector</param>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="nBytesOut">I/O Number of bytes in payload (input: Max bytes)</param>
|
||||
/// <param name="prefillFlag">I Flag to indicate prefilling buffers no coding</param>
|
||||
/// <returns>error code</returns>
|
||||
internal static int silk_Encode(
|
||||
SilkEncoder psEnc,
|
||||
EncControlState encControl,
|
||||
short[] samplesIn,
|
||||
int nSamplesIn,
|
||||
EntropyCoder psRangeEnc,
|
||||
BoxedValueInt nBytesOut,
|
||||
int prefillFlag)
|
||||
{
|
||||
int ret = SilkError.SILK_NO_ERROR;
|
||||
int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0;
|
||||
int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms;
|
||||
int nSamplesFromInput = 0, nSamplesFromInputMax;
|
||||
int speech_act_thr_for_switch_Q8;
|
||||
int TargetRate_bps, channelRate_bps, LBRR_symbol, sum;
|
||||
int[] MStargetRates_bps = new int[2];
|
||||
short[] buf;
|
||||
int transition, curr_block, tot_blocks;
|
||||
nBytesOut.Val = 0;
|
||||
|
||||
if (encControl.reducedDependency != 0)
|
||||
{
|
||||
psEnc.state_Fxx[0].first_frame_after_reset = 1;
|
||||
psEnc.state_Fxx[1].first_frame_after_reset = 1;
|
||||
}
|
||||
psEnc.state_Fxx[0].nFramesEncoded = psEnc.state_Fxx[1].nFramesEncoded = 0;
|
||||
|
||||
/* Check values in encoder control structure */
|
||||
ret += encControl.check_control_input();
|
||||
if (ret != SilkError.SILK_NO_ERROR)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
encControl.switchReady = 0;
|
||||
|
||||
if (encControl.nChannelsInternal > psEnc.nChannelsInternal)
|
||||
{
|
||||
/* Mono . Stereo transition: init state of second channel and stereo state */
|
||||
ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[1]);
|
||||
|
||||
Arrays.MemSetShort(psEnc.sStereo.pred_prev_Q13, 0, 2);
|
||||
Arrays.MemSetShort(psEnc.sStereo.sSide, 0, 2);
|
||||
psEnc.sStereo.mid_side_amp_Q0[0] = 0;
|
||||
psEnc.sStereo.mid_side_amp_Q0[1] = 1;
|
||||
psEnc.sStereo.mid_side_amp_Q0[2] = 0;
|
||||
psEnc.sStereo.mid_side_amp_Q0[3] = 1;
|
||||
psEnc.sStereo.width_prev_Q14 = 0;
|
||||
psEnc.sStereo.smth_width_Q14 = (short)(((int)((1.0f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(1.0f, 14)*/);
|
||||
if (psEnc.nChannelsAPI == 2)
|
||||
{
|
||||
psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state);
|
||||
Array.Copy(psEnc.state_Fxx[0].In_HP_State, psEnc.state_Fxx[1].In_HP_State, 2);
|
||||
}
|
||||
}
|
||||
|
||||
transition = ((encControl.payloadSize_ms != psEnc.state_Fxx[0].PacketSize_ms) || (psEnc.nChannelsInternal != encControl.nChannelsInternal)) ? 1 : 0;
|
||||
|
||||
psEnc.nChannelsAPI = encControl.nChannelsAPI;
|
||||
psEnc.nChannelsInternal = encControl.nChannelsInternal;
|
||||
|
||||
nBlocksOf10ms = Inlines.silk_DIV32(100 * nSamplesIn, encControl.API_sampleRate);
|
||||
tot_blocks = (nBlocksOf10ms > 1) ? nBlocksOf10ms >> 1 : 1;
|
||||
curr_block = 0;
|
||||
if (prefillFlag != 0)
|
||||
{
|
||||
/* Only accept input length of 10 ms */
|
||||
if (nBlocksOf10ms != 1)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
|
||||
}
|
||||
/* Reset Encoder */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[n]);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
}
|
||||
tmp_payloadSize_ms = encControl.payloadSize_ms;
|
||||
encControl.payloadSize_ms = 10;
|
||||
tmp_complexity = encControl.complexity;
|
||||
encControl.complexity = 0;
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
psEnc.state_Fxx[n].controlled_since_last_payload = 0;
|
||||
psEnc.state_Fxx[n].prefillFlag = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only accept input lengths that are a multiple of 10 ms */
|
||||
if (nBlocksOf10ms * encControl.API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
|
||||
}
|
||||
/* Make sure no more than one packet can be produced */
|
||||
if (1000 * (int)nSamplesIn > encControl.payloadSize_ms * encControl.API_sampleRate)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
|
||||
}
|
||||
}
|
||||
|
||||
TargetRate_bps = Inlines.silk_RSHIFT32(encControl.bitRate, encControl.nChannelsInternal - 1);
|
||||
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
/* Force the side channel to the same rate as the mid */
|
||||
int force_fs_kHz = (n == 1) ? psEnc.state_Fxx[0].fs_kHz : 0;
|
||||
ret += psEnc.state_Fxx[n].silk_control_encoder(encControl, TargetRate_bps, psEnc.allowBandwidthSwitch, n, force_fs_kHz);
|
||||
|
||||
if (ret != SilkError.SILK_NO_ERROR)
|
||||
{
|
||||
Inlines.OpusAssert(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (psEnc.state_Fxx[n].first_frame_after_reset != 0 || transition != 0)
|
||||
{
|
||||
for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; i++)
|
||||
{
|
||||
psEnc.state_Fxx[n].LBRR_flags[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[n].inDTX = psEnc.state_Fxx[n].useDTX;
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[0].fs_kHz == psEnc.state_Fxx[1].fs_kHz);
|
||||
|
||||
/* Input buffering/resampling and encoding */
|
||||
nSamplesToBufferMax = 10 * nBlocksOf10ms * psEnc.state_Fxx[0].fs_kHz;
|
||||
nSamplesFromInputMax =
|
||||
Inlines.silk_DIV32_16(nSamplesToBufferMax *
|
||||
psEnc.state_Fxx[0].API_fs_Hz,
|
||||
(short)(psEnc.state_Fxx[0].fs_kHz * 1000));
|
||||
|
||||
buf = new short[nSamplesFromInputMax];
|
||||
|
||||
int samplesIn_ptr = 0;
|
||||
while (true)
|
||||
{
|
||||
nSamplesToBuffer = psEnc.state_Fxx[0].frame_length - psEnc.state_Fxx[0].inputBufIx;
|
||||
nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, nSamplesToBufferMax);
|
||||
nSamplesFromInput = Inlines.silk_DIV32_16(nSamplesToBuffer * psEnc.state_Fxx[0].API_fs_Hz, psEnc.state_Fxx[0].fs_kHz * 1000);
|
||||
|
||||
/* Resample and write to buffer */
|
||||
if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 2)
|
||||
{
|
||||
int id = psEnc.state_Fxx[0].nFramesEncoded;
|
||||
for (n = 0; n < nSamplesFromInput; n++)
|
||||
{
|
||||
buf[n] = samplesIn[samplesIn_ptr + (2 * n)];
|
||||
}
|
||||
|
||||
/* Making sure to start both resamplers from the same state when switching from mono to stereo */
|
||||
if (psEnc.nPrevChannelsInternal == 1 && id == 0)
|
||||
{
|
||||
//silk_memcpy(&psEnc.state_Fxx[1].resampler_state, &psEnc.state_Fxx[0].resampler_state, sizeof(psEnc.state_Fxx[1].resampler_state));
|
||||
psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state);
|
||||
}
|
||||
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[0].resampler_state,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
psEnc.state_Fxx[0].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer;
|
||||
|
||||
nSamplesToBuffer = psEnc.state_Fxx[1].frame_length - psEnc.state_Fxx[1].inputBufIx;
|
||||
nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc.state_Fxx[1].fs_kHz);
|
||||
for (n = 0; n < nSamplesFromInput; n++)
|
||||
{
|
||||
buf[n] = samplesIn[samplesIn_ptr + (2 * n) + 1];
|
||||
}
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[1].resampler_state,
|
||||
psEnc.state_Fxx[1].inputBuf,
|
||||
psEnc.state_Fxx[1].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
psEnc.state_Fxx[1].inputBufIx += nSamplesToBuffer;
|
||||
}
|
||||
else if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 1)
|
||||
{
|
||||
/* Combine left and right channels before resampling */
|
||||
for (n = 0; n < nSamplesFromInput; n++)
|
||||
{
|
||||
sum = samplesIn[samplesIn_ptr + (2 * n)] + samplesIn[samplesIn_ptr + (2 * n) + 1];
|
||||
buf[n] = (short)Inlines.silk_RSHIFT_ROUND(sum, 1);
|
||||
}
|
||||
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[0].resampler_state,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
psEnc.state_Fxx[0].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
/* On the first mono frame, average the results for the two resampler states */
|
||||
if (psEnc.nPrevChannelsInternal == 2 && psEnc.state_Fxx[0].nFramesEncoded == 0)
|
||||
{
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[1].resampler_state,
|
||||
psEnc.state_Fxx[1].inputBuf,
|
||||
psEnc.state_Fxx[1].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
for (n = 0; n < psEnc.state_Fxx[0].frame_length; n++)
|
||||
{
|
||||
psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2] =
|
||||
(short)(Inlines.silk_RSHIFT(psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2]
|
||||
+ psEnc.state_Fxx[1].inputBuf[psEnc.state_Fxx[1].inputBufIx + n + 2], 1));
|
||||
}
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
Inlines.OpusAssert(encControl.nChannelsAPI == 1 && encControl.nChannelsInternal == 1);
|
||||
Array.Copy(samplesIn, samplesIn_ptr, buf, 0, nSamplesFromInput);
|
||||
ret += Resampler.silk_resampler(
|
||||
psEnc.state_Fxx[0].resampler_state,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
psEnc.state_Fxx[0].inputBufIx + 2,
|
||||
buf,
|
||||
0,
|
||||
nSamplesFromInput);
|
||||
|
||||
psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer;
|
||||
}
|
||||
|
||||
samplesIn_ptr += (nSamplesFromInput * encControl.nChannelsAPI);
|
||||
nSamplesIn -= nSamplesFromInput;
|
||||
|
||||
/* Default */
|
||||
psEnc.allowBandwidthSwitch = 0;
|
||||
|
||||
/* Silk encoder */
|
||||
if (psEnc.state_Fxx[0].inputBufIx >= psEnc.state_Fxx[0].frame_length)
|
||||
{
|
||||
/* Enough data in input buffer, so encode */
|
||||
Inlines.OpusAssert(psEnc.state_Fxx[0].inputBufIx == psEnc.state_Fxx[0].frame_length);
|
||||
Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inputBufIx == psEnc.state_Fxx[1].frame_length);
|
||||
|
||||
/* Deal with LBRR data */
|
||||
if (psEnc.state_Fxx[0].nFramesEncoded == 0 && prefillFlag == 0)
|
||||
{
|
||||
/* Create space at start of payload for VAD and FEC flags */
|
||||
byte[] iCDF = { 0, 0 };
|
||||
iCDF[0] = (byte)(256 - Inlines.silk_RSHIFT(256, (psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal));
|
||||
psRangeEnc.enc_icdf(0, iCDF, 8);
|
||||
|
||||
/* Encode any LBRR data from previous packet */
|
||||
/* Encode LBRR flags */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
LBRR_symbol = 0;
|
||||
for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; i++)
|
||||
{
|
||||
LBRR_symbol |= Inlines.silk_LSHIFT(psEnc.state_Fxx[n].LBRR_flags[i], i);
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[n].LBRR_flag = (sbyte)(LBRR_symbol > 0 ? 1 : 0);
|
||||
if (LBRR_symbol != 0 && psEnc.state_Fxx[n].nFramesPerPacket > 1)
|
||||
{
|
||||
psRangeEnc.enc_icdf( LBRR_symbol - 1, Tables.silk_LBRR_flags_iCDF_ptr[psEnc.state_Fxx[n].nFramesPerPacket - 2], 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Code LBRR indices and excitation signals */
|
||||
for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; i++)
|
||||
{
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
if (psEnc.state_Fxx[n].LBRR_flags[i] != 0)
|
||||
{
|
||||
int condCoding;
|
||||
|
||||
if (encControl.nChannelsInternal == 2 && n == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[i]);
|
||||
/* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */
|
||||
if (psEnc.state_Fxx[1].LBRR_flags[i] == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use conditional coding if previous frame available */
|
||||
if (i > 0 && psEnc.state_Fxx[n].LBRR_flags[i - 1] != 0)
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
|
||||
EncodeIndices.silk_encode_indices(psEnc.state_Fxx[n], psRangeEnc, i, 1, condCoding);
|
||||
EncodePulses.silk_encode_pulses(psRangeEnc, psEnc.state_Fxx[n].indices_LBRR[i].signalType, psEnc.state_Fxx[n].indices_LBRR[i].quantOffsetType,
|
||||
psEnc.state_Fxx[n].pulses_LBRR[i], psEnc.state_Fxx[n].frame_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset LBRR flags */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
Arrays.MemSetInt(psEnc.state_Fxx[n].LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET);
|
||||
}
|
||||
|
||||
psEnc.nBitsUsedLBRR = psRangeEnc.tell();
|
||||
}
|
||||
|
||||
HPVariableCutoff.silk_HP_variable_cutoff(psEnc.state_Fxx);
|
||||
|
||||
/* Total target bits for packet */
|
||||
nBits = Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000);
|
||||
|
||||
/* Subtract bits used for LBRR */
|
||||
if (prefillFlag == 0)
|
||||
{
|
||||
nBits -= psEnc.nBitsUsedLBRR;
|
||||
}
|
||||
|
||||
/* Divide by number of uncoded frames left in packet */
|
||||
nBits = Inlines.silk_DIV32_16(nBits, psEnc.state_Fxx[0].nFramesPerPacket);
|
||||
|
||||
/* Convert to bits/second */
|
||||
if (encControl.payloadSize_ms == 10)
|
||||
{
|
||||
TargetRate_bps = Inlines.silk_SMULBB(nBits, 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetRate_bps = Inlines.silk_SMULBB(nBits, 50);
|
||||
}
|
||||
|
||||
/* Subtract fraction of bits in excess of target in previous frames and packets */
|
||||
TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(psEnc.nBitsExceeded, 1000), TuningParameters.BITRESERVOIR_DECAY_TIME_MS);
|
||||
|
||||
if (prefillFlag == 0 && psEnc.state_Fxx[0].nFramesEncoded > 0)
|
||||
{
|
||||
/* Compare actual vs target bits so far in this packet */
|
||||
int bitsBalance = psRangeEnc.tell() - psEnc.nBitsUsedLBRR - nBits * psEnc.state_Fxx[0].nFramesEncoded;
|
||||
TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(bitsBalance, 1000), TuningParameters.BITRESERVOIR_DECAY_TIME_MS);
|
||||
}
|
||||
|
||||
/* Never exceed input bitrate */
|
||||
TargetRate_bps = Inlines.silk_LIMIT(TargetRate_bps, encControl.bitRate, 5000);
|
||||
|
||||
/* Convert Left/Right to Mid/Side */
|
||||
if (encControl.nChannelsInternal == 2)
|
||||
{
|
||||
BoxedValueSbyte midOnlyFlagBoxed = new BoxedValueSbyte(psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]);
|
||||
Stereo.silk_stereo_LR_to_MS(psEnc.sStereo,
|
||||
psEnc.state_Fxx[0].inputBuf,
|
||||
2,
|
||||
psEnc.state_Fxx[1].inputBuf,
|
||||
2,
|
||||
psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded],
|
||||
midOnlyFlagBoxed,
|
||||
MStargetRates_bps,
|
||||
TargetRate_bps,
|
||||
psEnc.state_Fxx[0].speech_activity_Q8,
|
||||
encControl.toMono,
|
||||
psEnc.state_Fxx[0].fs_kHz,
|
||||
psEnc.state_Fxx[0].frame_length);
|
||||
|
||||
psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded] = midOnlyFlagBoxed.Val;
|
||||
|
||||
if (midOnlyFlagBoxed.Val == 0)
|
||||
{
|
||||
/* Reset side channel encoder memory for first frame with side coding */
|
||||
if (psEnc.prev_decode_only_middle == 1)
|
||||
{
|
||||
psEnc.state_Fxx[1].sShape.Reset();
|
||||
psEnc.state_Fxx[1].sPrefilt.Reset();
|
||||
psEnc.state_Fxx[1].sNSQ.Reset();
|
||||
Arrays.MemSetShort(psEnc.state_Fxx[1].prev_NLSFq_Q15, 0, SilkConstants.MAX_LPC_ORDER);
|
||||
Arrays.MemSetInt(psEnc.state_Fxx[1].sLP.In_LP_State, 0, 2);
|
||||
|
||||
psEnc.state_Fxx[1].prevLag = 100;
|
||||
psEnc.state_Fxx[1].sNSQ.lagPrev = 100;
|
||||
psEnc.state_Fxx[1].sShape.LastGainIndex = 10;
|
||||
psEnc.state_Fxx[1].prevSignalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY;
|
||||
psEnc.state_Fxx[1].sNSQ.prev_gain_Q16 = 65536;
|
||||
psEnc.state_Fxx[1].first_frame_after_reset = 1;
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[1].silk_encode_do_VAD();
|
||||
}
|
||||
else
|
||||
{
|
||||
psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] = 0;
|
||||
}
|
||||
|
||||
if (prefillFlag == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded]);
|
||||
if (psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] == 0)
|
||||
{
|
||||
Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffering */
|
||||
Array.Copy(psEnc.sStereo.sMid, psEnc.state_Fxx[0].inputBuf, 2);
|
||||
Array.Copy(psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].frame_length, psEnc.sStereo.sMid, 0, 2);
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[0].silk_encode_do_VAD();
|
||||
|
||||
/* Encode */
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
int maxBits, useCBR;
|
||||
|
||||
/* Handling rate constraints */
|
||||
maxBits = encControl.maxBits;
|
||||
if (tot_blocks == 2 && curr_block == 0)
|
||||
{
|
||||
maxBits = maxBits * 3 / 5;
|
||||
}
|
||||
|
||||
else if (tot_blocks == 3)
|
||||
{
|
||||
if (curr_block == 0)
|
||||
{
|
||||
maxBits = maxBits * 2 / 5;
|
||||
}
|
||||
else if (curr_block == 1)
|
||||
{
|
||||
maxBits = maxBits * 3 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
useCBR = (encControl.useCBR != 0 && curr_block == tot_blocks - 1) ? 1 : 0;
|
||||
|
||||
if (encControl.nChannelsInternal == 1)
|
||||
{
|
||||
channelRate_bps = TargetRate_bps;
|
||||
}
|
||||
else
|
||||
{
|
||||
channelRate_bps = MStargetRates_bps[n];
|
||||
if (n == 0 && MStargetRates_bps[1] > 0)
|
||||
{
|
||||
useCBR = 0;
|
||||
/* Give mid up to 1/2 of the max bits for that frame */
|
||||
maxBits -= encControl.maxBits / (tot_blocks * 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (channelRate_bps > 0)
|
||||
{
|
||||
int condCoding;
|
||||
|
||||
psEnc.state_Fxx[n].silk_control_SNR(channelRate_bps);
|
||||
|
||||
/* Use independent coding if no previous frame available */
|
||||
if (psEnc.state_Fxx[0].nFramesEncoded - n <= 0)
|
||||
{
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY;
|
||||
}
|
||||
else if (n > 0 && psEnc.prev_decode_only_middle != 0)
|
||||
{
|
||||
/* If we skipped a side frame in this packet, we don't
|
||||
need LTP scaling; the LTP state is well-defined. */
|
||||
condCoding = SilkConstants.CODE_INDEPENDENTLY_NO_LTP_SCALING;
|
||||
}
|
||||
else
|
||||
{
|
||||
condCoding = SilkConstants.CODE_CONDITIONALLY;
|
||||
}
|
||||
|
||||
ret += psEnc.state_Fxx[n].silk_encode_frame(nBytesOut, psRangeEnc, condCoding, maxBits, useCBR);
|
||||
Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR);
|
||||
}
|
||||
|
||||
psEnc.state_Fxx[n].controlled_since_last_payload = 0;
|
||||
psEnc.state_Fxx[n].inputBufIx = 0;
|
||||
psEnc.state_Fxx[n].nFramesEncoded++;
|
||||
}
|
||||
|
||||
psEnc.prev_decode_only_middle = psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded - 1];
|
||||
|
||||
/* Insert VAD and FEC flags at beginning of bitstream */
|
||||
if (nBytesOut.Val > 0 && psEnc.state_Fxx[0].nFramesEncoded == psEnc.state_Fxx[0].nFramesPerPacket)
|
||||
{
|
||||
flags = 0;
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; i++)
|
||||
{
|
||||
flags = Inlines.silk_LSHIFT(flags, 1);
|
||||
flags |= (int)psEnc.state_Fxx[n].VAD_flags[i];
|
||||
}
|
||||
flags = Inlines.silk_LSHIFT(flags, 1);
|
||||
flags |= (int)psEnc.state_Fxx[n].LBRR_flag;
|
||||
}
|
||||
|
||||
if (prefillFlag == 0)
|
||||
{
|
||||
psRangeEnc.enc_patch_initial_bits((uint)flags, (uint)((psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal));
|
||||
}
|
||||
|
||||
/* Return zero bytes if all channels DTXed */
|
||||
if (psEnc.state_Fxx[0].inDTX != 0 && (encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inDTX != 0))
|
||||
{
|
||||
nBytesOut.Val = 0;
|
||||
}
|
||||
|
||||
psEnc.nBitsExceeded += nBytesOut.Val * 8;
|
||||
psEnc.nBitsExceeded -= Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000);
|
||||
psEnc.nBitsExceeded = Inlines.silk_LIMIT(psEnc.nBitsExceeded, 0, 10000);
|
||||
|
||||
/* Update flag indicating if bandwidth switching is allowed */
|
||||
speech_act_thr_for_switch_Q8 = Inlines.silk_SMLAWB(((int)((TuningParameters.SPEECH_ACTIVITY_DTX_THRES) * ((long)1 << (8)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.SPEECH_ACTIVITY_DTX_THRES, 8)*/,
|
||||
((int)(((1 - TuningParameters.SPEECH_ACTIVITY_DTX_THRES) / TuningParameters.MAX_BANDWIDTH_SWITCH_DELAY_MS) * ((long)1 << (16 + 8)) + 0.5))/*Inlines.SILK_CONST((1 - TuningParameters.SPEECH_ACTIVITY_DTX_THRES) / TuningParameters.MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8)*/,
|
||||
psEnc.timeSinceSwitchAllowed_ms);
|
||||
if (psEnc.state_Fxx[0].speech_activity_Q8 < speech_act_thr_for_switch_Q8)
|
||||
{
|
||||
psEnc.allowBandwidthSwitch = 1;
|
||||
psEnc.timeSinceSwitchAllowed_ms = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
psEnc.allowBandwidthSwitch = 0;
|
||||
psEnc.timeSinceSwitchAllowed_ms += encControl.payloadSize_ms;
|
||||
}
|
||||
}
|
||||
|
||||
if (nSamplesIn == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
curr_block++;
|
||||
}
|
||||
|
||||
psEnc.nPrevChannelsInternal = encControl.nChannelsInternal;
|
||||
|
||||
encControl.allowBandwidthSwitch = psEnc.allowBandwidthSwitch;
|
||||
encControl.inWBmodeWithoutVariableLP = (psEnc.state_Fxx[0].fs_kHz == 16 && psEnc.state_Fxx[0].sLP.mode == 0) ? 1 : 0;
|
||||
encControl.internalSampleRate = Inlines.silk_SMULBB(psEnc.state_Fxx[0].fs_kHz, 1000);
|
||||
encControl.stereoWidth_Q14 = encControl.toMono != 0 ? 0 : psEnc.sStereo.smth_width_Q14;
|
||||
|
||||
if (prefillFlag != 0)
|
||||
{
|
||||
encControl.payloadSize_ms = tmp_payloadSize_ms;
|
||||
encControl.complexity = tmp_complexity;
|
||||
|
||||
for (n = 0; n < encControl.nChannelsInternal; n++)
|
||||
{
|
||||
psEnc.state_Fxx[n].controlled_since_last_payload = 0;
|
||||
psEnc.state_Fxx[n].prefillFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//────────────────────▄▄▄▄▄▄▄▄▄▄────────────────────
|
||||
//─────────────▄▄▄▄████▓▓▓▓▓▓▓▓▓██▄▄────────────────
|
||||
//─────────▄▄██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒░▀▀▄─────────────
|
||||
//────────▀▀▀▀▀█████▓▓▓▓▒▒▒▒▒▒▒▒▒▒░░░░░▀▄───────────
|
||||
//────────────▄▄█▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░▀▄─────────
|
||||
//─────▄▀▀▄─▄█▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░█▄▀▀▄─────
|
||||
//────█░░░▄█▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░█░░░░░█────
|
||||
//───█░░░█▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░▄▀░░░▄░░█───
|
||||
//──█░░░█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░█░░░░░█░░█──
|
||||
//──█░░█▓▒▒▄▄▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░██░░░░░░█░█──
|
||||
//─█░░█▓▄▄▀█▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░▄▄▀█░░░░▄▀█░░░░░░█░░█─
|
||||
//─█░██▀░▄▀▒▒▒▒▒▒▒▒▒▒▒▒▄▄▄▄▀▀▀░▄▀░░░▄▀░░░░░░░░░█░░█─
|
||||
//─██▀░░█▒▒▒▒▒▒▒▒▒▄▄▀▀▀░░░░░░▄▀░░▄▄▀░░░░░░░░░░░░░░█─
|
||||
//──█░░█▒▒▒▒▒▒▒▄▀▀░░░░░░░░░░▀▀▀▀▀░░░░░░░░░░▄▄░░░░░█─
|
||||
//───██▒▒▒▒▒▒▄▀██▄▄░░░░░█░░░░░░░░░░░░░▄▄▄█▀░░░░░░█──
|
||||
//────█▒▒▒▒▒█─▓██████▄▄█░░░█░░░░▄▄▄████▓─█▀▀░░░░█───
|
||||
//───█▒▒▒▒▄█─▓█──████▓─█░░░░████████──█▓─█▄░░░▄▀────
|
||||
//───█▒▒▄▀█──▓█▒▓████▓─█░░░░█─▓█████▓▒█▓─█░░█▀──────
|
||||
//──█▒▄▀█░█──▓███─███▓─█░░░░█─▓████─██▓──█░█────────
|
||||
//──█▀──█░█──▓▓██████▓─█░░░░█─▓██████▓▓──█░█────────
|
||||
//──────█░░█──▓▓████▓─█░░░░░░█─▓████▓▓──█░░█────────
|
||||
//──────█░░▀▄───▓▓▓▓──█░░░░░░█──▓▓▓▓───▄▀░░█────────
|
||||
//───────█░░▀▄───────█░░░░░░░░█───────▄▀░░█─────────
|
||||
//───────█░░░░▀▄▄▄▄▄▀░░▄▀▀▀▀▄░░▀▄▄▄▄▄▀░░░░█─────────
|
||||
//────────█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█──────────
|
||||
//─────────█░░░░░░░░░░▀▄░░░░▄▀░░░░░░░░░░█───────────
|
||||
//──────────▀▄░░░░░░░░░░░░░░░░░░░░░░░░▄▀────────────
|
||||
//────────────▀▄░░░░░░▀▄░░░░▄▀░░░░░░▄▀──────────────
|
||||
//──────────────▀▄▄░░░░░▀▀▀▀░░░░░▄▄▀────────────────
|
||||
//─────────────────▀▀▄▄▄▄▄▄▄▄▄▄▀▀───────────────────
|
||||
//──────────────────────────────────────────────────
|
||||
//───────█───█───█─████──███──███──█───█─████─█─────
|
||||
//──────█─█──█───█─█────█────█───█─██─██─█────█─────
|
||||
//─────█▄▄▄█─█─█─█─██────██──█───█─█─█─█─██───█─────
|
||||
//─────█───█──█─█──█───────█─█───█─█───█─█──────────
|
||||
//─────█───█──█─█──████─███───███──█───█─████─█─────
|
||||
//──────────────────────────────────────────────────
|
||||
//──────────────────────────────────────────────────
|
||||
223
Libraries/Concentus/CSharp/Concentus/Silk/EncodeIndices.cs
Normal file
223
Libraries/Concentus/CSharp/Concentus/Silk/EncodeIndices.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class EncodeIndices
|
||||
{
|
||||
/// <summary>
|
||||
/// Encode side-information parameters to payload
|
||||
/// </summary>
|
||||
/// <param name="psEncC">I/O Encoder state</param>
|
||||
/// <param name="psRangeEnc">I/O Compressor data structure</param>
|
||||
/// <param name="FrameIndex">I Frame number</param>
|
||||
/// <param name="encode_LBRR">I Flag indicating LBRR data is being encoded</param>
|
||||
/// <param name="condCoding">I The type of conditional coding to use</param>
|
||||
internal static void silk_encode_indices(
|
||||
SilkChannelEncoder psEncC,
|
||||
EntropyCoder psRangeEnc,
|
||||
int FrameIndex,
|
||||
int encode_LBRR,
|
||||
int condCoding)
|
||||
{
|
||||
int i, k, typeOffset;
|
||||
int encode_absolute_lagIndex, delta_lagIndex;
|
||||
short[] ec_ix = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
byte[] pred_Q8 = new byte[SilkConstants.MAX_LPC_ORDER];
|
||||
SideInfoIndices psIndices;
|
||||
|
||||
if (encode_LBRR != 0)
|
||||
{
|
||||
psIndices = psEncC.indices_LBRR[FrameIndex];
|
||||
}
|
||||
else {
|
||||
psIndices = psEncC.indices;
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
/* Encode signal type and quantizer offset */
|
||||
/*******************************************/
|
||||
typeOffset = 2 * psIndices.signalType + psIndices.quantOffsetType;
|
||||
Inlines.OpusAssert(typeOffset >= 0 && typeOffset < 6);
|
||||
Inlines.OpusAssert(encode_LBRR == 0 || typeOffset >= 2);
|
||||
if (encode_LBRR != 0 || typeOffset >= 2)
|
||||
{
|
||||
psRangeEnc.enc_icdf( typeOffset - 2, Tables.silk_type_offset_VAD_iCDF, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
psRangeEnc.enc_icdf( typeOffset, Tables.silk_type_offset_no_VAD_iCDF, 8);
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Encode gains */
|
||||
/****************/
|
||||
/* first subframe */
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY)
|
||||
{
|
||||
/* conditional coding */
|
||||
Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.MIN_DELTA_GAIN_QUANT + 1);
|
||||
psRangeEnc.enc_icdf( psIndices.GainsIndices[0], Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* independent coding, in two stages: MSB bits followed by 3 LSBs */
|
||||
Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < SilkConstants.N_LEVELS_QGAIN);
|
||||
psRangeEnc.enc_icdf( Inlines.silk_RSHIFT(psIndices.GainsIndices[0], 3), Tables.silk_gain_iCDF[psIndices.signalType], 8);
|
||||
psRangeEnc.enc_icdf( psIndices.GainsIndices[0] & 7, Tables.silk_uniform8_iCDF, 8);
|
||||
}
|
||||
|
||||
/* remaining subframes */
|
||||
for (i = 1; i < psEncC.nb_subfr; i++)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.GainsIndices[i] >= 0 && psIndices.GainsIndices[i] < SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.MIN_DELTA_GAIN_QUANT + 1);
|
||||
psRangeEnc.enc_icdf( psIndices.GainsIndices[i], Tables.silk_delta_gain_iCDF, 8);
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Encode NLSFs */
|
||||
/****************/
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFIndices[0], psEncC.psNLSF_CB.CB1_iCDF, ((psIndices.signalType >> 1) * psEncC.psNLSF_CB.nVectors), 8);
|
||||
NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psEncC.psNLSF_CB, psIndices.NLSFIndices[0]);
|
||||
Inlines.OpusAssert(psEncC.psNLSF_CB.order == psEncC.predictLPCOrder);
|
||||
|
||||
for (i = 0; i < psEncC.psNLSF_CB.order; i++)
|
||||
{
|
||||
if (psIndices.NLSFIndices[i + 1] >= SilkConstants.NLSF_QUANT_MAX_AMPLITUDE)
|
||||
{
|
||||
psRangeEnc.enc_icdf( 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, psEncC.psNLSF_CB.ec_iCDF, (ec_ix[i]), 8);
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFIndices[i + 1] - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
else if (psIndices.NLSFIndices[i + 1] <= 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE)
|
||||
{
|
||||
psRangeEnc.enc_icdf( 0, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8);
|
||||
psRangeEnc.enc_icdf( -psIndices.NLSFIndices[i + 1] - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, Tables.silk_NLSF_EXT_iCDF, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFIndices[i + 1] + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode NLSF interpolation factor */
|
||||
if (psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.NLSFInterpCoef_Q2 >= 0 && psIndices.NLSFInterpCoef_Q2 < 5);
|
||||
psRangeEnc.enc_icdf( psIndices.NLSFInterpCoef_Q2, Tables.silk_NLSF_interpolation_factor_iCDF, 8);
|
||||
}
|
||||
|
||||
if (psIndices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/*********************/
|
||||
/* Encode pitch lags */
|
||||
/*********************/
|
||||
/* lag index */
|
||||
encode_absolute_lagIndex = 1;
|
||||
if (condCoding == SilkConstants.CODE_CONDITIONALLY && psEncC.ec_prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* Delta Encoding */
|
||||
delta_lagIndex = psIndices.lagIndex - psEncC.ec_prevLagIndex;
|
||||
|
||||
if (delta_lagIndex < -8 || delta_lagIndex > 11)
|
||||
{
|
||||
delta_lagIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta_lagIndex = delta_lagIndex + 9;
|
||||
encode_absolute_lagIndex = 0; /* Only use delta */
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(delta_lagIndex >= 0 && delta_lagIndex < 21);
|
||||
psRangeEnc.enc_icdf( delta_lagIndex, Tables.silk_pitch_delta_iCDF, 8);
|
||||
}
|
||||
|
||||
if (encode_absolute_lagIndex != 0)
|
||||
{
|
||||
/* Absolute encoding */
|
||||
int pitch_high_bits, pitch_low_bits;
|
||||
pitch_high_bits = Inlines.silk_DIV32_16(psIndices.lagIndex, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1));
|
||||
pitch_low_bits = psIndices.lagIndex - Inlines.silk_SMULBB(pitch_high_bits, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1));
|
||||
Inlines.OpusAssert(pitch_low_bits < psEncC.fs_kHz / 2);
|
||||
Inlines.OpusAssert(pitch_high_bits < 32);
|
||||
psRangeEnc.enc_icdf( pitch_high_bits, Tables.silk_pitch_lag_iCDF, 8);
|
||||
psRangeEnc.enc_icdf( pitch_low_bits, psEncC.pitch_lag_low_bits_iCDF, 8);
|
||||
}
|
||||
psEncC.ec_prevLagIndex = psIndices.lagIndex;
|
||||
|
||||
/* Countour index */
|
||||
Inlines.OpusAssert(psIndices.contourIndex >= 0);
|
||||
Inlines.OpusAssert((psIndices.contourIndex < 34 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 4) || (psIndices.contourIndex < 11 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 4) || (psIndices.contourIndex < 12 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 2) || (psIndices.contourIndex < 3 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 2));
|
||||
psRangeEnc.enc_icdf( psIndices.contourIndex, psEncC.pitch_contour_iCDF, 8);
|
||||
|
||||
/********************/
|
||||
/* Encode LTP gains */
|
||||
/********************/
|
||||
/* PERIndex value */
|
||||
Inlines.OpusAssert(psIndices.PERIndex >= 0 && psIndices.PERIndex < 3);
|
||||
psRangeEnc.enc_icdf( psIndices.PERIndex, Tables.silk_LTP_per_index_iCDF, 8);
|
||||
|
||||
/* Codebook Indices */
|
||||
for (k = 0; k < psEncC.nb_subfr; k++)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.LTPIndex[k] >= 0 && psIndices.LTPIndex[k] < (8 << psIndices.PERIndex));
|
||||
psRangeEnc.enc_icdf( psIndices.LTPIndex[k], Tables.silk_LTP_gain_iCDF_ptrs[psIndices.PERIndex], 8);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Encode LTP scaling */
|
||||
/**********************/
|
||||
if (condCoding == SilkConstants.CODE_INDEPENDENTLY)
|
||||
{
|
||||
Inlines.OpusAssert(psIndices.LTP_scaleIndex >= 0 && psIndices.LTP_scaleIndex < 3);
|
||||
psRangeEnc.enc_icdf( psIndices.LTP_scaleIndex, Tables.silk_LTPscale_iCDF, 8);
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(condCoding == 0 || psIndices.LTP_scaleIndex == 0);
|
||||
}
|
||||
|
||||
psEncC.ec_prevSignalType = psIndices.signalType;
|
||||
|
||||
/***************/
|
||||
/* Encode seed */
|
||||
/***************/
|
||||
Inlines.OpusAssert(psIndices.Seed >= 0 && psIndices.Seed < 4);
|
||||
psRangeEnc.enc_icdf( psIndices.Seed, Tables.silk_uniform4_iCDF, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
278
Libraries/Concentus/CSharp/Concentus/Silk/EncodePulses.cs
Normal file
278
Libraries/Concentus/CSharp/Concentus/Silk/EncodePulses.cs
Normal file
@@ -0,0 +1,278 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class EncodePulses
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pulses_comb">(O)</param>
|
||||
/// <param name="pulses_in">(I)</param>
|
||||
/// <param name="max_pulses"> I max value for sum of pulses</param>
|
||||
/// <param name="len">I number of output values</param>
|
||||
/// <returns>return ok</returns>
|
||||
internal static int combine_and_check(
|
||||
int[] pulses_comb,
|
||||
int pulses_comb_ptr,
|
||||
int[] pulses_in,
|
||||
int pulses_in_ptr,
|
||||
int max_pulses,
|
||||
int len)
|
||||
{
|
||||
for (int k = 0; k < len; k++)
|
||||
{
|
||||
int k2p = 2 * k + pulses_in_ptr;
|
||||
int sum = pulses_in[k2p] + pulses_in[k2p + 1];
|
||||
if (sum > max_pulses)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
pulses_comb[pulses_comb_ptr + k] = sum;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pulses_comb">(O)</param>
|
||||
/// <param name="pulses_in">(I)</param>
|
||||
/// <param name="max_pulses"> I max value for sum of pulses</param>
|
||||
/// <param name="len">I number of output values</param>
|
||||
/// <returns>return ok</returns>
|
||||
internal static int combine_and_check(
|
||||
int[] pulses_comb,
|
||||
int[] pulses_in,
|
||||
int max_pulses,
|
||||
int len)
|
||||
{
|
||||
for (int k = 0; k < len; k++)
|
||||
{
|
||||
int sum = pulses_in[2 * k] + pulses_in[2 * k + 1];
|
||||
if (sum > max_pulses)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
pulses_comb[k] = sum;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode quantization indices of excitation
|
||||
/// </summary>
|
||||
/// <param name="psRangeEnc">I/O compressor data structure</param>
|
||||
/// <param name="signalType">I Signal type</param>
|
||||
/// <param name="quantOffsetType">I quantOffsetType</param>
|
||||
/// <param name="pulses">I quantization indices</param>
|
||||
/// <param name="frame_length">I Frame length</param>
|
||||
internal static void silk_encode_pulses(
|
||||
EntropyCoder psRangeEnc,
|
||||
int signalType,
|
||||
int quantOffsetType,
|
||||
sbyte[] pulses,
|
||||
int frame_length)
|
||||
{
|
||||
int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0;
|
||||
int abs_q, minSumBits_Q5, sumBits_Q5;
|
||||
int[] abs_pulses;
|
||||
int[] sum_pulses;
|
||||
int[] nRshifts;
|
||||
int[] pulses_comb = new int[8];
|
||||
int abs_pulses_ptr;
|
||||
int pulses_ptr;
|
||||
byte[] nBits_ptr;
|
||||
|
||||
Arrays.MemSetInt(pulses_comb, 0, 8);
|
||||
|
||||
/****************************/
|
||||
/* Prepare for shell coding */
|
||||
/****************************/
|
||||
/* Calculate number of shell blocks */
|
||||
Inlines.OpusAssert(1 << SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH == SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
iter = Inlines.silk_RSHIFT(frame_length, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH);
|
||||
if (iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH < frame_length)
|
||||
{
|
||||
Inlines.OpusAssert(frame_length == 12 * 10); /* Make sure only happens for 10 ms @ 12 kHz */
|
||||
iter++;
|
||||
Arrays.MemSetWithOffset<sbyte>(pulses, 0, frame_length, SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
}
|
||||
|
||||
/* Take the absolute value of the pulses */
|
||||
abs_pulses = new int[iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH];
|
||||
Inlines.OpusAssert((SilkConstants.SHELL_CODEC_FRAME_LENGTH & 3) == 0);
|
||||
|
||||
// unrolled loop
|
||||
for (i = 0; i < iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH; i += 4)
|
||||
{
|
||||
abs_pulses[i + 0] = (int)Inlines.silk_abs(pulses[i + 0]);
|
||||
abs_pulses[i + 1] = (int)Inlines.silk_abs(pulses[i + 1]);
|
||||
abs_pulses[i + 2] = (int)Inlines.silk_abs(pulses[i + 2]);
|
||||
abs_pulses[i + 3] = (int)Inlines.silk_abs(pulses[i + 3]);
|
||||
}
|
||||
|
||||
/* Calc sum pulses per shell code frame */
|
||||
sum_pulses = new int[iter];
|
||||
nRshifts = new int[iter];
|
||||
abs_pulses_ptr = 0;
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
nRshifts[i] = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* 1+1 . 2 */
|
||||
scale_down = combine_and_check(pulses_comb, 0, abs_pulses, abs_pulses_ptr, Tables.silk_max_pulses_table[0], 8);
|
||||
/* 2+2 . 4 */
|
||||
scale_down += combine_and_check(pulses_comb, pulses_comb, Tables.silk_max_pulses_table[1], 4);
|
||||
/* 4+4 . 8 */
|
||||
scale_down += combine_and_check(pulses_comb, pulses_comb, Tables.silk_max_pulses_table[2], 2);
|
||||
/* 8+8 . 16 */
|
||||
scale_down += combine_and_check(sum_pulses, i, pulses_comb, 0, Tables.silk_max_pulses_table[3], 1);
|
||||
|
||||
if (scale_down != 0)
|
||||
{
|
||||
/* We need to downscale the quantization signal */
|
||||
nRshifts[i]++;
|
||||
for (k = abs_pulses_ptr; k < abs_pulses_ptr + SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++)
|
||||
{
|
||||
abs_pulses[k] = Inlines.silk_RSHIFT(abs_pulses[k], 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Jump out of while(1) loop and go to next shell coding frame */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
abs_pulses_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
}
|
||||
|
||||
/**************/
|
||||
/* Rate level */
|
||||
/**************/
|
||||
/* find rate level that leads to fewest bits for coding of pulses per block info */
|
||||
minSumBits_Q5 = int.MaxValue;
|
||||
for (k = 0; k < SilkConstants.N_RATE_LEVELS - 1; k++)
|
||||
{
|
||||
nBits_ptr = Tables.silk_pulses_per_block_BITS_Q5[k];
|
||||
sumBits_Q5 = Tables.silk_rate_levels_BITS_Q5[signalType >> 1][k];
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nRshifts[i] > 0)
|
||||
{
|
||||
sumBits_Q5 += nBits_ptr[SilkConstants.SILK_MAX_PULSES + 1];
|
||||
}
|
||||
else {
|
||||
sumBits_Q5 += nBits_ptr[sum_pulses[i]];
|
||||
}
|
||||
}
|
||||
if (sumBits_Q5 < minSumBits_Q5)
|
||||
{
|
||||
minSumBits_Q5 = sumBits_Q5;
|
||||
RateLevelIndex = k;
|
||||
}
|
||||
}
|
||||
|
||||
psRangeEnc.enc_icdf( RateLevelIndex, Tables.silk_rate_levels_iCDF[signalType >> 1], 8);
|
||||
|
||||
/***************************************************/
|
||||
/* Sum-Weighted-Pulses Encoding */
|
||||
/***************************************************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nRshifts[i] == 0)
|
||||
{
|
||||
psRangeEnc.enc_icdf( sum_pulses[i], Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
psRangeEnc.enc_icdf( SilkConstants.SILK_MAX_PULSES + 1, Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8);
|
||||
for (k = 0; k < nRshifts[i] - 1; k++)
|
||||
{
|
||||
psRangeEnc.enc_icdf( SilkConstants.SILK_MAX_PULSES + 1, Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], 8);
|
||||
}
|
||||
|
||||
psRangeEnc.enc_icdf( sum_pulses[i], Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], 8);
|
||||
}
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Shell Encoding */
|
||||
/******************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (sum_pulses[i] > 0)
|
||||
{
|
||||
ShellCoder.silk_shell_encoder(psRangeEnc, abs_pulses, i * SilkConstants.SHELL_CODEC_FRAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* LSB Encoding */
|
||||
/****************/
|
||||
for (i = 0; i < iter; i++)
|
||||
{
|
||||
if (nRshifts[i] > 0)
|
||||
{
|
||||
pulses_ptr = i * SilkConstants.SHELL_CODEC_FRAME_LENGTH;
|
||||
nLS = nRshifts[i] - 1;
|
||||
for (k = 0; k < SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++)
|
||||
{
|
||||
abs_q = (sbyte)Inlines.silk_abs(pulses[pulses_ptr + k]);
|
||||
for (j = nLS; j > 0; j--)
|
||||
{
|
||||
bit = Inlines.silk_RSHIFT(abs_q, j) & 1;
|
||||
psRangeEnc.enc_icdf( bit, Tables.silk_lsb_iCDF, 8);
|
||||
}
|
||||
bit = abs_q & 1;
|
||||
psRangeEnc.enc_icdf( bit, Tables.silk_lsb_iCDF, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Encode signs */
|
||||
/****************/
|
||||
CodeSigns.silk_encode_signs(psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Enums
|
||||
{
|
||||
internal static class DecoderAPIFlag
|
||||
{
|
||||
public const int FLAG_DECODE_NORMAL = 0;
|
||||
public const int FLAG_PACKET_LOST = 1;
|
||||
public const int FLAG_DECODE_LBRR = 2;
|
||||
}
|
||||
}
|
||||
91
Libraries/Concentus/CSharp/Concentus/Silk/Enums/SilkError.cs
Normal file
91
Libraries/Concentus/CSharp/Concentus/Silk/Enums/SilkError.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents error messages from a silk encoder/decoder
|
||||
/// </summary>
|
||||
internal static class SilkError
|
||||
{
|
||||
internal static int SILK_NO_ERROR = 0;
|
||||
|
||||
// Encoder error messages
|
||||
|
||||
/* Input length is not a multiple of 10 ms, or length is longer than the packet length */
|
||||
internal static int SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES = -101;
|
||||
|
||||
/* Sampling frequency not 8000, 12000 or 16000 Hertz */
|
||||
internal static int SILK_ENC_FS_NOT_SUPPORTED = -102;
|
||||
|
||||
/* Packet size not 10, 20, 40, or 60 ms */
|
||||
internal static int SILK_ENC_PACKET_SIZE_NOT_SUPPORTED = -103;
|
||||
|
||||
/* Allocated payload buffer too short */
|
||||
internal static int SILK_ENC_PAYLOAD_BUF_TOO_SHORT = -104;
|
||||
|
||||
/* Loss rate not between 0 and 100 percent */
|
||||
internal static int SILK_ENC_INVALID_LOSS_RATE = -105;
|
||||
|
||||
/* Complexity setting not valid, use 0...10 */
|
||||
internal static int SILK_ENC_INVALID_COMPLEXITY_SETTING = -106;
|
||||
|
||||
/* Inband FEC setting not valid, use 0 or 1 */
|
||||
internal static int SILK_ENC_INVALID_INBAND_FEC_SETTING = -107;
|
||||
|
||||
/* DTX setting not valid, use 0 or 1 */
|
||||
internal static int SILK_ENC_INVALID_DTX_SETTING = -108;
|
||||
|
||||
/* CBR setting not valid, use 0 or 1 */
|
||||
internal static int SILK_ENC_INVALID_CBR_SETTING = -109;
|
||||
|
||||
/* Internal encoder error */
|
||||
internal static int SILK_ENC_INTERNAL_ERROR = -110;
|
||||
|
||||
/* Internal encoder error */
|
||||
internal static int SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR = -111;
|
||||
|
||||
// Decoder error messages
|
||||
|
||||
/* Output sampling frequency lower than internal decoded sampling frequency */
|
||||
internal static int SILK_DEC_INVALID_SAMPLING_FREQUENCY = -200;
|
||||
|
||||
/* Payload size exceeded the maximum allowed 1024 bytes */
|
||||
internal static int SILK_DEC_PAYLOAD_TOO_LARGE = -201;
|
||||
|
||||
/* Payload has bit errors */
|
||||
internal static int SILK_DEC_PAYLOAD_ERROR = -202;
|
||||
|
||||
/* Payload has bit errors */
|
||||
internal static int SILK_DEC_INVALID_FRAME_SIZE = -203;
|
||||
}
|
||||
}
|
||||
714
Libraries/Concentus/CSharp/Concentus/Silk/Filters.cs
Normal file
714
Libraries/Concentus/CSharp/Concentus/Silk/Filters.cs
Normal file
@@ -0,0 +1,714 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Celt;
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class Filters
|
||||
{
|
||||
internal static void silk_warped_LPC_analysis_filter(
|
||||
int[] state, /* I/O State [order + 1] */
|
||||
int[] res_Q2, /* O Residual signal [length] */
|
||||
short[] coef_Q13, /* I Coefficients [order] */
|
||||
int coef_Q13_ptr,
|
||||
short[] input, /* I Input signal [length] */
|
||||
int input_ptr,
|
||||
short lambda_Q16, /* I Warping factor */
|
||||
int length, /* I Length of input signal */
|
||||
int order /* I Filter order (even) */
|
||||
)
|
||||
{
|
||||
int n, i;
|
||||
int acc_Q11, tmp1, tmp2;
|
||||
|
||||
/* Order must be even */
|
||||
Inlines.OpusAssert((order & 1) == 0);
|
||||
|
||||
for (n = 0; n < length; n++)
|
||||
{
|
||||
/* Output of lowpass section */
|
||||
tmp2 = Inlines.silk_SMLAWB(state[0], state[1], lambda_Q16);
|
||||
state[0] = Inlines.silk_LSHIFT(input[input_ptr + n], 14);
|
||||
/* Output of allpass section */
|
||||
tmp1 = Inlines.silk_SMLAWB(state[1], state[2] - tmp2, lambda_Q16);
|
||||
state[1] = tmp2;
|
||||
acc_Q11 = Inlines.silk_RSHIFT(order, 1);
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp2, coef_Q13[coef_Q13_ptr]);
|
||||
/* Loop over allpass sections */
|
||||
for (i = 2; i < order; i += 2)
|
||||
{
|
||||
/* Output of allpass section */
|
||||
tmp2 = Inlines.silk_SMLAWB(state[i], state[i + 1] - tmp1, lambda_Q16);
|
||||
state[i] = tmp1;
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp1, coef_Q13[coef_Q13_ptr + i - 1]);
|
||||
/* Output of allpass section */
|
||||
tmp1 = Inlines.silk_SMLAWB(state[i + 1], state[i + 2] - tmp2, lambda_Q16);
|
||||
state[i + 1] = tmp2;
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp2, coef_Q13[coef_Q13_ptr + i]);
|
||||
}
|
||||
state[order] = tmp1;
|
||||
acc_Q11 = Inlines.silk_SMLAWB(acc_Q11, tmp1, coef_Q13[coef_Q13_ptr + order - 1]);
|
||||
res_Q2[n] = Inlines.silk_LSHIFT((int)input[input_ptr + n], 2) - Inlines.silk_RSHIFT_ROUND(acc_Q11, 9);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void silk_prefilter(
|
||||
SilkChannelEncoder psEnc, /* I/O Encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I Encoder control */
|
||||
int[] xw_Q3, /* O Weighted signal */
|
||||
short[] x, /* I Speech signal */
|
||||
int x_ptr
|
||||
)
|
||||
{
|
||||
SilkPrefilterState P = psEnc.sPrefilt;
|
||||
int j, k, lag;
|
||||
int tmp_32;
|
||||
int AR1_shp_Q13;
|
||||
int px;
|
||||
int pxw_Q3;
|
||||
int HarmShapeGain_Q12, Tilt_Q14;
|
||||
int HarmShapeFIRPacked_Q12, LF_shp_Q14;
|
||||
int[] x_filt_Q12;
|
||||
int[] st_res_Q2;
|
||||
short[] B_Q10 = new short[2];
|
||||
|
||||
/* Set up pointers */
|
||||
px = x_ptr;
|
||||
pxw_Q3 = 0;
|
||||
lag = P.lagPrev;
|
||||
x_filt_Q12 = new int[psEnc.subfr_length];
|
||||
st_res_Q2 = new int[psEnc.subfr_length];
|
||||
for (k = 0; k < psEnc.nb_subfr; k++)
|
||||
{
|
||||
/* Update Variables that change per sub frame */
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
lag = psEncCtrl.pitchL[k];
|
||||
}
|
||||
|
||||
/* Noise shape parameters */
|
||||
HarmShapeGain_Q12 = Inlines.silk_SMULWB((int)psEncCtrl.HarmShapeGain_Q14[k], 16384 - psEncCtrl.HarmBoost_Q14[k]);
|
||||
Inlines.OpusAssert(HarmShapeGain_Q12 >= 0);
|
||||
HarmShapeFIRPacked_Q12 = Inlines.silk_RSHIFT(HarmShapeGain_Q12, 2);
|
||||
HarmShapeFIRPacked_Q12 |= Inlines.silk_LSHIFT((int)Inlines.silk_RSHIFT(HarmShapeGain_Q12, 1), 16);
|
||||
Tilt_Q14 = psEncCtrl.Tilt_Q14[k];
|
||||
LF_shp_Q14 = psEncCtrl.LF_shp_Q14[k];
|
||||
AR1_shp_Q13 = k * SilkConstants.MAX_SHAPE_LPC_ORDER;
|
||||
|
||||
/* Short term FIR filtering*/
|
||||
silk_warped_LPC_analysis_filter(P.sAR_shp, st_res_Q2, psEncCtrl.AR1_Q13, AR1_shp_Q13, x, px,
|
||||
(short)(psEnc.warping_Q16), psEnc.subfr_length, psEnc.shapingLPCOrder);
|
||||
|
||||
/* Reduce (mainly) low frequencies during harmonic emphasis */
|
||||
B_Q10[0] = (short)(Inlines.silk_RSHIFT_ROUND(psEncCtrl.GainsPre_Q14[k], 4));
|
||||
tmp_32 = Inlines.silk_SMLABB(((int)((TuningParameters.INPUT_TILT) * ((long)1 << (26)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.INPUT_TILT, 26)*/, psEncCtrl.HarmBoost_Q14[k], HarmShapeGain_Q12); /* Q26 */
|
||||
tmp_32 = Inlines.silk_SMLABB(tmp_32, psEncCtrl.coding_quality_Q14, ((int)((TuningParameters.HIGH_RATE_INPUT_TILT) * ((long)1 << (12)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.HIGH_RATE_INPUT_TILT, 12)*/); /* Q26 */
|
||||
tmp_32 = Inlines.silk_SMULWB(tmp_32, -psEncCtrl.GainsPre_Q14[k]); /* Q24 */
|
||||
tmp_32 = Inlines.silk_RSHIFT_ROUND(tmp_32, 14); /* Q10 */
|
||||
B_Q10[1] = (short)(Inlines.silk_SAT16(tmp_32));
|
||||
x_filt_Q12[0] = Inlines.silk_MLA(Inlines.silk_MUL(st_res_Q2[0], B_Q10[0]), P.sHarmHP_Q2, B_Q10[1]);
|
||||
for (j = 1; j < psEnc.subfr_length; j++)
|
||||
{
|
||||
x_filt_Q12[j] = Inlines.silk_MLA(Inlines.silk_MUL(st_res_Q2[j], B_Q10[0]), st_res_Q2[j - 1], B_Q10[1]);
|
||||
}
|
||||
P.sHarmHP_Q2 = st_res_Q2[psEnc.subfr_length - 1];
|
||||
|
||||
silk_prefilt(P, x_filt_Q12, xw_Q3, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc.subfr_length);
|
||||
|
||||
px += psEnc.subfr_length;
|
||||
pxw_Q3 += psEnc.subfr_length;
|
||||
}
|
||||
|
||||
P.lagPrev = psEncCtrl.pitchL[psEnc.nb_subfr - 1];
|
||||
|
||||
}
|
||||
|
||||
/* Prefilter for finding Quantizer input signal */
|
||||
static void silk_prefilt(
|
||||
SilkPrefilterState P, /* I/O state */
|
||||
int[] st_res_Q12, /* I short term residual signal */
|
||||
int[] xw_Q3, /* O prefiltered signal */
|
||||
int xw_Q3_ptr,
|
||||
int HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */
|
||||
int Tilt_Q14, /* I Tilt shaping coeficient */
|
||||
int LF_shp_Q14, /* I Low-frequancy shaping coeficients */
|
||||
int lag, /* I Lag for harmonic shaping */
|
||||
int length /* I Length of signals */
|
||||
)
|
||||
{
|
||||
int i, idx, LTP_shp_buf_idx;
|
||||
int n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
|
||||
int sLF_MA_shp_Q12, sLF_AR_shp_Q12;
|
||||
short[] LTP_shp_buf;
|
||||
|
||||
/* To speed up use temp variables instead of using the struct */
|
||||
LTP_shp_buf = P.sLTP_shp;
|
||||
LTP_shp_buf_idx = P.sLTP_shp_buf_idx;
|
||||
sLF_AR_shp_Q12 = P.sLF_AR_shp_Q12;
|
||||
sLF_MA_shp_Q12 = P.sLF_MA_shp_Q12;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (lag > 0)
|
||||
{
|
||||
/* unrolled loop */
|
||||
Inlines.OpusAssert(SilkConstants.HARM_SHAPE_FIR_TAPS == 3);
|
||||
idx = lag + LTP_shp_buf_idx;
|
||||
n_LTP_Q12 = Inlines.silk_SMULBB(LTP_shp_buf[(idx - SilkConstants.HARM_SHAPE_FIR_TAPS / 2 - 1) & SilkConstants.LTP_MASK], HarmShapeFIRPacked_Q12);
|
||||
n_LTP_Q12 = Inlines.silk_SMLABT(n_LTP_Q12, LTP_shp_buf[(idx - SilkConstants.HARM_SHAPE_FIR_TAPS / 2) & SilkConstants.LTP_MASK], HarmShapeFIRPacked_Q12);
|
||||
n_LTP_Q12 = Inlines.silk_SMLABB(n_LTP_Q12, LTP_shp_buf[(idx - SilkConstants.HARM_SHAPE_FIR_TAPS / 2 + 1) & SilkConstants.LTP_MASK], HarmShapeFIRPacked_Q12);
|
||||
}
|
||||
else {
|
||||
n_LTP_Q12 = 0;
|
||||
}
|
||||
|
||||
n_Tilt_Q10 = Inlines.silk_SMULWB(sLF_AR_shp_Q12, Tilt_Q14);
|
||||
n_LF_Q10 = Inlines.silk_SMLAWB(Inlines.silk_SMULWT(sLF_AR_shp_Q12, LF_shp_Q14), sLF_MA_shp_Q12, LF_shp_Q14);
|
||||
|
||||
sLF_AR_shp_Q12 = Inlines.silk_SUB32(st_res_Q12[i], Inlines.silk_LSHIFT(n_Tilt_Q10, 2));
|
||||
sLF_MA_shp_Q12 = Inlines.silk_SUB32(sLF_AR_shp_Q12, Inlines.silk_LSHIFT(n_LF_Q10, 2));
|
||||
|
||||
LTP_shp_buf_idx = (LTP_shp_buf_idx - 1) & SilkConstants.LTP_MASK;
|
||||
LTP_shp_buf[LTP_shp_buf_idx] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(sLF_MA_shp_Q12, 12));
|
||||
|
||||
xw_Q3[xw_Q3_ptr + i] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(sLF_MA_shp_Q12, n_LTP_Q12), 9);
|
||||
}
|
||||
|
||||
/* Copy temp variable back to state */
|
||||
P.sLF_AR_shp_Q12 = sLF_AR_shp_Q12;
|
||||
P.sLF_MA_shp_Q12 = sLF_MA_shp_Q12;
|
||||
P.sLTP_shp_buf_idx = LTP_shp_buf_idx;
|
||||
}
|
||||
|
||||
#if !UNSAFE
|
||||
|
||||
/// <summary>
|
||||
/// Second order ARMA filter, alternative implementation
|
||||
/// </summary>
|
||||
/// <param name="input">I input signal</param>
|
||||
/// <param name="B_Q28">I MA coefficients [3]</param>
|
||||
/// <param name="A_Q28">I AR coefficients [2]</param>
|
||||
/// <param name="S">I/O State vector [2]</param>
|
||||
/// <param name="output">O output signal</param>
|
||||
/// <param name="len">I signal length (must be even)</param>
|
||||
/// <param name="stride">I Operate on interleaved signal if > 1</param>
|
||||
internal static void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
|
||||
int k;
|
||||
int inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
|
||||
|
||||
/* Negate A_Q28 values and split in two parts */
|
||||
A0_L_Q28 = (-A_Q28[0]) & 0x00003FFF; /* lower part */
|
||||
A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); /* upper part */
|
||||
A1_L_Q28 = (-A_Q28[1]) & 0x00003FFF; /* lower part */
|
||||
A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); /* upper part */
|
||||
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
/* S[ 0 ], S[ 1 ]: Q12 */
|
||||
inval = input[input_ptr + k * stride];
|
||||
out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[0], B_Q28[0], inval), 2);
|
||||
|
||||
S[0] = S[1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14);
|
||||
S[0] = Inlines.silk_SMLAWB(S[0], out32_Q14, A0_U_Q28);
|
||||
S[0] = Inlines.silk_SMLAWB(S[0], B_Q28[1], inval);
|
||||
|
||||
S[1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14);
|
||||
S[1] = Inlines.silk_SMLAWB(S[1], out32_Q14, A1_U_Q28);
|
||||
S[1] = Inlines.silk_SMLAWB(S[1], B_Q28[2], inval);
|
||||
|
||||
/* Scale back to Q0 and saturate */
|
||||
output[output_ptr + k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + (1 << 14) - 1, 14));
|
||||
}
|
||||
}
|
||||
|
||||
internal static void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
int S_ptr,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
|
||||
int k;
|
||||
int inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
|
||||
|
||||
/* Negate A_Q28 values and split in two parts */
|
||||
A0_L_Q28 = (-A_Q28[0]) & 0x00003FFF; /* lower part */
|
||||
A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); /* upper part */
|
||||
A1_L_Q28 = (-A_Q28[1]) & 0x00003FFF; /* lower part */
|
||||
A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); /* upper part */
|
||||
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
int s1 = S_ptr + 1;
|
||||
/* S[ 0 ], S[ 1 ]: Q12 */
|
||||
inval = input[input_ptr + k * stride];
|
||||
out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[S_ptr], B_Q28[0], inval), 2);
|
||||
|
||||
S[S_ptr] = S[s1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14);
|
||||
S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], out32_Q14, A0_U_Q28);
|
||||
S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], B_Q28[1], inval);
|
||||
|
||||
S[s1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14);
|
||||
S[s1] = Inlines.silk_SMLAWB(S[s1], out32_Q14, A1_U_Q28);
|
||||
S[s1] = Inlines.silk_SMLAWB(S[s1], B_Q28[2], inval);
|
||||
|
||||
/* Scale back to Q0 and saturate */
|
||||
output[output_ptr + k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + (1 << 14) - 1, 14));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/// <summary>
|
||||
/// Second order ARMA filter, alternative implementation
|
||||
/// </summary>
|
||||
/// <param name="input">I input signal</param>
|
||||
/// <param name="B_Q28">I MA coefficients [3]</param>
|
||||
/// <param name="A_Q28">I AR coefficients [2]</param>
|
||||
/// <param name="S">I/O State vector [2]</param>
|
||||
/// <param name="output">O output signal</param>
|
||||
/// <param name="len">I signal length (must be even)</param>
|
||||
/// <param name="stride">I Operate on interleaved signal if > 1</param>
|
||||
internal static unsafe void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
int S_ptr,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
|
||||
int k;
|
||||
int inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
|
||||
|
||||
/* Negate A_Q28 values and split in two parts */
|
||||
A0_L_Q28 = (-A_Q28[0]) & 0x00003FFF; /* lower part */
|
||||
A0_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[0], 14); /* upper part */
|
||||
A1_L_Q28 = (-A_Q28[1]) & 0x00003FFF; /* lower part */
|
||||
A1_U_Q28 = Inlines.silk_RSHIFT(-A_Q28[1], 14); /* upper part */
|
||||
|
||||
fixed (short* pinput_base = input, poutput_base = output)
|
||||
{
|
||||
fixed (int* pS_base = S, pBQ28 = B_Q28)
|
||||
{
|
||||
int* pS = pS_base + S_ptr;
|
||||
short* pinput = pinput_base + input_ptr;
|
||||
short* poutput = poutput_base + output_ptr;
|
||||
for (k = 0; k < len; k++)
|
||||
{
|
||||
/* S[ 0 ], S[ 1 ]: Q12 */
|
||||
inval = pinput[k * stride];
|
||||
out32_Q14 = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(pS[0], pBQ28[0], inval), 2);
|
||||
|
||||
pS[0] = pS[1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A0_L_Q28), 14);
|
||||
pS[0] = Inlines.silk_SMLAWB(pS[0], out32_Q14, A0_U_Q28);
|
||||
pS[0] = Inlines.silk_SMLAWB(pS[0], pBQ28[1], inval);
|
||||
|
||||
pS[1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(out32_Q14, A1_L_Q28), 14);
|
||||
pS[1] = Inlines.silk_SMLAWB(pS[1], out32_Q14, A1_U_Q28);
|
||||
pS[1] = Inlines.silk_SMLAWB(pS[1], pBQ28[2], inval);
|
||||
|
||||
/* Scale back to Q0 and saturate */
|
||||
poutput[k * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(out32_Q14 + (1 << 14) - 1, 14));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void silk_biquad_alt(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int[] S,
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
int len,
|
||||
int stride)
|
||||
{
|
||||
silk_biquad_alt(input, input_ptr, B_Q28, A_Q28, S, 0, output, output_ptr, len, stride);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Coefficients for 2-band filter bank based on first-order allpass filters */
|
||||
private readonly static short A_fb1_20 = 5394 << 1;
|
||||
private readonly static short A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */
|
||||
|
||||
/// <summary>
|
||||
/// Split signal into two decimated bands using first-order allpass filters
|
||||
/// </summary>
|
||||
/// <param name="input">I Input signal [N]</param>
|
||||
/// <param name="S">I/O State vector [2]</param>
|
||||
/// <param name="outL">O Low band [N/2]</param>
|
||||
/// <param name="outH">O High band [N/2]</param>
|
||||
/// <param name="N">I Number of input samples</param>
|
||||
internal static void silk_ana_filt_bank_1(
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
int[] S,
|
||||
short[] outL,
|
||||
short[] outH,
|
||||
int outH_ptr,
|
||||
int N)
|
||||
{
|
||||
int k, N2 = Inlines.silk_RSHIFT(N, 1);
|
||||
int in32, X, Y, out_1, out_2;
|
||||
|
||||
/* Internal variables and state are in Q10 format */
|
||||
for (k = 0; k < N2; k++)
|
||||
{
|
||||
/* Convert to Q10 */
|
||||
in32 = Inlines.silk_LSHIFT((int)input[input_ptr + 2 * k], 10);
|
||||
|
||||
/* All-pass section for even input sample */
|
||||
Y = Inlines.silk_SUB32(in32, S[0]);
|
||||
X = Inlines.silk_SMLAWB(Y, Y, A_fb1_21);
|
||||
out_1 = Inlines.silk_ADD32(S[0], X);
|
||||
S[0] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Convert to Q10 */
|
||||
in32 = Inlines.silk_LSHIFT((int)input[input_ptr + 2 * k + 1], 10);
|
||||
|
||||
/* All-pass section for odd input sample, and add to output of previous section */
|
||||
Y = Inlines.silk_SUB32(in32, S[1]);
|
||||
X = Inlines.silk_SMULWB(Y, A_fb1_20);
|
||||
out_2 = Inlines.silk_ADD32(S[1], X);
|
||||
S[1] = Inlines.silk_ADD32(in32, X);
|
||||
|
||||
/* Add/subtract, convert back to int16 and store to output */
|
||||
outL[k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD32(out_2, out_1), 11));
|
||||
outH[outH_ptr + k] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(out_2, out_1), 11));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chirp (bandwidth expand) LP AR filter
|
||||
/// </summary>
|
||||
/// <param name="ar">I/O AR filter to be expanded (without leading 1)</param>
|
||||
/// <param name="d">I Length of ar</param>
|
||||
/// <param name="chirp_Q16">I Chirp factor in Q16</param>
|
||||
internal static void silk_bwexpander_32(int[] ar, int d, int chirp_Q16)
|
||||
{
|
||||
int i;
|
||||
int chirp_minus_one_Q16 = chirp_Q16 - 65536;
|
||||
|
||||
for (i = 0; i < d - 1; i++)
|
||||
{
|
||||
ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]);
|
||||
chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, chirp_minus_one_Q16), 16);
|
||||
}
|
||||
|
||||
ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elliptic/Cauer filters designed with 0.1 dB passband ripple,
|
||||
/// 80 dB minimum stopband attenuation, and
|
||||
/// [0.95 : 0.15 : 0.35] normalized cut off frequencies.
|
||||
/// Helper function, interpolates the filter taps
|
||||
/// </summary>
|
||||
/// <param name="B_Q28">order [TRANSITION_NB]</param>
|
||||
/// <param name="A_Q28">order [TRANSITION_NA]</param>
|
||||
/// <param name="ind"></param>
|
||||
/// <param name="fac_Q16"></param>
|
||||
internal static void silk_LP_interpolate_filter_taps(
|
||||
int[] B_Q28,
|
||||
int[] A_Q28,
|
||||
int ind,
|
||||
int fac_Q16)
|
||||
{
|
||||
int nb, na;
|
||||
|
||||
if (ind < SilkConstants.TRANSITION_INT_NUM - 1)
|
||||
{
|
||||
if (fac_Q16 > 0)
|
||||
{
|
||||
if (fac_Q16 < 32768)
|
||||
{
|
||||
/* fac_Q16 is in range of a 16-bit int */
|
||||
/* Piece-wise linear interpolation of B and A */
|
||||
for (nb = 0; nb < SilkConstants.TRANSITION_NB; nb++)
|
||||
{
|
||||
B_Q28[nb] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_B_Q28[ind][nb],
|
||||
Tables.silk_Transition_LP_B_Q28[ind + 1][nb] -
|
||||
Tables.silk_Transition_LP_B_Q28[ind][nb],
|
||||
fac_Q16);
|
||||
}
|
||||
|
||||
for (na = 0; na < SilkConstants.TRANSITION_NA; na++)
|
||||
{
|
||||
A_Q28[na] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_A_Q28[ind][na],
|
||||
Tables.silk_Transition_LP_A_Q28[ind + 1][na] -
|
||||
Tables.silk_Transition_LP_A_Q28[ind][na],
|
||||
fac_Q16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */
|
||||
Inlines.OpusAssert(fac_Q16 - (1 << 16) == Inlines.silk_SAT16(fac_Q16 - (1 << 16)));
|
||||
|
||||
/* Piece-wise linear interpolation of B and A */
|
||||
|
||||
for (nb = 0; nb < SilkConstants.TRANSITION_NB; nb++)
|
||||
{
|
||||
B_Q28[nb] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_B_Q28[ind + 1][nb],
|
||||
Tables.silk_Transition_LP_B_Q28[ind + 1][nb] -
|
||||
Tables.silk_Transition_LP_B_Q28[ind][nb],
|
||||
fac_Q16 - ((int)1 << 16));
|
||||
}
|
||||
|
||||
for (na = 0; na < SilkConstants.TRANSITION_NA; na++)
|
||||
{
|
||||
A_Q28[na] = Inlines.silk_SMLAWB(
|
||||
Tables.silk_Transition_LP_A_Q28[ind + 1][na],
|
||||
Tables.silk_Transition_LP_A_Q28[ind + 1][na] -
|
||||
Tables.silk_Transition_LP_A_Q28[ind][na],
|
||||
fac_Q16 - ((int)1 << 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(Tables.silk_Transition_LP_B_Q28[ind], 0, B_Q28, 0, SilkConstants.TRANSITION_NB);
|
||||
Array.Copy(Tables.silk_Transition_LP_A_Q28[ind], 0, A_Q28, 0, SilkConstants.TRANSITION_NA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(Tables.silk_Transition_LP_B_Q28[SilkConstants.TRANSITION_INT_NUM - 1], 0, B_Q28, 0, SilkConstants.TRANSITION_NB);
|
||||
Array.Copy(Tables.silk_Transition_LP_A_Q28[SilkConstants.TRANSITION_INT_NUM - 1], 0, A_Q28, 0, SilkConstants.TRANSITION_NA);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LPC analysis filter
|
||||
/// NB! State is kept internally and the
|
||||
/// filter always starts with zero state
|
||||
/// first d output samples are set to zero
|
||||
/// </summary>
|
||||
/// <param name="output">O Output signal</param>
|
||||
/// <param name="input">I Input signal</param>
|
||||
/// <param name="B">I MA prediction coefficients, Q12 [order]</param>
|
||||
/// <param name="len">I Signal length</param>
|
||||
/// <param name="d">I Filter order</param>
|
||||
internal static void silk_LPC_analysis_filter(
|
||||
short[] output,
|
||||
int output_ptr,
|
||||
short[] input,
|
||||
int input_ptr,
|
||||
short[] B,
|
||||
int B_ptr,
|
||||
int len,
|
||||
int d)
|
||||
{
|
||||
int j;
|
||||
|
||||
short[] mem = new short[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
short[] num = new short[SilkConstants.SILK_MAX_ORDER_LPC];
|
||||
|
||||
Inlines.OpusAssert(d >= 6);
|
||||
Inlines.OpusAssert((d & 1) == 0);
|
||||
Inlines.OpusAssert(d <= len);
|
||||
|
||||
Inlines.OpusAssert(d <= SilkConstants.SILK_MAX_ORDER_LPC);
|
||||
for (j = 0; j < d; j++)
|
||||
{
|
||||
num[j] = (short)(0 - B[B_ptr + j]);
|
||||
}
|
||||
for (j = 0; j < d; j++)
|
||||
{
|
||||
mem[j] = input[input_ptr + d - j - 1];
|
||||
}
|
||||
#if UNSAFE
|
||||
unsafe
|
||||
{
|
||||
fixed (short* pinput_base = input, poutput_base = output)
|
||||
{
|
||||
short* pinput = pinput_base + input_ptr + d;
|
||||
short* poutput = poutput_base + output_ptr + d;
|
||||
Kernels.celt_fir(pinput, num, poutput, len - d, d, mem);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Kernels.celt_fir(input, input_ptr + d, num, output, output_ptr + d, len - d, d, mem);
|
||||
#endif
|
||||
for (j = output_ptr; j < output_ptr + d; j++)
|
||||
{
|
||||
output[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private const int QA = 24;
|
||||
private static readonly int A_LIMIT = ((int)((0.99975f) * ((long)1 << (QA)) + 0.5))/*Inlines.SILK_CONST(0.99975f, QA)*/;
|
||||
|
||||
/// <summary>
|
||||
/// Compute inverse of LPC prediction gain, and
|
||||
/// test if LPC coefficients are stable (all poles within unit circle)
|
||||
/// </summary>
|
||||
/// <param name="A_QA">Prediction coefficients, order [2][SILK_MAX_ORDER_LPC]</param>
|
||||
/// <param name="order">Prediction order</param>
|
||||
/// <returns>inverse prediction gain in energy domain, Q30</returns>
|
||||
internal static int LPC_inverse_pred_gain_QA(
|
||||
int[][] A_QA,
|
||||
int order)
|
||||
{
|
||||
int k, n, mult2Q;
|
||||
int invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
|
||||
int[] Aold_QA, Anew_QA;
|
||||
|
||||
Anew_QA = A_QA[order & 1];
|
||||
|
||||
invGain_Q30 = (int)1 << 30;
|
||||
for (k = order - 1; k > 0; k--)
|
||||
{
|
||||
/* Check for stability */
|
||||
if ((Anew_QA[k] > A_LIMIT) || (Anew_QA[k] < -A_LIMIT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[k], 31 - QA);
|
||||
|
||||
/* rc_mult1_Q30 range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
Inlines.OpusAssert(rc_mult1_Q30 > (1 << 15)); /* reduce A_LIMIT if fails */
|
||||
Inlines.OpusAssert(rc_mult1_Q30 <= (1 << 30));
|
||||
|
||||
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
|
||||
mult2Q = 32 - Inlines.silk_CLZ32(Inlines.silk_abs(rc_mult1_Q30));
|
||||
rc_mult2 = Inlines.silk_INVERSE32_varQ(rc_mult1_Q30, mult2Q + 30);
|
||||
|
||||
/* Update inverse gain */
|
||||
/* invGain_Q30 range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2);
|
||||
Inlines.OpusAssert(invGain_Q30 >= 0);
|
||||
Inlines.OpusAssert(invGain_Q30 <= (1 << 30));
|
||||
|
||||
/* Swap pointers */
|
||||
Aold_QA = Anew_QA;
|
||||
Anew_QA = A_QA[k & 1];
|
||||
|
||||
/* Update AR coefficient */
|
||||
for (n = 0; n < k; n++)
|
||||
{
|
||||
tmp_QA = Aold_QA[n] - Inlines.MUL32_FRAC_Q(Aold_QA[k - n - 1], rc_Q31, 31);
|
||||
Anew_QA[n] = Inlines.MUL32_FRAC_Q(tmp_QA, rc_mult2, mult2Q);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for stability */
|
||||
if ((Anew_QA[0] > A_LIMIT) || (Anew_QA[0] < -A_LIMIT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = 0 - Inlines.silk_LSHIFT(Anew_QA[0], 31 - QA);
|
||||
|
||||
/* Range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31);
|
||||
|
||||
/* Update inverse gain */
|
||||
/* Range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, rc_mult1_Q30), 2);
|
||||
Inlines.OpusAssert(invGain_Q30 >= 0);
|
||||
Inlines.OpusAssert(invGain_Q30 <= 1 << 30);
|
||||
|
||||
return invGain_Q30;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For input in Q12 domain
|
||||
/// </summary>
|
||||
/// <param name="A_Q12">Prediction coefficients, Q12 [order]</param>
|
||||
/// <param name="order">I Prediction order</param>
|
||||
/// <returns>inverse prediction gain in energy domain, Q30</returns>
|
||||
internal static int silk_LPC_inverse_pred_gain(short[] A_Q12, int order)
|
||||
{
|
||||
int k;
|
||||
int[][] Atmp_QA = new int[2][];
|
||||
Atmp_QA[0] = new int[order];
|
||||
Atmp_QA[1] = new int[order];
|
||||
int[] Anew_QA;
|
||||
int DC_resp = 0;
|
||||
|
||||
Anew_QA = Atmp_QA[order & 1];
|
||||
|
||||
/* Increase Q domain of the AR coefficients */
|
||||
for (k = 0; k < order; k++)
|
||||
{
|
||||
DC_resp += (int)A_Q12[k];
|
||||
Anew_QA[k] = Inlines.silk_LSHIFT32((int)A_Q12[k], QA - 12);
|
||||
}
|
||||
|
||||
/* If the DC is unstable, we don't even need to do the full calculations */
|
||||
if (DC_resp >= 4096)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return LPC_inverse_pred_gain_QA(Atmp_QA, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
184
Libraries/Concentus/CSharp/Concentus/Silk/FindLPC.cs
Normal file
184
Libraries/Concentus/CSharp/Concentus/Silk/FindLPC.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindLPC
|
||||
{
|
||||
/* Finds LPC vector from correlations, and converts to NLSF */
|
||||
internal static void silk_find_LPC(
|
||||
SilkChannelEncoder psEncC, /* I/O Encoder state */
|
||||
short[] NLSF_Q15, /* O NLSFs */
|
||||
short[] x, /* I Input signal */
|
||||
int minInvGain_Q30 /* I Inverse of max prediction gain */
|
||||
)
|
||||
{
|
||||
int k, subfr_length;
|
||||
int[] a_Q16 = new int[SilkConstants.MAX_LPC_ORDER];
|
||||
int isInterpLower, shift;
|
||||
int res_nrg0, res_nrg1;
|
||||
int rshift0, rshift1;
|
||||
BoxedValueInt scratch_box1 = new BoxedValueInt();
|
||||
BoxedValueInt scratch_box2 = new BoxedValueInt();
|
||||
|
||||
/* Used only for LSF interpolation */
|
||||
int[] a_tmp_Q16 = new int[SilkConstants.MAX_LPC_ORDER];
|
||||
int res_nrg_interp, res_nrg, res_tmp_nrg;
|
||||
int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;
|
||||
short[] a_tmp_Q12 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
short[] NLSF0_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
|
||||
subfr_length = psEncC.subfr_length + psEncC.predictLPCOrder;
|
||||
|
||||
/* Default: no interpolation */
|
||||
psEncC.indices.NLSFInterpCoef_Q2 = 4;
|
||||
|
||||
/* Burg AR analysis for the full frame */
|
||||
BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_Q16, x, 0, minInvGain_Q30, subfr_length, psEncC.nb_subfr, psEncC.predictLPCOrder);
|
||||
res_nrg = scratch_box1.Val;
|
||||
res_nrg_Q = scratch_box2.Val;
|
||||
|
||||
if (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR)
|
||||
{
|
||||
short[] LPC_res;
|
||||
|
||||
/* Optimal solution for last 10 ms */
|
||||
BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_tmp_Q16, x, (2 * subfr_length), minInvGain_Q30, subfr_length, 2, psEncC.predictLPCOrder);
|
||||
res_tmp_nrg = scratch_box1.Val;
|
||||
res_tmp_nrg_Q = scratch_box2.Val;
|
||||
|
||||
/* subtract residual energy here, as that's easier than adding it to the */
|
||||
/* residual energy of the first 10 ms in each iteration of the search below */
|
||||
shift = res_tmp_nrg_Q - res_nrg_Q;
|
||||
if (shift >= 0)
|
||||
{
|
||||
if (shift < 32)
|
||||
{
|
||||
res_nrg = res_nrg - Inlines.silk_RSHIFT(res_tmp_nrg, shift);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Inlines.OpusAssert(shift > -32);
|
||||
res_nrg = Inlines.silk_RSHIFT(res_nrg, -shift) - res_tmp_nrg;
|
||||
res_nrg_Q = res_tmp_nrg_Q;
|
||||
}
|
||||
|
||||
/* Convert to NLSFs */
|
||||
NLSF.silk_A2NLSF(NLSF_Q15, a_tmp_Q16, psEncC.predictLPCOrder);
|
||||
|
||||
LPC_res = new short[2 * subfr_length];
|
||||
|
||||
/* Search over interpolation indices to find the one with lowest residual energy */
|
||||
for (k = 3; k >= 0; k--)
|
||||
{
|
||||
/* Interpolate NLSFs for first half */
|
||||
Inlines.silk_interpolate(NLSF0_Q15, psEncC.prev_NLSFq_Q15, NLSF_Q15, k, psEncC.predictLPCOrder);
|
||||
|
||||
/* Convert to LPC for residual energy evaluation */
|
||||
NLSF.silk_NLSF2A(a_tmp_Q12, NLSF0_Q15, psEncC.predictLPCOrder);
|
||||
|
||||
/* Calculate residual energy with NLSF interpolation */
|
||||
Filters.silk_LPC_analysis_filter(LPC_res, 0, x, 0, a_tmp_Q12, 0, 2 * subfr_length, psEncC.predictLPCOrder);
|
||||
|
||||
SumSqrShift.silk_sum_sqr_shift(out res_nrg0, out rshift0, LPC_res, psEncC.predictLPCOrder, subfr_length - psEncC.predictLPCOrder);
|
||||
|
||||
SumSqrShift.silk_sum_sqr_shift(out res_nrg1, out rshift1, LPC_res, psEncC.predictLPCOrder + subfr_length, subfr_length - psEncC.predictLPCOrder);
|
||||
|
||||
/* Add subframe energies from first half frame */
|
||||
shift = rshift0 - rshift1;
|
||||
if (shift >= 0)
|
||||
{
|
||||
res_nrg1 = Inlines.silk_RSHIFT(res_nrg1, shift);
|
||||
res_nrg_interp_Q = -rshift0;
|
||||
}
|
||||
else {
|
||||
res_nrg0 = Inlines.silk_RSHIFT(res_nrg0, -shift);
|
||||
res_nrg_interp_Q = -rshift1;
|
||||
}
|
||||
res_nrg_interp = Inlines.silk_ADD32(res_nrg0, res_nrg1);
|
||||
|
||||
/* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
|
||||
shift = res_nrg_interp_Q - res_nrg_Q;
|
||||
if (shift >= 0)
|
||||
{
|
||||
if (Inlines.silk_RSHIFT(res_nrg_interp, shift) < res_nrg)
|
||||
{
|
||||
isInterpLower = (true ? 1 : 0);
|
||||
}
|
||||
else {
|
||||
isInterpLower = (false ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (-shift < 32)
|
||||
{
|
||||
if (res_nrg_interp < Inlines.silk_RSHIFT(res_nrg, -shift))
|
||||
{
|
||||
isInterpLower = (true ? 1 : 0);
|
||||
}
|
||||
else {
|
||||
isInterpLower = (false ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
isInterpLower = (false ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine whether current interpolated NLSFs are best so far */
|
||||
if (isInterpLower == (true ? 1 : 0))
|
||||
{
|
||||
/* Interpolation has lower residual energy */
|
||||
res_nrg = res_nrg_interp;
|
||||
res_nrg_Q = res_nrg_interp_Q;
|
||||
psEncC.indices.NLSFInterpCoef_Q2 = (sbyte)k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (psEncC.indices.NLSFInterpCoef_Q2 == 4)
|
||||
{
|
||||
/* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
|
||||
NLSF.silk_A2NLSF(NLSF_Q15, a_Q16, psEncC.predictLPCOrder);
|
||||
}
|
||||
|
||||
Inlines.OpusAssert(psEncC.indices.NLSFInterpCoef_Q2 == 4 || (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
295
Libraries/Concentus/CSharp/Concentus/Silk/FindLTP.cs
Normal file
295
Libraries/Concentus/CSharp/Concentus/Silk/FindLTP.cs
Normal file
@@ -0,0 +1,295 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindLTP
|
||||
{
|
||||
/* Head room for correlations */
|
||||
private const int LTP_CORRS_HEAD_ROOM = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Finds linear prediction coeffecients and weights
|
||||
/// </summary>
|
||||
/// <param name="b_Q14"></param>
|
||||
/// <param name="WLTP"></param>
|
||||
/// <param name="LTPredCodGain_Q7"></param>
|
||||
/// <param name="r_lpc"></param>
|
||||
/// <param name="lag"></param>
|
||||
/// <param name="Wght_Q15"></param>
|
||||
/// <param name="subfr_length"></param>
|
||||
/// <param name="nb_subfr"></param>
|
||||
/// <param name="mem_offset"></param>
|
||||
/// <param name="corr_rshifts"></param>
|
||||
internal static void silk_find_LTP(
|
||||
short[] b_Q14, /* O LTP coefs [SilkConstants.MAX_NB_SUBFR * SilkConstants.LTP_ORDER] */
|
||||
int[] WLTP, /* O Weight for LTP quantization [SilkConstants.MAX_NB_SUBFR * SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER] */
|
||||
BoxedValueInt LTPredCodGain_Q7, /* O LTP coding gain */
|
||||
short[] r_lpc, /* I residual signal after LPC signal + state for first 10 ms */
|
||||
int[] lag, /* I LTP lags [SilkConstants.MAX_NB_SUBFR] */
|
||||
int[] Wght_Q15, /* I weights [SilkConstants.MAX_NB_SUBFR] */
|
||||
int subfr_length, /* I subframe length */
|
||||
int nb_subfr, /* I number of subframes */
|
||||
int mem_offset, /* I number of samples in LTP memory */
|
||||
int[] corr_rshifts /* O right shifts applied to correlations [SilkConstants.MAX_NB_SUBFR] */
|
||||
)
|
||||
{
|
||||
int i, k, lshift;
|
||||
int r_ptr;
|
||||
int lag_ptr;
|
||||
int b_Q14_ptr;
|
||||
|
||||
int regu;
|
||||
int WLTP_ptr;
|
||||
int[] b_Q16 = new int[SilkConstants.LTP_ORDER];
|
||||
int[] delta_b_Q14 = new int[SilkConstants.LTP_ORDER];
|
||||
int[] d_Q14 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int[] nrg = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int g_Q26;
|
||||
int[] w = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int WLTP_max, max_abs_d_Q14, max_w_bits;
|
||||
|
||||
int temp32, denom32;
|
||||
int extra_shifts;
|
||||
int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs;
|
||||
int LPC_res_nrg, LPC_LTP_res_nrg, div_Q16;
|
||||
int[] Rr = new int[SilkConstants.LTP_ORDER];
|
||||
int[] rr = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int wd, m_Q12;
|
||||
|
||||
b_Q14_ptr = 0;
|
||||
WLTP_ptr = 0;
|
||||
r_ptr = mem_offset;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
lag_ptr = r_ptr - (lag[k] + SilkConstants.LTP_ORDER / 2);
|
||||
|
||||
SumSqrShift.silk_sum_sqr_shift(out rr[k], out rr_shifts, r_lpc, r_ptr, subfr_length); /* rr[ k ] in Q( -rr_shifts ) */
|
||||
|
||||
/* Assure headroom */
|
||||
LZs = Inlines.silk_CLZ32(rr[k]);
|
||||
if (LZs < LTP_CORRS_HEAD_ROOM)
|
||||
{
|
||||
rr[k] = Inlines.silk_RSHIFT_ROUND(rr[k], LTP_CORRS_HEAD_ROOM - LZs);
|
||||
rr_shifts += (LTP_CORRS_HEAD_ROOM - LZs);
|
||||
}
|
||||
corr_rshifts[k] = rr_shifts;
|
||||
BoxedValueInt boxed_shifts = new BoxedValueInt(corr_rshifts[k]);
|
||||
CorrelateMatrix.silk_corrMatrix(r_lpc, lag_ptr, subfr_length, SilkConstants.LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP, WLTP_ptr, boxed_shifts); /* WLTP_ptr in Q( -corr_rshifts[ k ] ) */
|
||||
corr_rshifts[k] = boxed_shifts.Val;
|
||||
|
||||
/* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */
|
||||
CorrelateMatrix.silk_corrVector(r_lpc, lag_ptr, r_lpc, r_ptr, subfr_length, SilkConstants.LTP_ORDER, Rr, corr_rshifts[k]); /* Rr_ptr in Q( -corr_rshifts[ k ] ) */
|
||||
if (corr_rshifts[k] > rr_shifts)
|
||||
{
|
||||
rr[k] = Inlines.silk_RSHIFT(rr[k], corr_rshifts[k] - rr_shifts); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */
|
||||
}
|
||||
Inlines.OpusAssert(rr[k] >= 0);
|
||||
|
||||
regu = 1;
|
||||
regu = Inlines.silk_SMLAWB(regu, rr[k], ((int)((TuningParameters.LTP_DAMPING / 3) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_DAMPING / 3, 16)*/);
|
||||
regu = Inlines.silk_SMLAWB(regu, Inlines.MatrixGet(WLTP, WLTP_ptr, 0, 0, SilkConstants.LTP_ORDER), ((int)((TuningParameters.LTP_DAMPING / 3) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_DAMPING / 3, 16)*/);
|
||||
regu = Inlines.silk_SMLAWB(regu, Inlines.MatrixGet(WLTP, WLTP_ptr, SilkConstants.LTP_ORDER - 1, SilkConstants.LTP_ORDER - 1, SilkConstants.LTP_ORDER), ((int)((TuningParameters.LTP_DAMPING / 3) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_DAMPING / 3, 16)*/);
|
||||
RegularizeCorrelations.silk_regularize_correlations(WLTP, WLTP_ptr, rr, k, regu, SilkConstants.LTP_ORDER);
|
||||
|
||||
LinearAlgebra.silk_solve_LDL(WLTP, WLTP_ptr, SilkConstants.LTP_ORDER, Rr, b_Q16); /* WLTP_ptr and Rr_ptr both in Q(-corr_rshifts[k]) */
|
||||
|
||||
/* Limit and store in Q14 */
|
||||
silk_fit_LTP(b_Q16, b_Q14, b_Q14_ptr);
|
||||
|
||||
/* Calculate residual energy */
|
||||
nrg[k] = ResidualEnergy.silk_residual_energy16_covar(b_Q14, b_Q14_ptr, WLTP, WLTP_ptr, Rr, rr[k], SilkConstants.LTP_ORDER, 14); /* nrg in Q( -corr_rshifts[ k ] ) */
|
||||
|
||||
/* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */
|
||||
extra_shifts = Inlines.silk_min_int(corr_rshifts[k], LTP_CORRS_HEAD_ROOM);
|
||||
denom32 = Inlines.silk_LSHIFT_SAT32(Inlines.silk_SMULWB(nrg[k], Wght_Q15[k]), 1 + extra_shifts) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */
|
||||
Inlines.silk_RSHIFT(Inlines.silk_SMULWB((int)subfr_length, 655), corr_rshifts[k] - extra_shifts); /* Q( -corr_rshifts[ k ] + extra_shifts ) */
|
||||
denom32 = Inlines.silk_max(denom32, 1);
|
||||
Inlines.OpusAssert(((long)Wght_Q15[k] << 16) < int.MaxValue); /* Wght always < 0.5 in Q0 */
|
||||
temp32 = Inlines.silk_DIV32(Inlines.silk_LSHIFT((int)Wght_Q15[k], 16), denom32); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */
|
||||
temp32 = Inlines.silk_RSHIFT(temp32, 31 + corr_rshifts[k] - extra_shifts - 26); /* Q26 */
|
||||
|
||||
/* Limit temp such that the below scaling never wraps around */
|
||||
WLTP_max = 0;
|
||||
for (i = WLTP_ptr; i < WLTP_ptr + (SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER); i++)
|
||||
{
|
||||
WLTP_max = Inlines.silk_max(WLTP[i], WLTP_max);
|
||||
}
|
||||
lshift = Inlines.silk_CLZ32(WLTP_max) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor */
|
||||
Inlines.OpusAssert(26 - 18 + lshift >= 0);
|
||||
if (26 - 18 + lshift < 31)
|
||||
{
|
||||
temp32 = Inlines.silk_min_32(temp32, Inlines.silk_LSHIFT((int)1, 26 - 18 + lshift));
|
||||
}
|
||||
|
||||
Inlines.silk_scale_vector32_Q26_lshift_18(WLTP, WLTP_ptr, temp32, SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */
|
||||
|
||||
w[k] = Inlines.MatrixGet(WLTP, WLTP_ptr, SilkConstants.LTP_ORDER / 2, SilkConstants.LTP_ORDER / 2, SilkConstants.LTP_ORDER); /* w in Q( 18 - corr_rshifts[ k ] ) */
|
||||
Inlines.OpusAssert(w[k] >= 0);
|
||||
|
||||
r_ptr += subfr_length;
|
||||
b_Q14_ptr += SilkConstants.LTP_ORDER;
|
||||
WLTP_ptr += (SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER);
|
||||
}
|
||||
|
||||
maxRshifts = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
maxRshifts = Inlines.silk_max_int(corr_rshifts[k], maxRshifts);
|
||||
}
|
||||
|
||||
/* Compute LTP coding gain */
|
||||
if (LTPredCodGain_Q7 != null)
|
||||
{
|
||||
LPC_LTP_res_nrg = 0;
|
||||
LPC_res_nrg = 0;
|
||||
Inlines.OpusAssert(LTP_CORRS_HEAD_ROOM >= 2); /* Check that no overflow will happen when adding */
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
LPC_res_nrg = Inlines.silk_ADD32(LPC_res_nrg, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(rr[k], Wght_Q15[k]), 1), 1 + (maxRshifts - corr_rshifts[k]))); /* Q( -maxRshifts ) */
|
||||
LPC_LTP_res_nrg = Inlines.silk_ADD32(LPC_LTP_res_nrg, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(nrg[k], Wght_Q15[k]), 1), 1 + (maxRshifts - corr_rshifts[k]))); /* Q( -maxRshifts ) */
|
||||
}
|
||||
LPC_LTP_res_nrg = Inlines.silk_max(LPC_LTP_res_nrg, 1); /* avoid division by zero */
|
||||
|
||||
div_Q16 = Inlines.silk_DIV32_varQ(LPC_res_nrg, LPC_LTP_res_nrg, 16);
|
||||
LTPredCodGain_Q7.Val = (int)Inlines.silk_SMULBB(3, Inlines.silk_lin2log(div_Q16) - (16 << 7));
|
||||
|
||||
Inlines.OpusAssert(LTPredCodGain_Q7.Val == (int)Inlines.silk_SAT16(Inlines.silk_MUL(3, Inlines.silk_lin2log(div_Q16) - (16 << 7))));
|
||||
}
|
||||
|
||||
/* smoothing */
|
||||
/* d = sum( B, 1 ); */
|
||||
b_Q14_ptr = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
d_Q14[k] = 0;
|
||||
for (i = b_Q14_ptr; i < b_Q14_ptr + SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
d_Q14[k] += b_Q14[i];
|
||||
}
|
||||
b_Q14_ptr += SilkConstants.LTP_ORDER;
|
||||
}
|
||||
|
||||
/* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
|
||||
|
||||
/* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */
|
||||
max_abs_d_Q14 = 0;
|
||||
max_w_bits = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
max_abs_d_Q14 = Inlines.silk_max_32(max_abs_d_Q14, Inlines.silk_abs(d_Q14[k]));
|
||||
/* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */
|
||||
/* Find bits needed in Q( 18 - maxRshifts ) */
|
||||
max_w_bits = Inlines.silk_max_32(max_w_bits, 32 - Inlines.silk_CLZ32(w[k]) + corr_rshifts[k] - maxRshifts);
|
||||
}
|
||||
|
||||
/* max_abs_d_Q14 = (5 << 15); worst case, i.e. SilkConstants.LTP_ORDER * -silk_int16_MIN */
|
||||
Inlines.OpusAssert(max_abs_d_Q14 <= (5 << 15));
|
||||
|
||||
/* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */
|
||||
extra_shifts = max_w_bits + 32 - Inlines.silk_CLZ32(max_abs_d_Q14) - 14;
|
||||
|
||||
/* Subtract what we got available; bits in output var plus maxRshifts */
|
||||
extra_shifts -= (32 - 1 - 2 + maxRshifts); /* Keep sign bit free as well as 2 bits for accumulation */
|
||||
extra_shifts = Inlines.silk_max_int(extra_shifts, 0);
|
||||
|
||||
maxRshifts_wxtra = maxRshifts + extra_shifts;
|
||||
|
||||
temp32 = Inlines.silk_RSHIFT(262, maxRshifts + extra_shifts) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */
|
||||
wd = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
/* w has at least 2 bits of headroom so no overflow should happen */
|
||||
temp32 = Inlines.silk_ADD32(temp32, Inlines.silk_RSHIFT(w[k], maxRshifts_wxtra - corr_rshifts[k])); /* Q( 18 - maxRshifts_wxtra ) */
|
||||
wd = Inlines.silk_ADD32(wd, Inlines.silk_LSHIFT(Inlines.silk_SMULWW(Inlines.silk_RSHIFT(w[k], maxRshifts_wxtra - corr_rshifts[k]), d_Q14[k]), 2)); /* Q( 18 - maxRshifts_wxtra ) */
|
||||
}
|
||||
m_Q12 = Inlines.silk_DIV32_varQ(wd, temp32, 12);
|
||||
|
||||
b_Q14_ptr = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
/* w[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */
|
||||
if (2 - corr_rshifts[k] > 0)
|
||||
{
|
||||
temp32 = Inlines.silk_RSHIFT(w[k], 2 - corr_rshifts[k]);
|
||||
}
|
||||
else {
|
||||
temp32 = Inlines.silk_LSHIFT_SAT32(w[k], corr_rshifts[k] - 2);
|
||||
}
|
||||
|
||||
g_Q26 = Inlines.silk_MUL(
|
||||
Inlines.silk_DIV32(
|
||||
((int)((TuningParameters.LTP_SMOOTHING) * ((long)1 << (26)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_SMOOTHING, 26)*/,
|
||||
Inlines.silk_RSHIFT(((int)((TuningParameters.LTP_SMOOTHING) * ((long)1 << (26)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.LTP_SMOOTHING, 26)*/, 10) + temp32), /* Q10 */
|
||||
Inlines.silk_LSHIFT_SAT32(Inlines.silk_SUB_SAT32((int)m_Q12, Inlines.silk_RSHIFT(d_Q14[k], 2)), 4)); /* Q16 */
|
||||
|
||||
temp32 = 0;
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
delta_b_Q14[i] = Inlines.silk_max_16(b_Q14[b_Q14_ptr + i], 1638); /* 1638_Q14 = 0.1_Q0 */
|
||||
temp32 += delta_b_Q14[i]; /* Q14 */
|
||||
}
|
||||
temp32 = Inlines.silk_DIV32(g_Q26, temp32); /* Q14 . Q12 */
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
b_Q14[b_Q14_ptr + i] = (short)(Inlines.silk_LIMIT_32((int)b_Q14[b_Q14_ptr + i] + Inlines.silk_SMULWB(Inlines.silk_LSHIFT_SAT32(temp32, 4), delta_b_Q14[i]), -16000, 28000));
|
||||
}
|
||||
b_Q14_ptr += SilkConstants.LTP_ORDER;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="LTP_coefs_Q16">[SilkConstants.LTP_ORDER]</param>
|
||||
/// <param name="LTP_coefs_Q14">[SilkConstants.LTP_ORDER]</param>
|
||||
/// <param name="LTP_coefs_Q14_ptr"></param>
|
||||
internal static void silk_fit_LTP(
|
||||
int[] LTP_coefs_Q16,
|
||||
short[] LTP_coefs_Q14,
|
||||
int LTP_coefs_Q14_ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SilkConstants.LTP_ORDER; i++)
|
||||
{
|
||||
LTP_coefs_Q14[LTP_coefs_Q14_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(LTP_coefs_Q16[i], 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
Libraries/Concentus/CSharp/Concentus/Silk/FindPitchLags.cs
Normal file
167
Libraries/Concentus/CSharp/Concentus/Silk/FindPitchLags.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindPitchLags
|
||||
{
|
||||
/* Find pitch lags */
|
||||
internal static void silk_find_pitch_lags(
|
||||
SilkChannelEncoder psEnc, /* I/O encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I/O encoder control */
|
||||
short[] res, /* O residual */
|
||||
short[] x, /* I Speech signal */
|
||||
int x_ptr
|
||||
)
|
||||
{
|
||||
int buf_len, i, scale;
|
||||
int thrhld_Q13, res_nrg;
|
||||
int x_buf, x_buf_ptr;
|
||||
short[] Wsig;
|
||||
int Wsig_ptr;
|
||||
int[] auto_corr = new int[SilkConstants.MAX_FIND_PITCH_LPC_ORDER + 1];
|
||||
short[] rc_Q15 = new short[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
|
||||
int[] A_Q24 = new int[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
|
||||
short[] A_Q12 = new short[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* Set up buffer lengths etc based on Fs */
|
||||
/******************************************/
|
||||
buf_len = psEnc.la_pitch + psEnc.frame_length + psEnc.ltp_mem_length;
|
||||
|
||||
/* Safety check */
|
||||
Inlines.OpusAssert(buf_len >= psEnc.pitch_LPC_win_length);
|
||||
|
||||
x_buf = x_ptr - psEnc.ltp_mem_length;
|
||||
|
||||
/*************************************/
|
||||
/* Estimate LPC AR coefficients */
|
||||
/*************************************/
|
||||
|
||||
/* Calculate windowed signal */
|
||||
|
||||
Wsig = new short[psEnc.pitch_LPC_win_length];
|
||||
|
||||
/* First LA_LTP samples */
|
||||
x_buf_ptr = x_buf + buf_len - psEnc.pitch_LPC_win_length;
|
||||
Wsig_ptr = 0;
|
||||
ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr, x, x_buf_ptr, 1, psEnc.la_pitch);
|
||||
|
||||
/* Middle un - windowed samples */
|
||||
Wsig_ptr += psEnc.la_pitch;
|
||||
x_buf_ptr += psEnc.la_pitch;
|
||||
Array.Copy(x, x_buf_ptr, Wsig, Wsig_ptr, (psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1)));
|
||||
|
||||
/* Last LA_LTP samples */
|
||||
Wsig_ptr += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1);
|
||||
x_buf_ptr += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1);
|
||||
ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr, x, x_buf_ptr, 2, psEnc.la_pitch);
|
||||
|
||||
/* Calculate autocorrelation sequence */
|
||||
BoxedValueInt boxed_scale = new BoxedValueInt();
|
||||
Autocorrelation.silk_autocorr(auto_corr, boxed_scale, Wsig, psEnc.pitch_LPC_win_length, psEnc.pitchEstimationLPCOrder + 1);
|
||||
scale = boxed_scale.Val;
|
||||
|
||||
/* Add white noise, as fraction of energy */
|
||||
auto_corr[0] = Inlines.silk_SMLAWB(auto_corr[0], auto_corr[0], ((int)((TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION, 16)*/) + 1;
|
||||
|
||||
/* Calculate the reflection coefficients using schur */
|
||||
res_nrg = Schur.silk_schur(rc_Q15, auto_corr, psEnc.pitchEstimationLPCOrder);
|
||||
|
||||
/* Prediction gain */
|
||||
psEncCtrl.predGain_Q16 = Inlines.silk_DIV32_varQ(auto_corr[0], Inlines.silk_max_int(res_nrg, 1), 16);
|
||||
|
||||
/* Convert reflection coefficients to prediction coefficients */
|
||||
K2A.silk_k2a(A_Q24, rc_Q15, psEnc.pitchEstimationLPCOrder);
|
||||
|
||||
/* Convert From 32 bit Q24 to 16 bit Q12 coefs */
|
||||
for (i = 0; i < psEnc.pitchEstimationLPCOrder; i++)
|
||||
{
|
||||
A_Q12[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(A_Q24[i], 12));
|
||||
}
|
||||
|
||||
/* Do BWE */
|
||||
BWExpander.silk_bwexpander(A_Q12, psEnc.pitchEstimationLPCOrder, ((int)((TuningParameters.FIND_PITCH_BANDWIDTH_EXPANSION) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_BANDWIDTH_EXPANSION, 16)*/);
|
||||
|
||||
/*****************************************/
|
||||
/* LPC analysis filtering */
|
||||
/*****************************************/
|
||||
Filters.silk_LPC_analysis_filter(res, 0, x, x_buf, A_Q12, 0, buf_len, psEnc.pitchEstimationLPCOrder);
|
||||
|
||||
if (psEnc.indices.signalType != SilkConstants.TYPE_NO_VOICE_ACTIVITY && psEnc.first_frame_after_reset == 0)
|
||||
{
|
||||
/* Threshold for pitch estimator */
|
||||
thrhld_Q13 = ((int)((0.6f) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(0.6f, 13)*/;
|
||||
thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, ((int)((-0.004f) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(-0.004f, 13)*/, psEnc.pitchEstimationLPCOrder);
|
||||
thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, ((int)((-0.1f) * ((long)1 << (21)) + 0.5))/*Inlines.SILK_CONST(-0.1f, 21)*/, psEnc.speech_activity_Q8);
|
||||
thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, ((int)((-0.15f) * ((long)1 << (13)) + 0.5))/*Inlines.SILK_CONST(-0.15f, 13)*/, Inlines.silk_RSHIFT(psEnc.prevSignalType, 1));
|
||||
thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, ((int)((-0.1f) * ((long)1 << (14)) + 0.5))/*Inlines.SILK_CONST(-0.1f, 14)*/, psEnc.input_tilt_Q15);
|
||||
thrhld_Q13 = Inlines.silk_SAT16(thrhld_Q13);
|
||||
|
||||
/*****************************************/
|
||||
/* Call pitch estimator */
|
||||
/*****************************************/
|
||||
BoxedValueShort boxed_lagIndex = new BoxedValueShort(psEnc.indices.lagIndex);
|
||||
BoxedValueSbyte boxed_contourIndex = new BoxedValueSbyte(psEnc.indices.contourIndex);
|
||||
BoxedValueInt boxed_LTPcorr = new BoxedValueInt(psEnc.LTPCorr_Q15);
|
||||
if (PitchAnalysisCore.silk_pitch_analysis_core(res, psEncCtrl.pitchL, boxed_lagIndex, boxed_contourIndex,
|
||||
boxed_LTPcorr, psEnc.prevLag, psEnc.pitchEstimationThreshold_Q16,
|
||||
(int)thrhld_Q13, psEnc.fs_kHz, psEnc.pitchEstimationComplexity, psEnc.nb_subfr) == 0)
|
||||
{
|
||||
psEnc.indices.signalType = SilkConstants.TYPE_VOICED;
|
||||
}
|
||||
else {
|
||||
psEnc.indices.signalType = SilkConstants.TYPE_UNVOICED;
|
||||
}
|
||||
|
||||
psEnc.indices.lagIndex = boxed_lagIndex.Val;
|
||||
psEnc.indices.contourIndex = boxed_contourIndex.Val;
|
||||
psEnc.LTPCorr_Q15 = boxed_LTPcorr.Val;
|
||||
}
|
||||
else {
|
||||
Arrays.MemSetInt(psEncCtrl.pitchL, 0, SilkConstants.MAX_NB_SUBFR);
|
||||
psEnc.indices.lagIndex = 0;
|
||||
psEnc.indices.contourIndex = 0;
|
||||
psEnc.LTPCorr_Q15 = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
171
Libraries/Concentus/CSharp/Concentus/Silk/FindPredCoefs.cs
Normal file
171
Libraries/Concentus/CSharp/Concentus/Silk/FindPredCoefs.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class FindPredCoefs
|
||||
{
|
||||
internal static void silk_find_pred_coefs(
|
||||
SilkChannelEncoder psEnc, /* I/O encoder state */
|
||||
SilkEncoderControl psEncCtrl, /* I/O encoder control */
|
||||
short[] res_pitch, /* I Residual from pitch analysis */
|
||||
short[] x, /* I Speech signal */
|
||||
int x_ptr,
|
||||
int condCoding /* I The type of conditional coding to use */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int[] invGains_Q16 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int[] local_gains = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
int[] Wght_Q15 = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
short[] NLSF_Q15 = new short[SilkConstants.MAX_LPC_ORDER];
|
||||
int x_ptr2;
|
||||
int x_pre_ptr;
|
||||
short[] LPC_in_pre;
|
||||
int tmp, min_gain_Q16, minInvGain_Q30;
|
||||
int[] LTP_corrs_rshift = new int[SilkConstants.MAX_NB_SUBFR];
|
||||
|
||||
/* weighting for weighted least squares */
|
||||
min_gain_Q16 = int.MaxValue >> 6;
|
||||
for (i = 0; i < psEnc.nb_subfr; i++)
|
||||
{
|
||||
min_gain_Q16 = Inlines.silk_min(min_gain_Q16, psEncCtrl.Gains_Q16[i]);
|
||||
}
|
||||
for (i = 0; i < psEnc.nb_subfr; i++)
|
||||
{
|
||||
/* Divide to Q16 */
|
||||
Inlines.OpusAssert(psEncCtrl.Gains_Q16[i] > 0);
|
||||
/* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */
|
||||
invGains_Q16[i] = Inlines.silk_DIV32_varQ(min_gain_Q16, psEncCtrl.Gains_Q16[i], 16 - 2);
|
||||
|
||||
/* Ensure Wght_Q15 a minimum value 1 */
|
||||
invGains_Q16[i] = Inlines.silk_max(invGains_Q16[i], 363);
|
||||
|
||||
/* Square the inverted gains */
|
||||
Inlines.OpusAssert(invGains_Q16[i] == Inlines.silk_SAT16(invGains_Q16[i]));
|
||||
tmp = Inlines.silk_SMULWB(invGains_Q16[i], invGains_Q16[i]);
|
||||
Wght_Q15[i] = Inlines.silk_RSHIFT(tmp, 1);
|
||||
|
||||
/* Invert the inverted and normalized gains */
|
||||
local_gains[i] = Inlines.silk_DIV32(((int)1 << 16), invGains_Q16[i]);
|
||||
}
|
||||
|
||||
LPC_in_pre = new short[psEnc.nb_subfr * psEnc.predictLPCOrder + psEnc.frame_length];
|
||||
if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
int[] WLTP;
|
||||
|
||||
/**********/
|
||||
/* VOICED */
|
||||
/**********/
|
||||
Inlines.OpusAssert(psEnc.ltp_mem_length - psEnc.predictLPCOrder >= psEncCtrl.pitchL[0] + SilkConstants.LTP_ORDER / 2);
|
||||
|
||||
WLTP = new int[psEnc.nb_subfr * SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER];
|
||||
|
||||
/* LTP analysis */
|
||||
BoxedValueInt boxed_codgain = new BoxedValueInt(psEncCtrl.LTPredCodGain_Q7);
|
||||
FindLTP.silk_find_LTP(psEncCtrl.LTPCoef_Q14, WLTP, boxed_codgain,
|
||||
res_pitch, psEncCtrl.pitchL, Wght_Q15, psEnc.subfr_length,
|
||||
psEnc.nb_subfr, psEnc.ltp_mem_length, LTP_corrs_rshift);
|
||||
psEncCtrl.LTPredCodGain_Q7 = boxed_codgain.Val;
|
||||
|
||||
/* Quantize LTP gain parameters */
|
||||
BoxedValueSbyte boxed_periodicity = new BoxedValueSbyte(psEnc.indices.PERIndex);
|
||||
BoxedValueInt boxed_gain = new BoxedValueInt(psEnc.sum_log_gain_Q7);
|
||||
QuantizeLTPGains.silk_quant_LTP_gains(psEncCtrl.LTPCoef_Q14, psEnc.indices.LTPIndex, boxed_periodicity,
|
||||
boxed_gain, WLTP, psEnc.mu_LTP_Q9, psEnc.LTPQuantLowComplexity, psEnc.nb_subfr
|
||||
);
|
||||
psEnc.indices.PERIndex = boxed_periodicity.Val;
|
||||
psEnc.sum_log_gain_Q7 = boxed_gain.Val;
|
||||
|
||||
/* Control LTP scaling */
|
||||
LTPScaleControl.silk_LTP_scale_ctrl(psEnc, psEncCtrl, condCoding);
|
||||
|
||||
/* Create LTP residual */
|
||||
LTPAnalysisFilter.silk_LTP_analysis_filter(LPC_in_pre, x, x_ptr - psEnc.predictLPCOrder, psEncCtrl.LTPCoef_Q14,
|
||||
psEncCtrl.pitchL, invGains_Q16, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder);
|
||||
|
||||
}
|
||||
else {
|
||||
/************/
|
||||
/* UNVOICED */
|
||||
/************/
|
||||
/* Create signal with prepended subframes, scaled by inverse gains */
|
||||
x_ptr2 = x_ptr - psEnc.predictLPCOrder;
|
||||
x_pre_ptr = 0;
|
||||
for (i = 0; i < psEnc.nb_subfr; i++)
|
||||
{
|
||||
Inlines.silk_scale_copy_vector16(LPC_in_pre, x_pre_ptr, x, x_ptr2, invGains_Q16[i],
|
||||
psEnc.subfr_length + psEnc.predictLPCOrder);
|
||||
x_pre_ptr += psEnc.subfr_length + psEnc.predictLPCOrder;
|
||||
x_ptr2 += psEnc.subfr_length;
|
||||
}
|
||||
|
||||
Arrays.MemSetShort(psEncCtrl.LTPCoef_Q14, 0, psEnc.nb_subfr * SilkConstants.LTP_ORDER);
|
||||
psEncCtrl.LTPredCodGain_Q7 = 0;
|
||||
psEnc.sum_log_gain_Q7 = 0;
|
||||
}
|
||||
|
||||
/* Limit on total predictive coding gain */
|
||||
if (psEnc.first_frame_after_reset != 0)
|
||||
{
|
||||
minInvGain_Q30 = ((int)((1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN_AFTER_RESET) * ((long)1 << (30)) + 0.5))/*Inlines.SILK_CONST(1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30)*/;
|
||||
}
|
||||
else {
|
||||
minInvGain_Q30 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(16 << 7, (int)psEncCtrl.LTPredCodGain_Q7, ((int)((1.0f / 3f) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(1.0f / 3f, 16)*/)); /* Q16 */
|
||||
minInvGain_Q30 = Inlines.silk_DIV32_varQ(minInvGain_Q30,
|
||||
Inlines.silk_SMULWW(((int)((SilkConstants.MAX_PREDICTION_POWER_GAIN) * ((long)1 << (0)) + 0.5))/*Inlines.SILK_CONST(SilkConstants.MAX_PREDICTION_POWER_GAIN, 0)*/,
|
||||
Inlines.silk_SMLAWB(((int)((0.25f) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(0.25f, 18)*/, ((int)((0.75f) * ((long)1 << (18)) + 0.5))/*Inlines.SILK_CONST(0.75f, 18)*/, psEncCtrl.coding_quality_Q14)), 14);
|
||||
}
|
||||
|
||||
/* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
|
||||
FindLPC.silk_find_LPC(psEnc, NLSF_Q15, LPC_in_pre, minInvGain_Q30);
|
||||
|
||||
/* Quantize LSFs */
|
||||
NLSF.silk_process_NLSFs(psEnc, psEncCtrl.PredCoef_Q12, NLSF_Q15, psEnc.prev_NLSFq_Q15);
|
||||
|
||||
/* Calculate residual energy using quantized LPC coefficients */
|
||||
ResidualEnergy.silk_residual_energy(psEncCtrl.ResNrg, psEncCtrl.ResNrgQ, LPC_in_pre, psEncCtrl.PredCoef_Q12, local_gains,
|
||||
psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder);
|
||||
|
||||
/* Copy to prediction struct for use in next frame for interpolation */
|
||||
Array.Copy(NLSF_Q15, psEnc.prev_NLSFq_Q15, SilkConstants.MAX_LPC_ORDER);
|
||||
}
|
||||
}
|
||||
}
|
||||
187
Libraries/Concentus/CSharp/Concentus/Silk/GainQuantization.cs
Normal file
187
Libraries/Concentus/CSharp/Concentus/Silk/GainQuantization.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class GainQuantization
|
||||
{
|
||||
private static readonly int OFFSET = ((SilkConstants.MIN_QGAIN_DB * 128) / 6 + 16 * 128);
|
||||
private static readonly int SCALE_Q16 = ((65536 * (SilkConstants.N_LEVELS_QGAIN - 1)) / (((SilkConstants.MAX_QGAIN_DB - SilkConstants.MIN_QGAIN_DB) * 128) / 6));
|
||||
private static readonly int INV_SCALE_Q16 = ((65536 * (((SilkConstants.MAX_QGAIN_DB - SilkConstants.MIN_QGAIN_DB) * 128) / 6)) / (SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
|
||||
/// <summary>
|
||||
/// Gain scalar quantization with hysteresis, uniform on log scale
|
||||
/// </summary>
|
||||
/// <param name="ind">O gain indices [MAX_NB_SUBFR]</param>
|
||||
/// <param name="gain_Q16">I/O gains (quantized out) [MAX_NB_SUBFR]</param>
|
||||
/// <param name="prev_ind">I/O last index in previous frame. [Porting note] original implementation passed this as an int8*</param>
|
||||
/// <param name="conditional">I first gain is delta coded if 1</param>
|
||||
/// <param name="nb_subfr">I number of subframes</param>
|
||||
internal static void silk_gains_quant(
|
||||
sbyte[] ind,
|
||||
int[] gain_Q16,
|
||||
BoxedValueSbyte prev_ind,
|
||||
int conditional,
|
||||
int nb_subfr)
|
||||
{
|
||||
int k, double_step_size_threshold;
|
||||
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
// Debug.WriteLine("2a 0x{0:x}", (uint)gain_Q16[k]);
|
||||
/* Convert to log scale, scale, floor() */
|
||||
ind[k] = (sbyte)(Inlines.silk_SMULWB(SCALE_Q16, Inlines.silk_lin2log(gain_Q16[k]) - OFFSET));
|
||||
|
||||
/* Round towards previous quantized gain (hysteresis) */
|
||||
if (ind[k] < prev_ind.Val)
|
||||
{
|
||||
ind[k]++;
|
||||
}
|
||||
|
||||
ind[k] = (sbyte)(Inlines.silk_LIMIT_int(ind[k], 0, SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
|
||||
/* Compute delta indices and limit */
|
||||
if (k == 0 && conditional == 0)
|
||||
{
|
||||
/* Full index */
|
||||
ind[k] = (sbyte)(Inlines.silk_LIMIT_int(ind[k], prev_ind.Val + SilkConstants.MIN_DELTA_GAIN_QUANT, SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
prev_ind.Val = ind[k];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delta index */
|
||||
ind[k] = (sbyte)(ind[k] - prev_ind.Val);
|
||||
|
||||
/* Double the quantization step size for large gain increases, so that the max gain level can be reached */
|
||||
double_step_size_threshold = 2 * SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.N_LEVELS_QGAIN + prev_ind.Val;
|
||||
if (ind[k] > double_step_size_threshold)
|
||||
{
|
||||
ind[k] = (sbyte)(double_step_size_threshold + Inlines.silk_RSHIFT(ind[k] - double_step_size_threshold + 1, 1));
|
||||
}
|
||||
|
||||
ind[k] = (sbyte)(Inlines.silk_LIMIT_int(ind[k], SilkConstants.MIN_DELTA_GAIN_QUANT, SilkConstants.MAX_DELTA_GAIN_QUANT));
|
||||
|
||||
/* Accumulate deltas */
|
||||
if (ind[k] > double_step_size_threshold)
|
||||
{
|
||||
prev_ind.Val += (sbyte)(Inlines.silk_LSHIFT(ind[k], 1) - double_step_size_threshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_ind.Val += ind[k];
|
||||
}
|
||||
|
||||
/* Shift to make non-negative */
|
||||
ind[k] -= SilkConstants.MIN_DELTA_GAIN_QUANT;
|
||||
// Debug.WriteLine("2b 0x{0:x}", (uint)ind[k]);
|
||||
}
|
||||
|
||||
/* Scale and convert to linear scale */
|
||||
gain_Q16[k] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(INV_SCALE_Q16, prev_ind.Val) + OFFSET, 3967)); /* 3967 = 31 in Q7 */
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gains scalar dequantization, uniform on log scale
|
||||
/// </summary>
|
||||
/// <param name="gain_Q16">O quantized gains [MAX_NB_SUBFR]</param>
|
||||
/// <param name="ind">I gain indices [MAX_NB_SUBFR]</param>
|
||||
/// <param name="prev_ind">I/O last index in previous frame [Porting note] original implementation passed this as an int8*</param>
|
||||
/// <param name="conditional">I first gain is delta coded if 1</param>
|
||||
/// <param name="nb_subfr">I number of subframes</param>
|
||||
internal static void silk_gains_dequant(
|
||||
int[] gain_Q16,
|
||||
sbyte[] ind,
|
||||
BoxedValueSbyte prev_ind,
|
||||
int conditional,
|
||||
int nb_subfr)
|
||||
{
|
||||
int k, ind_tmp, double_step_size_threshold;
|
||||
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
if (k == 0 && conditional == 0)
|
||||
{
|
||||
/* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */
|
||||
prev_ind.Val = (sbyte)(Inlines.silk_max_int(ind[k], prev_ind.Val - 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delta index */
|
||||
ind_tmp = ind[k] + SilkConstants.MIN_DELTA_GAIN_QUANT;
|
||||
|
||||
/* Accumulate deltas */
|
||||
double_step_size_threshold = 2 * SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.N_LEVELS_QGAIN + prev_ind.Val;
|
||||
if (ind_tmp > double_step_size_threshold)
|
||||
{
|
||||
prev_ind.Val += (sbyte)(Inlines.silk_LSHIFT(ind_tmp, 1) - double_step_size_threshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_ind.Val += (sbyte)(ind_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
prev_ind.Val = (sbyte)(Inlines.silk_LIMIT_int(prev_ind.Val, 0, SilkConstants.N_LEVELS_QGAIN - 1));
|
||||
|
||||
/* Scale and convert to linear scale */
|
||||
gain_Q16[k] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(INV_SCALE_Q16, prev_ind.Val) + OFFSET, 3967)); /* 3967 = 31 in Q7 */
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute unique identifier of gain indices vector
|
||||
/// </summary>
|
||||
/// <param name="ind">I gain indices [MAX_NB_SUBFR]</param>
|
||||
/// <param name="nb_subfr">I number of subframes</param>
|
||||
/// <returns>unique identifier of gains</returns>
|
||||
internal static int silk_gains_ID(sbyte[] ind, int nb_subfr)
|
||||
{
|
||||
int k;
|
||||
int gainsID;
|
||||
|
||||
gainsID = 0;
|
||||
for (k = 0; k < nb_subfr; k++)
|
||||
{
|
||||
gainsID = Inlines.silk_ADD_LSHIFT32(ind[k], gainsID, 8);
|
||||
}
|
||||
|
||||
return gainsID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2006-2011 Skype Limited. All Rights Reserved
|
||||
Ported to C# by Logan Stromberg
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace Concentus.Silk
|
||||
{
|
||||
using Concentus.Common;
|
||||
using Concentus.Common.CPlusPlus;
|
||||
using Concentus.Silk.Enums;
|
||||
using Concentus.Silk.Structs;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class HPVariableCutoff
|
||||
{
|
||||
/// <summary>
|
||||
/// High-pass filter with cutoff frequency adaptation based on pitch lag statistics
|
||||
/// </summary>
|
||||
/// <param name="state_Fxx">I/O Encoder states</param>
|
||||
internal static void silk_HP_variable_cutoff(SilkChannelEncoder[] state_Fxx)
|
||||
{
|
||||
int quality_Q15;
|
||||
int pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7;
|
||||
SilkChannelEncoder psEncC1 = state_Fxx[0];
|
||||
|
||||
/* Adaptive cutoff frequency: estimate low end of pitch frequency range */
|
||||
if (psEncC1.prevSignalType == SilkConstants.TYPE_VOICED)
|
||||
{
|
||||
/* difference, in log domain */
|
||||
pitch_freq_Hz_Q16 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(Inlines.silk_MUL(psEncC1.fs_kHz, 1000), 16), psEncC1.prevLag);
|
||||
pitch_freq_log_Q7 = Inlines.silk_lin2log(pitch_freq_Hz_Q16) - (16 << 7);
|
||||
|
||||
/* adjustment based on quality */
|
||||
quality_Q15 = psEncC1.input_quality_bands_Q15[0];
|
||||
pitch_freq_log_Q7 = Inlines.silk_SMLAWB(pitch_freq_log_Q7, Inlines.silk_SMULWB(Inlines.silk_LSHIFT(-quality_Q15, 2), quality_Q15),
|
||||
pitch_freq_log_Q7 - (Inlines.silk_lin2log(((int)((TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ, 16)*/) - (16 << 7)));
|
||||
|
||||
/* delta_freq = pitch_freq_log - psEnc.variable_HP_smth1; */
|
||||
delta_freq_Q7 = pitch_freq_log_Q7 - Inlines.silk_RSHIFT(psEncC1.variable_HP_smth1_Q15, 8);
|
||||
if (delta_freq_Q7 < 0)
|
||||
{
|
||||
/* less smoothing for decreasing pitch frequency, to track something close to the minimum */
|
||||
delta_freq_Q7 = Inlines.silk_MUL(delta_freq_Q7, 3);
|
||||
}
|
||||
|
||||
/* limit delta, to reduce impact of outliers in pitch estimation */
|
||||
delta_freq_Q7 = Inlines.silk_LIMIT_32(
|
||||
delta_freq_Q7,
|
||||
0 - ((int)((TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ, 7)*/,
|
||||
((int)((TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ) * ((long)1 << (7)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_MAX_DELTA_FREQ, 7)*/);
|
||||
|
||||
/* update smoother */
|
||||
psEncC1.variable_HP_smth1_Q15 = Inlines.silk_SMLAWB(psEncC1.variable_HP_smth1_Q15,
|
||||
Inlines.silk_SMULBB(psEncC1.speech_activity_Q8, delta_freq_Q7), ((int)((TuningParameters.VARIABLE_HP_SMTH_COEF1) * ((long)1 << (16)) + 0.5))/*Inlines.SILK_CONST(TuningParameters.VARIABLE_HP_SMTH_COEF1, 16)*/);
|
||||
|
||||
/* limit frequency range */
|
||||
psEncC1.variable_HP_smth1_Q15 = Inlines.silk_LIMIT_32(psEncC1.variable_HP_smth1_Q15,
|
||||
Inlines.silk_LSHIFT(Inlines.silk_lin2log(TuningParameters.VARIABLE_HP_MIN_CUTOFF_HZ), 8),
|
||||
Inlines.silk_LSHIFT(Inlines.silk_lin2log(TuningParameters.VARIABLE_HP_MAX_CUTOFF_HZ), 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user