mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
feat(dmr): decode and route AMBE voice
This commit is contained in:
@@ -27,8 +27,11 @@ const
|
||||
DMR_RING_SIZE = 65536; // >1.3 s at 48 kHz, power of two
|
||||
DMR_BURST_DIBITS = 144;
|
||||
DMR_SYNC_END_DIBIT = 89; // sync occupies burst dibits 66..89
|
||||
DMR_VOICE_FRAME_SAMPLES = DMR_PCM_SAMPLES; // 20 ms at 8 kHz
|
||||
|
||||
type
|
||||
TDMRAudioEvent = procedure(const PCM: array of Single; Count: Integer) of object;
|
||||
|
||||
TDMRSyncKind = (
|
||||
dskNone,
|
||||
dskBSData, dskBSVoice,
|
||||
@@ -62,6 +65,9 @@ type
|
||||
ServiceOptions: Integer;
|
||||
TargetID: LongWord;
|
||||
SourceID: LongWord;
|
||||
SelectedSlot: Integer;
|
||||
VoiceFrameCount: QWord;
|
||||
VoiceErrorCount: QWord;
|
||||
end;
|
||||
|
||||
TDMRDecoder = class;
|
||||
@@ -111,6 +117,9 @@ type
|
||||
FLastLCSlot: Integer;
|
||||
FColorCodeValid: Boolean;
|
||||
FColorCode, FLastDataType, FSlotTypeCorrectedBits: Integer;
|
||||
FSelectedSlot: Integer;
|
||||
FVoiceFrameCount, FVoiceErrorCount: QWord;
|
||||
FOnAudio: TDMRAudioEvent;
|
||||
FBurstCount: QWord;
|
||||
FRMSSq: Double;
|
||||
|
||||
@@ -127,6 +136,7 @@ type
|
||||
function Digitize(Phase: Integer; Symbol: Double): Byte;
|
||||
procedure StartBurstTracking(Phase: Integer);
|
||||
procedure CompleteBurst;
|
||||
procedure DecodeVoiceBurst;
|
||||
procedure ResetDSP;
|
||||
public
|
||||
constructor Create;
|
||||
@@ -140,6 +150,7 @@ type
|
||||
|
||||
class function SyncKindName(Kind: TDMRSyncKind): string; static;
|
||||
property Enabled: Boolean read FEnabled;
|
||||
property OnAudio: TDMRAudioEvent read FOnAudio write FOnAudio;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -275,6 +286,10 @@ begin
|
||||
FColorCode := 0;
|
||||
FLastDataType := 0;
|
||||
FSlotTypeCorrectedBits := 0;
|
||||
FSelectedSlot := -1;
|
||||
FVoiceFrameCount := 0;
|
||||
FVoiceErrorCount := 0;
|
||||
DMRMbeReset(FMbe);
|
||||
FTrackPhase := -1;
|
||||
FCurrentBurstPos := 0;
|
||||
FBurstCount := 0;
|
||||
@@ -480,11 +495,51 @@ begin
|
||||
FLastLCSlot := 1
|
||||
else
|
||||
FLastLCSlot := 0;
|
||||
if FSelectedSlot < 0 then FSelectedSlot := FLastLCSlot;
|
||||
end;
|
||||
DecodeVoiceBurst;
|
||||
Inc(FBurstCount);
|
||||
FCurrentBurstPos := 0;
|
||||
end;
|
||||
|
||||
procedure TDMRDecoder.DecodeVoiceBurst;
|
||||
var
|
||||
Frames: TDMRAMBEFrames;
|
||||
PCM: array[0..DMR_PCM_SAMPLES - 1] of Single;
|
||||
MbeResult: TDMRMbeResult;
|
||||
Slot, FrameIndex, RC: Integer;
|
||||
begin
|
||||
if (FMbe = nil) or (FLastSyncTick = 0) or
|
||||
(GetTickCount64 - FLastSyncTick > DMR_SYNC_HOLD_MS) then Exit;
|
||||
if not (FSyncKind in [dskBSVoice, dskMSVoice, dskDirectTS1Voice,
|
||||
dskDirectTS2Voice]) then Exit;
|
||||
|
||||
if FSyncKind in [dskBSVoice] then
|
||||
begin
|
||||
if not FLastBurstInfo.CACH.Valid then Exit;
|
||||
Slot := FLastBurstInfo.CACH.Slot;
|
||||
end
|
||||
else if FSyncKind = dskDirectTS2Voice then Slot := 1
|
||||
else Slot := 0;
|
||||
if FSelectedSlot < 0 then FSelectedSlot := Slot;
|
||||
if Slot <> FSelectedSlot then Exit;
|
||||
|
||||
DMRExtractAMBEFrames(FLastBurst, Frames);
|
||||
for FrameIndex := 0 to 2 do
|
||||
begin
|
||||
FillChar(MbeResult, SizeOf(MbeResult), 0);
|
||||
RC := DMRMbeDecode(FMbe, @Frames[FrameIndex][0], @PCM[0], @MbeResult);
|
||||
if RC <> 0 then
|
||||
begin
|
||||
Inc(FVoiceErrorCount);
|
||||
Continue;
|
||||
end;
|
||||
Inc(FVoiceFrameCount);
|
||||
if MbeResult.ErrorsTotal > 0 then Inc(FVoiceErrorCount, MbeResult.ErrorsTotal);
|
||||
if Assigned(FOnAudio) then FOnAudio(PCM, Length(PCM));
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDMRDecoder.NoteSync(Phase: Integer; Kind: TDMRSyncKind;
|
||||
Inverted: Boolean);
|
||||
var
|
||||
@@ -559,6 +614,9 @@ begin
|
||||
S.ServiceOptions := FLastLinkControl.ServiceOptions;
|
||||
S.TargetID := FLastLinkControl.TargetID;
|
||||
S.SourceID := FLastLinkControl.SourceID;
|
||||
S.SelectedSlot := FSelectedSlot;
|
||||
S.VoiceFrameCount := FVoiceFrameCount;
|
||||
S.VoiceErrorCount := FVoiceErrorCount;
|
||||
finally
|
||||
FStatusLock.Leave;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user