Quisk version 4.2.54

This commit is contained in:
James C. Ahlstrom
2026-08-04 12:01:45 -04:00
parent 84e194c644
commit 67c6fbcad9
16 changed files with 305 additions and 24 deletions
+9
View File
@@ -1,3 +1,12 @@
Quisk Version 4.2.54 August 2026
=================================
Quisk can now accept audio samples for Tx from TCI at rates 48000, 24000, 12000 and 8000. Please test.
Quisk now includes program icons in the directory "quisk/icons". The Windows icon is quisk/icons/quisk.ico.
On Windows, right-click the desktop icon and change the icon to <path-to-quisk>/quisk/icons/quisk.ico.
The Linux icon is quisk/icons/quisk.svg. On Linux, change the quisk.desktop file to
Icon=<path-to-quisk>/quisk/icons/quisk.svg.
Quisk Version 4.2.53 June 2026 Quisk Version 4.2.53 June 2026
=============================== ===============================
I added TCI support for Software Defined Connectors CW skimmer. Please test. I added TCI support for Software Defined Connectors CW skimmer. Please test.
+1 -1
View File
@@ -1,2 +1,2 @@
#Quisk version 4.2.53 #Quisk version 4.2.54
from .quisk import main from .quisk import main
+3
View File
@@ -255,6 +255,8 @@ and then name the shortcut, perhaps "Quisk".
If you check the properties you will see that Windows expanded the location and start directory to the full path. If you check the properties you will see that Windows expanded the location and start directory to the full path.
If you are curious, Quisk and its Python source files are installed in "<b>your_install_directory</b>\Lib\site-packages\quisk". If you are curious, Quisk and its Python source files are installed in "<b>your_install_directory</b>\Lib\site-packages\quisk".
If you change to that directory you can run Quisk with "pythonw quisk.py". If you change to that directory you can run Quisk with "pythonw quisk.py".
Quisk has its icon file in quisk\icons. Right-click your desktop shortcut and change the Icon to
"<b>your_install_directory</b>\Lib\site-packages\quisk\icons\quisk.ico".
</p> </p>
<br> <br>
<p> <p>
@@ -389,6 +391,7 @@ make
<p> <p>
You run Quisk by running the file quisk.py with python3. For example, "python3 /home/jim/quisk/quisk.py". You run Quisk by running the file quisk.py with python3. For example, "python3 /home/jim/quisk/quisk.py".
You can create a desktop icon to do that, but the method depends on your version of Linux. You can create a desktop icon to do that, but the method depends on your version of Linux.
The quisk icon is the file quisk/icons/quisk.svg.
<b>Never run Quisk with root privelege by using sudo. Fix the permission problem instead.</b> <b>Never run Quisk with root privelege by using sudo. Fix the permission problem instead.</b>
To get started you must tell Quisk what kind of radio hardware you have. Press the Config button and select Radios. To get started you must tell Quisk what kind of radio hardware you have. Press the Config button and select Radios.
Add a radio from the list of hardware radios available. Or add the best match. Add a radio from the list of hardware radios available. Or add the best match.
+4 -4
View File
@@ -414,7 +414,7 @@ double quiskFilt111D4Coefs[196] = { 0.000022860383861326, 0.000070265173417164,
0.000878636067621920, 0.000694724116305488, 0.000487289901409396, 0.000301317969124407, 0.000160689233204503, 0.000878636067621920, 0.000694724116305488, 0.000487289901409396, 0.000301317969124407, 0.000160689233204503,
0.000070265173417164, 0.000022860383861326} ; 0.000070265173417164, 0.000022860383861326} ;
// Sample 53333 Hz, pass 20000, stop 24000, ripple 0.1 dB, atten 100 dB. For SDR-IQ. Stop 0.45000. // Sample 53333 Hz, pass 20000, stop 24000, ripple 0.1 dB, atten 100 dB. For SDR-IQ. Pass 0.375. Stop 0.45000.
double quiskFilt53D1Coefs[55] = { 0.000318858391362187, 0.001662116369387873, -0.000065237353639775, -0.000854885424783294, double quiskFilt53D1Coefs[55] = { 0.000318858391362187, 0.001662116369387873, -0.000065237353639775, -0.000854885424783294,
0.001693126335254083, -0.002034310867663472, 0.001354648789538254, 0.000509693525155950, -0.003079059747940221, 0.005242349925004462, 0.001693126335254083, -0.002034310867663472, 0.001354648789538254, 0.000509693525155950, -0.003079059747940221, 0.005242349925004462,
-0.005626507739484119, 0.003235398612833476, 0.001883583294529978, -0.008273775245721798, 0.013282431836060808, -0.013924391581141530, -0.005626507739484119, 0.003235398612833476, 0.001883583294529978, -0.008273775245721798, 0.013282431836060808, -0.013924391581141530,
@@ -426,7 +426,7 @@ double quiskFilt53D1Coefs[55] = { 0.000318858391362187, 0.001662116369387873, -0
-0.003079059747940221, 0.000509693525155950, 0.001354648789538254, -0.002034310867663472, 0.001693126335254083, -0.000854885424783294, -0.003079059747940221, 0.000509693525155950, 0.001354648789538254, -0.002034310867663472, 0.001693126335254083, -0.000854885424783294,
-0.000065237353639775, 0.001662116369387873, 0.000318858391362187 } ; -0.000065237353639775, 0.001662116369387873, 0.000318858391362187 } ;
// Sample 53333 Hz, pass 10000, stop 12000, ripple 0.5 dB, atten 100 dB. For SDR-IQ. Stop 0.22500. // Sample 53333 Hz, pass 10000, stop 12000, ripple 0.5 dB, atten 100 dB. For SDR-IQ. Pass 0.1875. Stop 0.22500.
double quiskFilt53D2Coefs[93] = { 0.000107966318729964, 0.000421475598772498, 0.000731343669484184, 0.000328611865414609, double quiskFilt53D2Coefs[93] = { 0.000107966318729964, 0.000421475598772498, 0.000731343669484184, 0.000328611865414609,
-0.001457272471508304, -0.004143803290279123, -0.005736802939367581, -0.004303861070721504, -0.000415676176666607, -0.001457272471508304, -0.004143803290279123, -0.005736802939367581, -0.004303861070721504, -0.000415676176666607,
0.002561521351129964, 0.001705074918770091, -0.001794491466202784, -0.003398011312785532, -0.000595401366072839, 0.002561521351129964, 0.001705074918770091, -0.001794491466202784, -0.003398011312785532, -0.000595401366072839,
@@ -603,7 +603,7 @@ double quiskAudio48p6Coefs[71] = { 0.000324677779792651, 0.001038192405843851, 0
0.001132278163758895, 0.002811674671240099, 0.002938055116822665, 0.002082337464742640, 0.001038192405843851, 0.001132278163758895, 0.002811674671240099, 0.002938055116822665, 0.002082337464742640, 0.001038192405843851,
0.000324677779792651} ; 0.000324677779792651} ;
// Sample 96 kHz, pass 6, stop 40, ripple 0.1 dB, atten 100 dB. Stop 0.41667. // Sample 96 kHz, pass 6, stop 40, ripple 0.1 dB, atten 100 dB. Pass 0.0625. Stop 0.41667.
double quiskAudio96Coefs[11] = { -0.004756607210954994, -0.022893760473075838, -0.023609616122334920, double quiskAudio96Coefs[11] = { -0.004756607210954994, -0.022893760473075838, -0.023609616122334920,
0.078161168368381481, 0.277880235815005590, 0.388489826271597950, 0.277880235815005590, 0.078161168368381481, 0.277880235815005590, 0.388489826271597950, 0.277880235815005590,
0.078161168368381481, -0.023609616122334920, -0.022893760473075838, -0.004756607210954994} ; 0.078161168368381481, -0.023609616122334920, -0.022893760473075838, -0.004756607210954994} ;
@@ -663,7 +663,7 @@ double quiskAudioFmHpCoefs[309] = { 0.004847574947800705, -0.001211970386842814,
-0.000365311474947399, -0.000434052387522716, -0.000504808183463150, -0.000579117971409598, -0.000658731927598885, -0.000745515693376396, -0.000365311474947399, -0.000434052387522716, -0.000504808183463150, -0.000579117971409598, -0.000658731927598885, -0.000745515693376396,
-0.000841696354699768, -0.000949749961336003, -0.001072277374239886, -0.001211970386842814, 0.004847574947800705} ; -0.000841696354699768, -0.000949749961336003, -0.001072277374239886, -0.001211970386842814, 0.004847574947800705} ;
// Sample 24 kHz, pass 3, stop 4, ripple 0.1 dB, atten 100 dB. Stop 0.166667. // Sample 24 kHz, pass 3, stop 4, ripple 0.1 dB, atten 100 dB. Pass 0.125. Stop 0.166667.
double quiskAudio24p3Coefs[100] = { 0.000040101217607380, 0.000144142945632828, 0.000313272623844654, 0.000472482653992188, double quiskAudio24p3Coefs[100] = { 0.000040101217607380, 0.000144142945632828, 0.000313272623844654, 0.000472482653992188,
0.000478145332060253, 0.000196098255702949, -0.000370577202968848, -0.000996638165520275, -0.001297816111521122, 0.000478145332060253, 0.000196098255702949, -0.000370577202968848, -0.000996638165520275, -0.001297816111521122,
-0.000964536466628102, -0.000042557313824444, 0.000962997869327471, 0.001323534221298773, 0.000594056697947640, -0.000964536466628102, -0.000042557313824444, 0.000962997869327471, 0.001323534221298773, 0.000594056697947640,
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

+221
View File
@@ -0,0 +1,221 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg5"
sodipodi:docname="quisk.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="36.5"
inkscape:cy="265"
inkscape:window-width="1854"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#c0c276;fill-opacity:1;stroke:#7180ff;stroke-width:48.671;stroke-dasharray:none;stroke-opacity:1"
id="rect556"
width="341.84088"
height="349.28082"
x="62.823105"
y="39.435188"
ry="63.709782" />
<path
style="fill:none;stroke:#7180ff;stroke-width:43.2582;stroke-dasharray:none;stroke-opacity:1"
id="path3352"
d="m 193.20147,396.22476 c 6.34642,4.65885 12.2534,9.94281 18.02477,15.29408 7.66447,7.60025 15.04758,15.4729 22.82647,22.96045 6.77582,6.4671 13.60289,12.87487 20.7907,18.88349 12.48185,9.03783 26.6187,15.49278 41.24908,20.07891 13.25326,2.83808 26.93926,1.98796 40.38664,1.44647 9.20443,-0.51765 18.4186,-0.74315 27.63591,-0.83235 5.72468,-0.0231 11.44941,-0.0285 17.17409,-0.009 6.5518,0.45377 13.10409,0.8185 19.62685,1.59571 0,0 -12.83677,-9.54278 -12.83677,-9.54278 v 0 c -6.57664,-0.66042 -13.17806,-1.05429 -19.77266,-1.4853 -5.6652,0.0193 -11.33079,0.0283 -16.99467,0.16838 -9.18212,0.18217 -18.37151,0.31632 -27.53553,0.96497 -13.36116,0.68668 -27.00081,1.48715 -40.0815,-1.91133 -5.00213,-1.62118 -9.82704,-3.39549 -14.63078,-5.53945 -1.63493,-0.7297 -6.26911,-3.36104 -4.89255,-2.21625 2.66168,2.21356 5.85064,3.70365 8.82036,5.48275 1.18824,0.71182 -2.31609,-1.51997 -3.47415,-2.27995 -7.27169,-6.00427 -14.22221,-12.36521 -21.05126,-18.86768 -7.76318,-7.43952 -15.14957,-15.24359 -22.67391,-22.91764 -5.64713,-5.35952 -11.55857,-10.4455 -17.53983,-15.42662 0,0 -15.05126,-5.84659 -15.05126,-5.84659 z" />
<path
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:17.3033;stroke-dasharray:none;stroke-opacity:1"
d="m 91.391053,213.41065 14.719477,-17.25897 11.13289,28.30763 12.1198,-17.78253 21.1946,-4.54944 18.44448,16.54887 12.64335,-45.07916 6.78807,-41.91379 11.53004,-41.685155 12.62529,26.532375 11.28934,37.31624 2.38907,28.97559 7.74488,35.33638 30.5342,-4.30873 22.19957,-13.63027 4.61563,-22.8555 13.28124,-96.170083 17.96907,92.980663 3.0811,45.22358 24.94369,-9.63446 10.832,-20.40026 14.95416,42.66002"
id="path15623"
sodipodi:nodetypes="cccccccccccccccccccccc" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="rect16404"
width="17.303272"
height="117.87855"
x="86.571724"
y="246.9482"
inkscape:tile-cx="107.539"
inkscape:tile-cy="302.5"
inkscape:tile-w="16"
inkscape:tile-h="109"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18731"
width="17.303272"
height="117.87855"
x="103.87501"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18733"
width="17.303272"
height="117.87855"
x="121.17827"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18735"
width="17.303272"
height="117.87855"
x="138.48155"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18737"
width="17.303272"
height="117.87855"
x="155.78482"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#dc34c6;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18739"
width="17.303272"
height="117.87855"
x="173.08809"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#fffa41;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18741"
width="17.303272"
height="117.87855"
x="190.39134"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#d20ac7;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18743"
width="17.303272"
height="117.87855"
x="207.69463"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18745"
width="17.303272"
height="117.87855"
x="224.99789"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<use
x="0"
y="0"
inkscape:tiled-clone-of="#rect16404"
xlink:href="#rect16404"
transform="translate(155.72944)"
id="use18747"
style="fill:#3e4fa1;fill-opacity:1" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18749"
width="17.303272"
height="117.87855"
x="259.60446"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#b931b2;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18751"
width="17.303272"
height="117.87855"
x="276.90775"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#e7ec2e;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18753"
width="17.303272"
height="117.87855"
x="294.21097"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#a735a6;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18755"
width="17.303272"
height="117.87855"
x="311.51425"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18757"
width="17.303272"
height="117.87855"
x="328.81754"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18759"
width="17.303272"
height="117.87855"
x="346.12079"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<rect
style="fill:#3e4fa1;fill-opacity:1;stroke:none;stroke-width:34.8847;stroke-dasharray:none;stroke-opacity:1"
id="use18761"
width="17.303272"
height="117.87855"
x="363.42407"
y="246.9482"
inkscape:tile-x0="99.539001"
inkscape:tile-y0="248" />
<path
id="path12957"
style="fill:none;fill-opacity:1;stroke:#7180ff;stroke-width:48.671;stroke-dasharray:none;stroke-opacity:1"
d="m 404.54932,300.57496 v 23.76192 c 0,35.29519 -28.4146,63.70978 -63.70977,63.70978 H 126.41823 c -35.295185,0 -63.709785,-28.41459 -63.709785,-63.70978 v -23.19942" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+9 -3
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "quisk" name = "quisk"
version = "4.2.53" version = "4.2.54"
requires-python = ">=3.13" requires-python = ">=3.13"
description = 'QUISK is a Software Defined Radio (SDR) transceiver that can control various radio hardware.' description = 'QUISK is a Software Defined Radio (SDR) transceiver that can control various radio hardware.'
license = "GPL-2.0-or-later" license = "GPL-2.0-or-later"
@@ -25,6 +25,7 @@ classifiers = [
'Programming Language :: C', 'Programming Language :: C',
'Topic :: Communications :: Ham Radio', 'Topic :: Communications :: Ham Radio',
] ]
dynamic = ["readme"]
[project.gui-scripts] [project.gui-scripts]
quisk = "quisk.quisk:main" quisk = "quisk.quisk:main"
@@ -35,7 +36,12 @@ Documentation = "https://james.ahlstrom.name/quisk/docs.html"
Repository = "https://github.com/jimahlstrom/quisk" Repository = "https://github.com/jimahlstrom/quisk"
Changelog = "https://james.ahlstrom.name/quisk/CHANGELOG.txt" Changelog = "https://james.ahlstrom.name/quisk/CHANGELOG.txt"
[tool.setuptools.packages.find] [tool.setuptools.package-data]
where = ["."] "quisk.icons" = ["*"]
[tool.setuptools]
package-dir = {"quisk" = "."}
packages = ["quisk", "quisk.n2adr", "quisk.softrock", "quisk.freedvpkg",
"quisk.hermes", "quisk.hiqsdr", "quisk.afedrinet", "quisk.soapypkg",
"quisk.sdrmicronpkg", "quisk.perseuspkg", "quisk.ac2yd", "quisk.multuspkg"]
+1 -1
View File
@@ -82,7 +82,7 @@ N1MM+ and software that uses Hamlib.
'quisk.hermes', 'quisk.hiqsdr', 'quisk.afedrinet', 'quisk.soapypkg', 'quisk.hermes', 'quisk.hiqsdr', 'quisk.afedrinet', 'quisk.soapypkg',
'quisk.sdrmicronpkg', 'quisk.perseuspkg', 'quisk.ac2yd', 'quisk.multuspkg'], 'quisk.sdrmicronpkg', 'quisk.perseuspkg', 'quisk.ac2yd', 'quisk.multuspkg'],
package_dir = {'quisk' : '.'}, package_dir = {'quisk' : '.'},
package_data = {'' : ['*.txt', '*.html', '*.so', '*.dll']}, package_data = {'' : ['*.txt', '*.html', '*.so', '*.dll'], 'quisk' : ['icons/*']},
entry_points = {'gui_scripts' : ['quisk = quisk.quisk:main', 'quisk_vna = quisk.quisk_vna:main']}, entry_points = {'gui_scripts' : ['quisk = quisk.quisk:main', 'quisk_vna = quisk.quisk_vna:main']},
ext_modules = Modules, ext_modules = Modules,
provides = ['quisk'], provides = ['quisk'],
+57 -15
View File
@@ -80,9 +80,14 @@ struct ClientData { // data for each client
int audio_stream_channels; int audio_stream_channels;
int audio_stream_samples; int audio_stream_samples;
int audio_stream_bytes_per_sample; int audio_stream_bytes_per_sample;
// Rx stream decimation filters
struct quisk_cHB45Filter HalfBand1; struct quisk_cHB45Filter HalfBand1;
struct quisk_cFilter filtDecim3; struct quisk_cFilter filtDecim3;
struct quisk_cFilter filtDecim48to24; struct quisk_cFilter filtDecim48to24;
// Tx stream interpolation filters
struct quisk_cHB45Filter HalfBandTx1;
struct quisk_cHB45Filter HalfBandTx2;
struct quisk_cFilter filtTxInterp3;
int send_IQ_stream; int send_IQ_stream;
int IQ_stream_samplerate; int IQ_stream_samplerate;
} ; } ;
@@ -138,6 +143,9 @@ struct _StreamTypes StreamTypes[NUM_STREAM_TYPES] = {
{"lineout ", 0} {"lineout ", 0}
} ; } ;
static int interpolate_tx_audio_stream(complex double * cSamples, int nSamples, struct ClientData * ctx);
static int decimate_audio_stream(complex double * cSamples, int nSamples, struct ClientData * ctx);
static void PrintStream(const char * msg, size_t size, int always) static void PrintStream(const char * msg, size_t size, int always)
{ {
struct _Stream * pt = (struct _Stream *)msg; struct _Stream * pt = (struct _Stream *)msg;
@@ -203,6 +211,7 @@ static int text_message(ws_cli_conn_t client, struct ClientData * ctx)
for (i = 0; i < tci_clients_count; i++) { for (i = 0; i < tci_clients_count; i++) {
if (tci_clients_list[i] == client) { if (tci_clients_list[i] == client) {
ctx->send_Rx_audio_stream = 1; ctx->send_Rx_audio_stream = 1;
// Rx stream filters
memset(&ctx->HalfBand1, memset(&ctx->HalfBand1,
0, sizeof(struct quisk_cHB45Filter)); 0, sizeof(struct quisk_cHB45Filter));
quisk_filt_cInit(&ctx->filtDecim3, quisk_filt_cInit(&ctx->filtDecim3,
@@ -361,6 +370,13 @@ static int text_message(ws_cli_conn_t client, struct ClientData * ctx)
tci_tx_audio_samples = 0; tci_tx_audio_samples = 0;
tci_tx_audio_rate = ctx->audio_stream_samplerate; tci_tx_audio_rate = ctx->audio_stream_samplerate;
pthread_mutex_unlock(&tx_buffer_mutex); pthread_mutex_unlock(&tx_buffer_mutex);
// Tx stream filters
memset(&ctx->HalfBandTx1,
0, sizeof(struct quisk_cHB45Filter));
memset(&ctx->HalfBandTx2,
0, sizeof(struct quisk_cHB45Filter));
quisk_filt_cInit(&ctx->filtTxInterp3,
quiskAudio24p3Coefs, sizeof(quiskAudio24p3Coefs)/sizeof(double));
} }
} }
else if (client == tci_tx_audio_client) { else if (client == tci_tx_audio_client) {
@@ -426,7 +442,7 @@ static void onopen(ws_cli_conn_t client)
QuiskPrintf("TCI *Connection opened, addr: %s\n", cli); QuiskPrintf("TCI *Connection opened, addr: %s\n", cli);
} }
sendframe_txt(client, "protocol:ESDR,1.4;"); sendframe_txt(client, "protocol:ExpertSDR3,2.0;");
//sendframe_txt(client, "vfo_limits:30000,30000000;"); Not known due to transverters //sendframe_txt(client, "vfo_limits:30000,30000000;"); Not known due to transverters
int if_limit = quisk_sound_state.sample_rate / 2; int if_limit = quisk_sound_state.sample_rate / 2;
snprintf(command, TCI_COMMAND_SIZE, "if_limits:%d,%d;", - if_limit, if_limit); snprintf(command, TCI_COMMAND_SIZE, "if_limits:%d,%d;", - if_limit, if_limit);
@@ -480,12 +496,14 @@ static void onclose(ws_cli_conn_t client)
static void onmessage(ws_cli_conn_t client, const unsigned char *msg, uint64_t size, int type) static void onmessage(ws_cli_conn_t client, const unsigned char *msg, uint64_t size, int type)
{ {
char echo_copy[TCI_RX_BUF_SIZE]; char echo_copy[TCI_RX_BUF_SIZE];
complex double sample; int n;
static complex double * cCopy = NULL;
static int cCopy_size = 0;
struct ClientData * ctx = ws_get_connection_context(client);
if (type == WS_FR_OP_TXT) { if (type == WS_FR_OP_TXT) {
if (size > TCI_RX_BUF_SIZE / 2) if (size > TCI_RX_BUF_SIZE / 2)
return; // prevent overflow return; // prevent overflow
struct ClientData * ctx = ws_get_connection_context(client);
if (ctx->msg_length + size >= TCI_RX_BUF_SIZE - 2) if (ctx->msg_length + size >= TCI_RX_BUF_SIZE - 2)
ctx->msg_length = 0; // prevent overflow ctx->msg_length = 0; // prevent overflow
memcpy(ctx->msg_buf + ctx->msg_length, msg, size); // append msg to buffer memcpy(ctx->msg_buf + ctx->msg_length, msg, size); // append msg to buffer
@@ -519,7 +537,6 @@ static void onmessage(ws_cli_conn_t client, const unsigned char *msg, uint64_t s
const unsigned char * vpt2; const unsigned char * vpt2;
const unsigned char * vpt2_end; const unsigned char * vpt2_end;
int count2; int count2;
int buf_start=0, buf_end;
if (verbose >= 3) { if (verbose >= 3) {
QuiskPrintf("\n\nMSG size %ld length %d\n 0 ", size, pt->length); QuiskPrintf("\n\nMSG size %ld length %d\n 0 ", size, pt->length);
@@ -544,15 +561,19 @@ static void onmessage(ws_cli_conn_t client, const unsigned char *msg, uint64_t s
} }
if (pt->type == TX_AUDIO_STREAM) { if (pt->type == TX_AUDIO_STREAM) {
n = pt->length * 7 + 100; // Make room for 6X interpolation
if (cCopy_size < n) {
if (cCopy)
free(cCopy);
cCopy_size = n;
cCopy = (complex double *)malloc(cCopy_size * sizeof(complex double));
}
if (pt->length > 0 && client == tci_tx_audio_client) { if (pt->length > 0 && client == tci_tx_audio_client) {
pthread_mutex_lock(&tx_buffer_mutex); n = 0;
if (verbose >= 2)
buf_start = CircularBuffer(0, &sample, 0, 0);
switch (TxChrono.format) { switch (TxChrono.format) {
case TCI_INT16: case TCI_INT16:
break; break;
case TCI_FLOAT32: case TCI_FLOAT32:
// Version 1.4 does not return the number of channels. We assume two channels.
// pt->length is the number of floats // pt->length is the number of floats
while (vpt < vpt_end && count < pt->length) { while (vpt < vpt_end && count < pt->length) {
re = *(float *)vpt; re = *(float *)vpt;
@@ -566,18 +587,16 @@ static void onmessage(ws_cli_conn_t client, const unsigned char *msg, uint64_t s
else { else {
im = re; im = re;
} }
sample = (re + I * im) * (CLIP32 / 2); cCopy[n++] = (re + I * im) * (CLIP32 / 2);
CircularBuffer(0, &sample, 0, 1);
} }
if (verbose && count != pt->length) if (verbose && count != pt->length)
QuiskPrintf("TCI *TX count %ld %d %d\n", size, count, pt->length); QuiskPrintf("TCI *TX count %ld %d %d\n", size, count, pt->length);
n = interpolate_tx_audio_stream(cCopy, n, ctx);
pthread_mutex_lock(&tx_buffer_mutex);
CircularBuffer(0, cCopy, 0, n);
pthread_mutex_unlock(&tx_buffer_mutex);
break; break;
} }
if (verbose >= 2) {
buf_end = CircularBuffer(0, &sample, 0, 0);
QuiskPrintf("TCI Tx buffer add %4d start %5d end %5d\n", count, buf_start, buf_end);
}
pthread_mutex_unlock(&tx_buffer_mutex);
} }
} }
if (verbose) if (verbose)
@@ -634,6 +653,29 @@ static int decimate_audio_stream(complex double * cSamples, int nSamples, struct
return nSamples; return nSamples;
} }
static int interpolate_tx_audio_stream(complex double * cSamples, int nSamples, struct ClientData * ctx)
{
switch(tci_tx_audio_rate) { // Ending audio rate is 48000
case 48000:
break;
case 24000:
nSamples = quisk_cInterp2HB45(cSamples, nSamples, &ctx->HalfBandTx1);
break;
case 12000:
nSamples = quisk_cInterp2HB45(cSamples, nSamples, &ctx->HalfBandTx1);
nSamples = quisk_cInterp2HB45(cSamples, nSamples, &ctx->HalfBandTx2);
break;
case 8000:
nSamples = quisk_cInterpolate(cSamples, nSamples, &ctx->filtTxInterp3, 3);
nSamples = quisk_cInterp2HB45(cSamples, nSamples, &ctx->HalfBandTx1);
break;
default:
nSamples = 0;
break;
}
return nSamples;
}
void tci_send_audio(complex double * cSamples, int nSamples) // called from the sound thread void tci_send_audio(complex double * cSamples, int nSamples) // called from the sound thread
{ {
int i, n; int i, n;