diff --git a/AlertOverlay.pas b/AlertOverlay.pas index c9c274b..afcfe87 100644 --- a/AlertOverlay.pas +++ b/AlertOverlay.pas @@ -42,9 +42,15 @@ begin Inc(Row, RR.Left * 4); for X := RR.Left to RR.Right - 1 do begin +{$IFDEF DARWIN} + Row[1] := Byte((Alpha * R + InvA * Row[1]) div 255); + Row[2] := Byte((Alpha * G + InvA * Row[2]) div 255); + Row[3] := Byte((Alpha * B + InvA * Row[3]) div 255); +{$ELSE} Row[0] := Byte((Alpha * B + InvA * Row[0]) div 255); Row[1] := Byte((Alpha * G + InvA * Row[1]) div 255); Row[2] := Byte((Alpha * R + InvA * Row[2]) div 255); +{$ENDIF} Inc(Row, 4); end; end; diff --git a/AudioInput.pas b/AudioInput.pas index 6efc125..367c734 100644 --- a/AudioInput.pas +++ b/AudioInput.pas @@ -152,14 +152,22 @@ function PaInCallback(inputBuffer, outputBuffer: Pointer; implementation const -{$IFDEF UNIX} +{$IFDEF DARWIN} + PA_IN_LIBS: array[0..3] of AnsiString = ( + 'libportaudio.dylib', + 'libportaudio.2.dylib', + '/usr/local/lib/libportaudio.dylib', + '/opt/homebrew/lib/libportaudio.dylib' + ); +{$ELSE} + {$IFDEF UNIX} PA_IN_LIBS: array[0..3] of AnsiString = ( 'libportaudio.so.2', 'libportaudio.so', 'libportaudio.so.2.0.0', 'libportaudio.so.0' ); -{$ELSE} + {$ELSE} PA_IN_LIBS: array[0..5] of AnsiString = ( 'portaudio_x64.dll', 'portaudio_x86.dll', @@ -168,6 +176,7 @@ const 'libportaudio.dll', 'libportaudio64.dll' ); + {$ENDIF} {$ENDIF} PA_NO_ERROR = 0; PA_FLOAT32 = LongWord(1); @@ -276,7 +285,11 @@ begin {$IFDEF WINDOWS} FLastError := 'PortAudio DLL not found. Put portaudio_x64.dll, portaudio.dll, or libportaudio-2.dll next to ewsdr.exe'; {$ELSE} - FLastError := 'libportaudio not found'; + {$IFDEF DARWIN} + FLastError := 'libportaudio not found. Install via: brew install portaudio'; + {$ELSE} + FLastError := 'libportaudio not found. sudo apt install libportaudio2'; + {$ENDIF} {$ENDIF} Exit; end; diff --git a/AudioOutput.pas b/AudioOutput.pas index 6ba4aea..b6b9df2 100644 --- a/AudioOutput.pas +++ b/AudioOutput.pas @@ -163,14 +163,22 @@ function PaOutCallback(inputBuffer, outputBuffer: Pointer; implementation const -{$IFDEF UNIX} +{$IFDEF DARWIN} + PA_LIBS: array[0..3] of AnsiString = ( + 'libportaudio.dylib', + 'libportaudio.2.dylib', + '/usr/local/lib/libportaudio.dylib', + '/opt/homebrew/lib/libportaudio.dylib' + ); +{$ELSE} + {$IFDEF UNIX} PA_LIBS: array[0..3] of AnsiString = ( 'libportaudio.so.2', 'libportaudio.so', 'libportaudio.so.2.0.0', 'libportaudio.so.0' ); -{$ELSE} + {$ELSE} PA_LIBS: array[0..5] of AnsiString = ( 'portaudio_x64.dll', 'portaudio_x86.dll', @@ -179,6 +187,7 @@ const 'libportaudio.dll', 'libportaudio64.dll' ); + {$ENDIF} {$ENDIF} PA_NO_ERROR = 0; PA_FLOAT32 = LongWord(1); @@ -292,7 +301,11 @@ begin {$IFDEF WINDOWS} FLastError := 'PortAudio DLL not found. Put portaudio_x64.dll, portaudio.dll, or libportaudio-2.dll next to ewsdr.exe'; {$ELSE} + {$IFDEF DARWIN} + FLastError := 'libportaudio not found. Install via: brew install portaudio'; + {$ELSE} FLastError := 'libportaudio not found. sudo apt install libportaudio2'; + {$ENDIF} {$ENDIF} Exit; end; diff --git a/SampleRateOverlay.pas b/SampleRateOverlay.pas index 0e10095..73dfd7b 100644 --- a/SampleRateOverlay.pas +++ b/SampleRateOverlay.pas @@ -98,9 +98,15 @@ begin Inc(Row, RR.Left * 4); for X := RR.Left to RR.Right - 1 do begin +{$IFDEF DARWIN} + Row[1] := Byte((Alpha * R + InvA * Row[1]) div 255); + Row[2] := Byte((Alpha * G + InvA * Row[2]) div 255); + Row[3] := Byte((Alpha * B + InvA * Row[3]) div 255); +{$ELSE} Row[0] := Byte((Alpha * B + InvA * Row[0]) div 255); Row[1] := Byte((Alpha * G + InvA * Row[1]) div 255); Row[2] := Byte((Alpha * R + InvA * Row[2]) div 255); +{$ENDIF} Inc(Row, 4); end; end; diff --git a/SpectrumView.pas b/SpectrumView.pas index 01599cd..0b79d14 100644 --- a/SpectrumView.pas +++ b/SpectrumView.pas @@ -495,9 +495,15 @@ begin Inc(Row, X1 * 4); for X := X1 to X2 - 1 do begin +{$IFDEF DARWIN} + Row[1] := Byte((Alpha * R + InvA * Row[1]) div 255); + Row[2] := Byte((Alpha * G + InvA * Row[2]) div 255); + Row[3] := Byte((Alpha * B + InvA * Row[3]) div 255); +{$ELSE} Row[0] := Byte((Alpha * B + InvA * Row[0]) div 255); Row[1] := Byte((Alpha * G + InvA * Row[1]) div 255); Row[2] := Byte((Alpha * R + InvA * Row[2]) div 255); +{$ENDIF} Inc(Row, 4); end; end; @@ -513,6 +519,13 @@ var begin if (FSpectrumBitmap = nil) or (FGridBitmap = nil) then Exit; if (W <= 0) or (H <= 0) then Exit; +{$IFDEF DARWIN} + // On macOS/Cocoa, Canvas writes into a CGBitmapContext; ScanLine reads the + // raw backing buffer which is not synced until BeginUpdate is called on the + // source bitmap. Canvas.Draw goes through CoreGraphics and sees the live + // CGContext, so use it instead of the direct ScanLine copy. + FSpectrumBitmap.Canvas.Draw(0, 0, FGridBitmap); +{$ELSE} FSpectrumBitmap.BeginUpdate(False); try for Y := 0 to H - 1 do @@ -525,6 +538,7 @@ begin finally FSpectrumBitmap.EndUpdate(False); end; +{$ENDIF} end; procedure TSpectrumView.DrawADCOverloadOverlay(C: TCanvas; W, H: Integer); @@ -576,9 +590,15 @@ begin if SpPts[Col].Y <= Row then begin Off := Col * 4; +{$IFDEF DARWIN} + RowPtr[Off+1] := (GradR * Alpha + RowPtr[Off+1] * (200 - Alpha)) div 200; + RowPtr[Off+2] := (GradG * Alpha + RowPtr[Off+2] * (200 - Alpha)) div 200; + RowPtr[Off+3] := (GradB * Alpha + RowPtr[Off+3] * (200 - Alpha)) div 200; +{$ELSE} RowPtr[Off] := (GradB * Alpha + RowPtr[Off] * (200 - Alpha)) div 200; RowPtr[Off+1] := (GradG * Alpha + RowPtr[Off+1] * (200 - Alpha)) div 200; RowPtr[Off+2] := (GradR * Alpha + RowPtr[Off+2] * (200 - Alpha)) div 200; +{$ENDIF} end; end; FSpectrumBitmap.EndUpdate(False); @@ -913,7 +933,11 @@ begin FSpectrumBitmap.BeginUpdate(False); for i := 0 to H - 1 do begin - AlphaPtr := PByte(FSpectrumBitmap.ScanLine[i]) + 3; +{$IFDEF DARWIN} + AlphaPtr := PByte(FSpectrumBitmap.ScanLine[i]); // ARGB: alpha at byte 0 +{$ELSE} + AlphaPtr := PByte(FSpectrumBitmap.ScanLine[i]) + 3; // BGRA: alpha at byte 3 +{$ENDIF} for Yp := 0 to W - 1 do begin AlphaPtr^ := $FF; diff --git a/SpectrumViewOpengl.pas b/SpectrumViewOpengl.pas index 31a5b2f..f70c92a 100644 --- a/SpectrumViewOpengl.pas +++ b/SpectrumViewOpengl.pas @@ -185,10 +185,15 @@ begin Src := PByte(B.ScanLine[Y]); for X := 0 to T.W - 1 do begin +{$IFDEF DARWIN} + // ARGB: byte0=A, byte1=R, byte2=G, byte3=B + IsKey := Keyed and (Src[1] = $FF) and (Src[2] = $00) and (Src[3] = $FF); + Buf[I] := Src[1]; Buf[I+1] := Src[2]; Buf[I+2] := Src[3]; +{$ELSE} + // BGRA: byte0=B, byte1=G, byte2=R IsKey := Keyed and (Src[0] = $FF) and (Src[1] = $00) and (Src[2] = $FF); - Buf[I] := Src[2]; - Buf[I + 1] := Src[1]; - Buf[I + 2] := Src[0]; + Buf[I] := Src[2]; Buf[I+1] := Src[1]; Buf[I+2] := Src[0]; +{$ENDIF} if IsKey then Buf[I + 3] := 0 else Buf[I + 3] := FixedAlpha; Inc(Src, 4); Inc(I, 4); @@ -230,7 +235,11 @@ begin Src := PByte(B.ScanLine[Y]); for X := 0 to T.W - 1 do begin - A := Max(Src[0], Max(Src[1], Src[2])); +{$IFDEF DARWIN} + A := Max(Src[1], Max(Src[2], Src[3])); // ARGB: R,G,B at bytes 1,2,3 +{$ELSE} + A := Max(Src[0], Max(Src[1], Src[2])); // BGRA: B,G,R at bytes 0,1,2 +{$ENDIF} Buf[I] := R; Buf[I + 1] := G; Buf[I + 2] := BB; diff --git a/VfoOverlay.pas b/VfoOverlay.pas index f8e8633..4bc0ed4 100644 --- a/VfoOverlay.pas +++ b/VfoOverlay.pas @@ -173,13 +173,23 @@ begin Inc(DstRow, DstX * 4); for X := SX0 to SX1 - 1 do begin - // KEY_COLOR is clFuchsia in pf32bit B,G,R order. +{$IFDEF DARWIN} + // ARGB layout: byte0=A, byte1=R, byte2=G, byte3=B + if not ((SrcRow[1] = $FF) and (SrcRow[2] = $00) and (SrcRow[3] = $FF)) then + begin + DstRow[1] := Byte((Alpha * SrcRow[1] + InvA * DstRow[1]) div 255); + DstRow[2] := Byte((Alpha * SrcRow[2] + InvA * DstRow[2]) div 255); + DstRow[3] := Byte((Alpha * SrcRow[3] + InvA * DstRow[3]) div 255); + end; +{$ELSE} + // BGRA layout: byte0=B, byte1=G, byte2=R if not ((SrcRow[0] = $FF) and (SrcRow[1] = $00) and (SrcRow[2] = $FF)) then begin DstRow[0] := Byte((Alpha * SrcRow[0] + InvA * DstRow[0]) div 255); DstRow[1] := Byte((Alpha * SrcRow[1] + InvA * DstRow[1]) div 255); DstRow[2] := Byte((Alpha * SrcRow[2] + InvA * DstRow[2]) div 255); end; +{$ENDIF} Inc(SrcRow, 4); Inc(DstRow, 4); end; diff --git a/WidebandView.pas b/WidebandView.pas index d734a1a..3ddf318 100644 --- a/WidebandView.pas +++ b/WidebandView.pas @@ -472,12 +472,17 @@ begin Inc(Row, RR.Left * 4); for X := RR.Left to RR.Right - 1 do begin - BB := Row[0]; - BG := Row[1]; - BR := Row[2]; +{$IFDEF DARWIN} + BB := Row[3]; BG := Row[2]; BR := Row[1]; + Row[1] := Byte((SR * Alpha + BR * (255 - Alpha)) div 255); + Row[2] := Byte((SG * Alpha + BG * (255 - Alpha)) div 255); + Row[3] := Byte((SB * Alpha + BB * (255 - Alpha)) div 255); +{$ELSE} + BB := Row[0]; BG := Row[1]; BR := Row[2]; Row[0] := Byte((SB * Alpha + BB * (255 - Alpha)) div 255); Row[1] := Byte((SG * Alpha + BG * (255 - Alpha)) div 255); Row[2] := Byte((SR * Alpha + BR * (255 - Alpha)) div 255); +{$ENDIF} Inc(Row, 4); end; end; @@ -574,9 +579,15 @@ begin if SpPts[Col].Y <= Row then begin Off := Col * 4; - RowPtr[Off] := (GradB * Alpha + RowPtr[Off] * (200 - Alpha)) div 200; - RowPtr[Off + 1] := (GradG * Alpha + RowPtr[Off + 1] * (200 - Alpha)) div 200; - RowPtr[Off + 2] := (GradR * Alpha + RowPtr[Off + 2] * (200 - Alpha)) div 200; +{$IFDEF DARWIN} + RowPtr[Off+1] := (GradR * Alpha + RowPtr[Off+1] * (200 - Alpha)) div 200; + RowPtr[Off+2] := (GradG * Alpha + RowPtr[Off+2] * (200 - Alpha)) div 200; + RowPtr[Off+3] := (GradB * Alpha + RowPtr[Off+3] * (200 - Alpha)) div 200; +{$ELSE} + RowPtr[Off] := (GradB * Alpha + RowPtr[Off] * (200 - Alpha)) div 200; + RowPtr[Off+1] := (GradG * Alpha + RowPtr[Off+1] * (200 - Alpha)) div 200; + RowPtr[Off+2] := (GradR * Alpha + RowPtr[Off+2] * (200 - Alpha)) div 200; +{$ENDIF} end; end; finally @@ -984,21 +995,37 @@ begin Src := PByte(FLabelBitmap.ScanLine[Y]); for X := 0 to FLabelBitmap.Width - 1 do begin - A := Max(Src[0], Max(Src[1], Src[2])); +{$IFDEF DARWIN} + // ARGB: byte0=A, byte1=R, byte2=G, byte3=B + A := Max(Src[1], Max(Src[2], Src[3])); if A < 6 then A := 0; if A > 0 then begin - Buf[I] := Byte(Min(255, Src[2] * 255 div A)); - Buf[I + 1] := Byte(Min(255, Src[1] * 255 div A)); - Buf[I + 2] := Byte(Min(255, Src[0] * 255 div A)); + Buf[I] := Byte(Min(255, Src[1] * 255 div A)); // R + Buf[I + 1] := Byte(Min(255, Src[2] * 255 div A)); // G + Buf[I + 2] := Byte(Min(255, Src[3] * 255 div A)); // B A := Byte(Min(255, A + (255 - A) div 3)); end else begin - Buf[I] := 0; - Buf[I + 1] := 0; - Buf[I + 2] := 0; + Buf[I] := 0; Buf[I + 1] := 0; Buf[I + 2] := 0; end; +{$ELSE} + // BGRA: byte0=B, byte1=G, byte2=R + A := Max(Src[0], Max(Src[1], Src[2])); + if A < 6 then A := 0; + if A > 0 then + begin + Buf[I] := Byte(Min(255, Src[2] * 255 div A)); // R + Buf[I + 1] := Byte(Min(255, Src[1] * 255 div A)); // G + Buf[I + 2] := Byte(Min(255, Src[0] * 255 div A)); // B + A := Byte(Min(255, A + (255 - A) div 3)); + end + else + begin + Buf[I] := 0; Buf[I + 1] := 0; Buf[I + 2] := 0; + end; +{$ENDIF} Buf[I + 3] := A; Inc(Src, 4); Inc(I, 4);