mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:27:33 +00:00
feat(dmr): decode and route AMBE voice
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user