feat(dmr): decode and route AMBE voice

This commit is contained in:
2026-07-14 18:55:28 +03:00
parent e0e74b5337
commit 28c434d9a7
7 changed files with 231 additions and 10 deletions
+27
View File
@@ -9,6 +9,20 @@ uses
const
BS_VOICE_SYNC = '131111333113313313113313';
type
TAudioSink = class
public
CallCount: Integer;
SampleCount: Integer;
procedure AudioReady(const PCM: array of Single; Count: Integer);
end;
procedure TAudioSink.AudioReady(const PCM: array of Single; Count: Integer);
begin
Inc(CallCount);
Inc(SampleCount, Count);
end;
procedure FeedSync(D: TDMRDecoder; const Pattern: string; Invert: Boolean);
var
L, R: array of Single;
@@ -95,9 +109,12 @@ end;
var
D: TDMRDecoder;
S: TDMRStatus;
Sink: TAudioSink;
begin
Sink := TAudioSink.Create;
D := TDMRDecoder.Create;
try
D.OnAudio := Sink.AudioReady;
D.SetEnabled(True);
FeedSync(D, BS_VOICE_SYNC, False);
Sleep(50);
@@ -124,8 +141,18 @@ begin
D.SetInverted(False);
D.SetEnabled(True);
TestBurst(D);
D.GetStatus(S);
if S.VocoderAvailable and
((Sink.CallCount <> 3) or
(Sink.SampleCount <> 3 * DMR_VOICE_FRAME_SAMPLES)) then
begin
WriteLn('AMBE callback failed: calls=', Sink.CallCount,
' samples=', Sink.SampleCount);
Halt(5);
end;
WriteLn('DMR front-end sync tests passed');
finally
D.Free;
Sink.Free;
end;
end.
+18 -1
View File
@@ -76,6 +76,8 @@ var
Burst: TDMRDibitBurst;
Info: TDMRBurstInfo;
Payload: TDMRBit96;
Frames: TDMRAMBEFrames;
VoiceDibits: array[0..107] of Byte;
i: Integer;
begin
FillChar(Burst, SizeOf(Burst), 0);
@@ -155,5 +157,20 @@ begin
DMRParseBurst(Burst, Info);
Check(not Info.LinkControl.Decoded, 'invalid Full LC RS checksum accepted');
WriteLn('DMR CACH, Slot Type, BPTC and Full LC tests passed');
// Three AMBE frames occupy 36 + 18/18 + 36 dibits around the centre sync.
FillChar(Burst, SizeOf(Burst), 0);
for i := 12 to 65 do Burst[i] := (i * 3 + 1) and 3;
for i := 90 to 143 do Burst[i] := (i * 3 + 2) and 3;
for i := 0 to 53 do VoiceDibits[i] := Burst[12 + i];
for i := 0 to 53 do VoiceDibits[54 + i] := Burst[90 + i];
DMRExtractAMBEFrames(Burst, Frames);
for i := 12 to 65 do Burst[i] := 0;
for i := 90 to 143 do Burst[i] := 0;
DMRInsertAMBEFrames(Frames, Burst);
for i := 0 to 53 do Check(Burst[12 + i] = VoiceDibits[i],
'AMBE frame 1/2 interleave mismatch');
for i := 0 to 53 do Check(Burst[90 + i] = VoiceDibits[54 + i],
'AMBE frame 2/3 interleave mismatch');
WriteLn('DMR protocol, FEC, Full LC and AMBE extraction tests passed');
end.