Porównaj commity
650 Commity
Autor | SHA1 | Data |
---|---|---|
Roeland Jansen | 85178de1d5 | |
Roeland Jansen | c7e8e90928 | |
Phil Taylor | 9db9be5dec | |
Phil Taylor | 637e94dfd8 | |
Elliott Liggett | b68874d328 | |
AsciiWolf | e5c6e2030a | |
AsciiWolf | 9be0acdf2e | |
Roeland Jansen | 1805861274 | |
Phil Taylor | b4c079f7f4 | |
Phil Taylor | 80d6614ca7 | |
Phil Taylor | 7df55bc41f | |
Roeland Jansen | 54b00b9022 | |
Roeland Jansen | 0c072f4665 | |
M0VSE | 6fc63df321 | |
M0VSE | d5e4a67ac1 | |
Roeland Jansen | c7e53f6a4d | |
Roeland Jansen | 375acead89 | |
Phil Taylor | e274271820 | |
Phil Taylor | 34655f6348 | |
Phil Taylor | 8ad74ac7f6 | |
Phil Taylor | 5d897c127a | |
Phil Taylor | 3c90a9363b | |
Phil Taylor | c392874b3b | |
Phil Taylor | 7b101d5ad4 | |
Phil Taylor | 6a2e2024ef | |
Phil Taylor | d941c831f3 | |
Phil Taylor | f35ac25ad3 | |
Phil Taylor | 58f38c1735 | |
Phil Taylor | 59bc2077e4 | |
Phil Taylor | 8b786c1821 | |
Phil Taylor | 5ded2a0e79 | |
M0VSE | c9300f4d86 | |
Roeland Jansen | 1549819ad6 | |
M0VSE | 4874d70215 | |
Phil Taylor | d5f0e0f63c | |
Phil Taylor | 1da3696ba2 | |
Phil Taylor | 289170e22d | |
Phil Taylor | ae0271c7f9 | |
Phil Taylor | a0f3f7de07 | |
Phil Taylor | 0304ac67f6 | |
Phil Taylor | 468cd2de0d | |
Phil Taylor | 592c583d19 | |
Phil Taylor | cadf835d95 | |
Phil Taylor | 75288b5e78 | |
Phil Taylor | 6fd0d4e763 | |
Phil Taylor | 03c45663dc | |
Phil Taylor | ac58289188 | |
Phil Taylor | d7ba3d9d9a | |
Phil Taylor | d1688a99c5 | |
Phil Taylor | a74f68d9d4 | |
Phil Taylor | f663550da7 | |
M0VSE | 9d63c5cb71 | |
Phil Taylor | eb65ae0b1c | |
Phil Taylor | 898d5960d8 | |
Phil Taylor | a461babf73 | |
Phil Taylor | 792fac11d6 | |
Phil Taylor | f3a25fade4 | |
Roeland Jansen | 3fa14ebc37 | |
Roeland Jansen | 6049e1dee6 | |
Roeland Jansen | e8ca39ca18 | |
Phil Taylor | 48a9710c11 | |
Phil Taylor | 5328838c73 | |
Phil Taylor | 87a261be12 | |
Phil Taylor | b738a38cbe | |
Phil Taylor | b2af4c898e | |
Phil Taylor | cf4e872e4f | |
Phil Taylor | 37c30404d8 | |
Phil Taylor | 5b9a5baaa1 | |
Roeland Jansen | fc0bd2232d | |
Phil Taylor | 2186a74490 | |
Phil Taylor | b9288175bd | |
Phil Taylor | 7901ceba79 | |
Phil Taylor | e49eb2878e | |
Phil Taylor | c8b97e8952 | |
Phil Taylor | a6b1bce69e | |
Phil Taylor | e6644cdc11 | |
Phil Taylor | fe0fc0a5bb | |
Phil Taylor | 5fb9588c4a | |
Phil Taylor | 62f923d8ad | |
Phil Taylor | 9f97df0ea5 | |
Phil Taylor | ed1e8c3a8e | |
Phil Taylor | acec37ea17 | |
Phil Taylor | 428ea9156c | |
Phil Taylor | 18254cad10 | |
Phil Taylor | 67685dc100 | |
Phil Taylor | 71fd70f78b | |
Phil Taylor | f9ca8e7e84 | |
Phil Taylor | acaed4601e | |
Phil Taylor | 1177fa3419 | |
Phil Taylor | 97ed3f6f42 | |
Phil Taylor | e594efdbbc | |
Phil Taylor | 3ce35500b9 | |
Phil Taylor | 9eb89a9cb1 | |
Phil Taylor | fd6d132fd3 | |
Phil Taylor | 6f1d4e24b7 | |
Phil Taylor | 8b7377f096 | |
Roeland Jansen | ce9e3e9f2c | |
Phil Taylor | dd4770a85f | |
Phil Taylor | 32e662237b | |
Phil Taylor | 3582c95c58 | |
Phil Taylor | da71bb3bc3 | |
Phil Taylor | 0397b4b68a | |
Phil Taylor | feac83b997 | |
Phil Taylor | 9afc661c4c | |
Phil Taylor | 6de14df1da | |
Phil Taylor | 7e89e9f457 | |
Phil Taylor | 3cb54f9cd7 | |
Phil Taylor | 80838e4f82 | |
Phil Taylor | 54c75d5def | |
Phil Taylor | 8b59efbf33 | |
Phil Taylor | 9db0698927 | |
Phil Taylor | 251239e445 | |
Phil Taylor | a3a82cd442 | |
Phil Taylor | 3461a0e5e5 | |
Phil Taylor | 3429786e10 | |
Phil Taylor | c2e9100a40 | |
Phil Taylor | c8a29bb400 | |
Phil Taylor | fa47bfb4bc | |
Phil Taylor | 82425b445e | |
Phil Taylor | 7aa7546660 | |
Phil Taylor | 4e61a455b5 | |
Phil Taylor | cad3bb9418 | |
Phil Taylor | 1f1800f046 | |
Phil Taylor | 5ed380c03d | |
Phil Taylor | a8951813f5 | |
Roeland Jansen | 6e5e22a672 | |
Elliott Liggett | bbbfe38e0b | |
Roeland Jansen | 6a76efa368 | |
Phil Taylor | 17a6547264 | |
Phil Taylor | 1515e135e5 | |
Phil Taylor | 0ff2551026 | |
Phil Taylor | cb339edc1f | |
Phil Taylor | f4a86ac02e | |
Phil Taylor | b783f8057a | |
Phil Taylor | 1064038138 | |
Phil Taylor | dda3c8ee9d | |
Phil Taylor | 63b8a356e8 | |
Phil Taylor | 4fc37290e5 | |
Phil Taylor | 72e8bc6fa6 | |
Phil Taylor | 8a28a89760 | |
Phil Taylor | 5298949f3a | |
Phil Taylor | 1e217bc5b8 | |
Phil Taylor | fbea7f1a13 | |
Dawid Szymanski - SQ6EMM/SN6M | 32639c5394 | |
Roeland Jansen | b373685fd3 | |
Roeland Jansen | ea1fefc219 | |
Phil Taylor | 3d2c16201b | |
Roeland Jansen | 6e0ebcdd5a | |
Roeland Jansen | 2488d62f2e | |
Phil Taylor | 40f49c56e7 | |
Phil Taylor | 529d101540 | |
Phil Taylor | 14a4b25e97 | |
Phil Taylor | 78fa248963 | |
Phil Taylor | 7de515b70d | |
Phil Taylor | 76694361b5 | |
Phil Taylor | 0e28f288ff | |
Phil Taylor | b619be3e2a | |
Phil Taylor | 64c0007c78 | |
Phil Taylor | b566a760ed | |
Phil Taylor | 69afce7712 | |
Phil Taylor | 5654fa524e | |
Phil Taylor | 3d053c3c96 | |
Phil Taylor | 872c8aee30 | |
Phil Taylor | e2d6101a53 | |
Phil Taylor | b35e1af185 | |
Phil Taylor | a60cb39483 | |
Phil Taylor | 6464f28159 | |
Phil Taylor | 7b7d21d3a7 | |
Roeland Jansen | 16eb4591eb | |
Roeland Jansen | eae5b93f0e | |
Phil Taylor | 02c1dcdb8b | |
Phil Taylor | f4e772e1c7 | |
Phil Taylor | 4a3f8692b5 | |
Phil Taylor | 2ec62b6c80 | |
Phil Taylor | 01e01321d3 | |
Phil Taylor | f0c8842c05 | |
Phil Taylor | 979dffc176 | |
Phil Taylor | 2128e6fc10 | |
Phil Taylor | fd86efa4b9 | |
Phil Taylor | 27ac972f4a | |
Elliott Liggett | bb632b8e2b | |
Roeland Jansen | 11f8cb702f | |
Roeland Jansen | 82f268508e | |
Phil Taylor | a1db8d1d60 | |
Roeland Jansen | a08ada4cab | |
Phil Taylor | 5671e26591 | |
Roeland Jansen | 953399de06 | |
Phil Taylor | 903d1965ba | |
Phil Taylor | eae1fc725e | |
Phil Taylor | 857c62f99f | |
Phil Taylor | 7b2aca6cbd | |
Phil Taylor | f3da86940f | |
Roeland Jansen | c70bbb0998 | |
Phil Taylor | d7fa78fcd2 | |
Roeland | 0af2615833 | |
Phil Taylor | b928f23051 | |
Roeland Jansen | 41aa95129a | |
Roeland Jansen | 072ab1967f | |
Phil Taylor | 75b86a0e4a | |
Phil Taylor | b334241ea0 | |
Phil Taylor | a511282505 | |
Phil Taylor | 4ea80af164 | |
Phil Taylor | 80dc5d2df6 | |
Phil Taylor | 3993046771 | |
Phil Taylor | 06c3e33b4d | |
Phil Taylor | d0cd7e2eb3 | |
Phil Taylor | 5237c930e5 | |
Phil Taylor | 777d08ef24 | |
Phil Taylor | c4fcc89830 | |
Phil Taylor | 193e07284e | |
Phil Taylor | 6c44ea9e0d | |
Phil Taylor | ad50d41071 | |
Phil Taylor | 1ac8f5c2f0 | |
Phil Taylor | e20900dbcf | |
Phil Taylor | a192e6643b | |
Phil Taylor | c6bd93a2b6 | |
Phil Taylor | 4816427954 | |
Elliott Liggett | 156f45d42f | |
Elliott Liggett | bbcc0e4842 | |
Elliott Liggett | 4411c1480e | |
Phil Taylor | 5fa14d13e1 | |
Phil Taylor | 180b7b0095 | |
Phil Taylor | 071606fe5a | |
Phil Taylor | 096c223715 | |
Elliott Liggett | eaf7eb126e | |
Elliott Liggett | 38e6cb2ef4 | |
Elliott Liggett | 3c31687b15 | |
Elliott Liggett | a5f3750988 | |
Elliott Liggett | eea17e5e09 | |
Elliott Liggett | d503df03bd | |
Elliott Liggett | 17d6493338 | |
Elliott Liggett | cb7cf6c218 | |
Phil Taylor | 2696d2c8d9 | |
Phil Taylor | 63a7ec0a21 | |
Phil Taylor | 28c9d1beb2 | |
Phil Taylor | db9f6cb933 | |
Phil Taylor | 2c9c304844 | |
Roeland Jansen | b2915b9f5e | |
Roeland Jansen | 3bdee82501 | |
Roeland Jansen | 199295b6ae | |
Roeland Jansen | c89a7bde97 | |
Phil Taylor | 0b37b1f984 | |
Elliott Liggett | fc4bce8cd7 | |
Elliott Liggett | 5d5723fae6 | |
Elliott Liggett | eec2fff4ce | |
Phil Taylor | db686b1c8b | |
Phil Taylor | 5afcfb4e1d | |
Phil Taylor | cb81bef3bc | |
Phil Taylor | db5f8a0893 | |
Phil Taylor | 479671386e | |
Elliott Liggett | 3faf8d331c | |
Phil Taylor | 3ca82deb6c | |
Phil Taylor | 8d8f945cfa | |
Phil Taylor | 12f7a9cf0a | |
Phil Taylor | 9d711f3a17 | |
Elliott Liggett | 78ec6b1423 | |
Phil Taylor | 0e9a26dbc1 | |
Elliott Liggett | de9f510d76 | |
Elliott Liggett | 2d1773720d | |
Dawid SQ6EMM | e13d85489d | |
Phil Taylor | 5926c12a20 | |
Phil Taylor | c55ff52fc0 | |
Phil Taylor | 79decc552b | |
Phil Taylor | 5d5ea25fb6 | |
Phil Taylor | 7e7dceaa99 | |
Phil Taylor | 166905ee76 | |
Elliott Liggett | c91d06fea5 | |
Elliott Liggett | bc508565ee | |
Elliott Liggett | 264badb9c9 | |
Elliott Liggett | 6976120d48 | |
Elliott Liggett | 8903c7cb07 | |
Elliott Liggett | b30230fc05 | |
Elliott Liggett | 2c6884d827 | |
Elliott Liggett | 404d6ddceb | |
Elliott Liggett | f660681c53 | |
Phil Taylor | eb782da010 | |
Phil Taylor | fa41571eca | |
Phil Taylor | 5d0a95cd00 | |
Phil Taylor | 5dc9107f00 | |
Phil Taylor | 5128ea0e69 | |
Roeland Jansen | 5db5f40ed4 | |
Roeland Jansen | fe36ff1ac7 | |
Phil Taylor | 49501273d0 | |
Phil Taylor | ea46d6c625 | |
Roeland Jansen | 13f06e1dd7 | |
Phil Taylor | ded6bd1ade | |
Phil Taylor | 4b40e20d98 | |
Roeland Jansen | 6df7099cb3 | |
Phil Taylor | 5483732766 | |
Phil Taylor | 8b8668a6de | |
Roeland Jansen | bc0f9f01c7 | |
Elliott Liggett | be0aee6183 | |
Roeland Jansen | 85e38d940f | |
Elliott Liggett | 4fea16c356 | |
Elliott Liggett | ae64677c42 | |
Phil Taylor | a1d3f93dad | |
Roeland Jansen | 7f97625e38 | |
Elliott Liggett | d53c9b028e | |
Elliott Liggett | 0a7f6b0b65 | |
Roeland Jansen | 2df82d4f92 | |
Phil Taylor | 152f71c6cf | |
Phil Taylor | 2ada127124 | |
Phil Taylor | 646ee94341 | |
Elliott Liggett | 68ed3dc56b | |
Elliott Liggett | 4137fce70c | |
Phil Taylor | 7ebfcdefbd | |
Phil Taylor | b89ae0459e | |
Phil Taylor | 525f984f01 | |
Phil Taylor | 9c3ca568ed | |
Phil Taylor | 4e89c91f0d | |
Phil Taylor | f93dd83268 | |
Phil Taylor | 9349679e5b | |
Elliott Liggett | cba4ad345b | |
Elliott Liggett | 3297f66208 | |
Elliott Liggett | 294fac72c6 | |
Elliott Liggett | 27dd547e2a | |
Elliott Liggett | a205e003c9 | |
Elliott Liggett | 4a0f5a7f59 | |
Phil Taylor | e7091cb2c2 | |
Elliott Liggett | deade9a38e | |
Elliott Liggett | c5c01cf81d | |
Elliott Liggett | 7a4f708e68 | |
Elliott Liggett | c26409b2a8 | |
Elliott Liggett | ff50718563 | |
Elliott Liggett | 2f098be1a9 | |
Elliott Liggett | f772801b02 | |
Elliott Liggett | fd1dc860c1 | |
Elliott Liggett | 5664842f47 | |
Elliott Liggett | b3258c57a5 | |
Elliott Liggett | 23c191a091 | |
Phil Taylor | 93d20cc1ba | |
Phil Taylor | ee4f00e153 | |
Elliott Liggett | 1e79d5d32d | |
Roeland Jansen | 18281798d6 | |
Phil Taylor | c98d7094f9 | |
Phil Taylor | 037f05297d | |
Elliott Liggett | 71326cd385 | |
Elliott Liggett | b99249692f | |
Elliott Liggett | e9e042fad8 | |
Phil Taylor | f224068ec1 | |
Phil Taylor | e94c3e53c5 | |
Elliott Liggett | 0c27bf7208 | |
Elliott Liggett | 05295acc6f | |
Elliott Liggett | fc753ffd39 | |
Elliott Liggett | f820d289b2 | |
Elliott Liggett | 9c0aea0102 | |
Phil Taylor | a0f7d5d86f | |
Phil Taylor | a6ea32d996 | |
Phil Taylor | 450ccefb60 | |
Phil Taylor | ca84555c15 | |
Phil Taylor | 8fca384135 | |
Phil Taylor | 794a8b71c8 | |
Phil Taylor | 3baf3eae65 | |
Phil Taylor | ffd7abb376 | |
Phil Taylor | 120899e9f8 | |
Roeland Jansen | b468c514df | |
Roeland Jansen | c221fb4a04 | |
Phil Taylor | c3ba36ebfd | |
Phil Taylor | d1ec010e68 | |
Phil Taylor | e2f4646207 | |
Phil Taylor | 19818dc3b3 | |
Phil Taylor | 58f86f029b | |
Phil Taylor | b285b81d72 | |
Phil Taylor | 8f98696bec | |
Phil Taylor | 4f4cd5146c | |
Phil Taylor | cac454cbf6 | |
Phil Taylor | 3e46b5a42d | |
Phil Taylor | 41e5e4b1c3 | |
Phil Taylor | d48bdfa6e2 | |
Phil Taylor | 4ee8741157 | |
Phil Taylor | efb953a8c9 | |
Roeland Jansen | 596607e95a | |
Phil Taylor | 5c210f0699 | |
Phil Taylor | 996c813251 | |
Phil Taylor | 8f5016a2f4 | |
Roeland Jansen | f86a721a05 | |
Roeland Jansen | 7052dbf6ef | |
Phil Taylor | 5d2089c3e1 | |
Phil Taylor | 460641972a | |
Phil Taylor | b2d62dab3c | |
Phil Taylor | c0a70ae0b7 | |
Phil Taylor | b45bf9ce41 | |
Phil Taylor | 0d9a01cd1f | |
Phil Taylor | 93f18fae9e | |
Roeland Jansen | 29897e5795 | |
Roeland Jansen | 1deaec3720 | |
Phil Taylor | b7f83a7807 | |
Phil Taylor | 8a4b9f1934 | |
Phil Taylor | 03ebafae5b | |
Phil Taylor | 00a5c78e98 | |
Phil Taylor | d9ff07486d | |
Phil Taylor | 4a8de3c0c9 | |
Phil Taylor | 3e149ee742 | |
Phil Taylor | 373b670482 | |
Phil Taylor | 7bb5e0f9c5 | |
Phil Taylor | 322cc54ad6 | |
Phil Taylor | 4e62f365cd | |
Roeland Jansen | 24ac791ad4 | |
Roeland Jansen | 5dabcb34df | |
Phil Taylor | 39dacf54f2 | |
Phil Taylor | e6a5152734 | |
roeland jansen | b3f76fce67 | |
Phil Taylor | 436428b3a9 | |
Phil Taylor | a327b2690e | |
Phil Taylor | 7348fc2ed0 | |
Phil Taylor | ff6dd19e53 | |
Phil Taylor | db0112c8a3 | |
Phil Taylor | 6199c648c1 | |
Phil Taylor | 32528a02b8 | |
Phil Taylor | 91ce6040e0 | |
Dawid SQ6EMM | 8ead34b253 | |
Phil Taylor | 891fd68a52 | |
Phil Taylor | f4c455396a | |
Phil Taylor | a89af116e9 | |
Phil Taylor | aabe690bae | |
Phil Taylor | 14fc07905e | |
Phil Taylor | 0aca239b2a | |
Phil Taylor | 2bf14520d8 | |
Phil Taylor | 0b51d5bb05 | |
Phil Taylor | 72e8b2ec2f | |
Phil Taylor | c3fa41490a | |
Phil Taylor | 978a444759 | |
Dawid Szymański | 3aa4375bdf | |
Phil Taylor | 7dfdc5e3e2 | |
Phil Taylor | f232ff2396 | |
Phil Taylor | d9e839b6f2 | |
Roeland Jansen | 0d2d9ba23e | |
Roeland Jansen | 28d3c55e2f | |
Elliott Liggett | 093e6e799c | |
Roeland Jansen | ac3894f897 | |
Phil Taylor | e8142a11ba | |
Phil Taylor | 3bf095020c | |
Phil Taylor | e56294406a | |
Roeland Jansen | 8d3406a8ae | |
Elliott Liggett | f6b1428267 | |
Elliott Liggett | 82dfb99822 | |
Elliott Liggett | 8cfb3f70e5 | |
Phil Taylor | 0b39b91665 | |
Phil Taylor | 65ba69822a | |
Phil Taylor | f91dea47b5 | |
Roeland Jansen | 9367d605f4 | |
Roeland Jansen | 508f870062 | |
Roeland Jansen | 06e4567b12 | |
Phil Taylor | 4c76cf6320 | |
Phil Taylor | 0a1a7b2336 | |
Elliott Liggett | 8a1347f17c | |
Elliott Liggett | 4f6da00206 | |
Elliott Liggett | 39caf41905 | |
Elliott Liggett | b25c8a93f3 | |
Phil Taylor | 81f9e9bfcf | |
Phil Taylor | 7138ef69ea | |
Phil Taylor | 1fe19166f3 | |
Elliott Liggett | afcf087a70 | |
Elliott Liggett | e1e9167622 | |
Elliott Liggett | 9a63a6c4c4 | |
Elliott Liggett | bb5ae03235 | |
Elliott Liggett | 45244c7c64 | |
Elliott Liggett | a5ac42fe57 | |
Elliott Liggett | 9da6f77078 | |
Roeland Jansen | b57e4ebd76 | |
Phil Taylor | a1252eec1e | |
Phil Taylor | 29060eb43e | |
Phil Taylor | 209c5a9b0b | |
Phil Taylor | b46dfb8f3e | |
Phil Taylor | d47b9be7e1 | |
Phil Taylor | f7c532007e | |
Phil Taylor | 429aba7d68 | |
Phil Taylor | e49e00c3ad | |
Phil Taylor | bf340e7790 | |
Phil Taylor | 3a07830d47 | |
Phil Taylor | 5ffbfc0f1d | |
Roeland Jansen | 103dc9c86a | |
Phil Taylor | 034ec90662 | |
Phil Taylor | ce9ab6d7ff | |
Phil Taylor | e2338edde6 | |
Phil Taylor | 16dd595f52 | |
Phil Taylor | eb363db09c | |
Phil Taylor | b1b6f26b7d | |
Phil Taylor | 4452e0127b | |
Phil Taylor | b0ebed916c | |
Phil Taylor | 1c8f08a077 | |
Phil Taylor | 91b4ab9f94 | |
Phil Taylor | 75aab75b46 | |
Phil Taylor | d753315c55 | |
Phil Taylor | 6a0997017e | |
Phil Taylor | 6255542ee1 | |
Phil Taylor | a2c348f646 | |
Phil Taylor | ba07c26a2b | |
Phil Taylor | 2dad92b9f6 | |
Phil Taylor | 45c7429c40 | |
Phil Taylor | ecd93b3841 | |
Phil Taylor | 09cd0ba541 | |
Phil Taylor | eff37c586c | |
Phil Taylor | 710566715b | |
Phil Taylor | 358375be8a | |
Phil Taylor | 677eb3c944 | |
Roeland Jansen | 6609aa58d9 | |
Phil Taylor | 3f84e093be | |
Roeland Jansen | ce12135c4a | |
Phil Taylor | 066af2d9b8 | |
Phil Taylor | 3dd1d7bb9a | |
Phil Taylor | cb0ace1a51 | |
Phil Taylor | 5d0f6e82c5 | |
Roeland Jansen | faf5caefa3 | |
Phil Taylor | e15496e0b6 | |
Roeland Jansen | f8cef53a7d | |
Phil Taylor | f4e25d2273 | |
Phil Taylor | 3ec54f1ebb | |
Phil Taylor | 6862009e94 | |
Phil Taylor | b7bcd58578 | |
Phil Taylor | 22abc65849 | |
Phil Taylor | cc6e4d042a | |
Phil Taylor | f7e2631ee3 | |
Phil Taylor | 62d9ec2442 | |
Phil Taylor | fa9cab1374 | |
Phil Taylor | 880a9c3da0 | |
Phil Taylor | b110ce7fbb | |
Phil Taylor | 4d158f5078 | |
Phil Taylor | f31aadd991 | |
Phil Taylor | b011165d5b | |
Phil Taylor | 9fdc09c5be | |
Phil Taylor | 855438e843 | |
Phil Taylor | 711b86e91b | |
Phil Taylor | 9db695cc63 | |
Phil Taylor | 2d58ea2afb | |
Phil Taylor | 4db4510501 | |
Phil Taylor | 3b1efbd69e | |
Phil Taylor | e6713dc516 | |
Phil Taylor | 7d141608bf | |
Roeland Jansen | d5aeec61ba | |
Phil Taylor | f48e65d147 | |
Phil Taylor | e7e7821f2b | |
Phil Taylor | dbc13a0533 | |
Phil Taylor | cef827f7f8 | |
Phil Taylor | f7bde0fe64 | |
Phil Taylor | bbc2613942 | |
Phil Taylor | 0bb57a859d | |
Phil Taylor | 1193841103 | |
Phil Taylor | b3756391c1 | |
Phil Taylor | 242d39ce39 | |
Phil Taylor | 51878e5a3d | |
Phil Taylor | b7af0d4edd | |
Phil Taylor | 518e1700ae | |
Phil Taylor | 87ebd0cdcc | |
Phil Taylor | 08b6224471 | |
Phil Taylor | ac0771f034 | |
Elliott Liggett | 65b4a9cc17 | |
Phil Taylor | 0c530303c7 | |
Phil Taylor | 9d9a817f97 | |
Phil Taylor | d8e244f33a | |
Phil Taylor | 2f35e009e9 | |
Phil Taylor | 31969d0647 | |
Phil Taylor | 722e5b3c35 | |
Phil Taylor | 5ccc2fc375 | |
Phil Taylor | e6506cd55f | |
Phil Taylor | c87dc5ef73 | |
Phil Taylor | 546330e829 | |
Phil Taylor | d1ffbe84f5 | |
Phil Taylor | 4574e2b7b2 | |
Phil Taylor | 62c48ac2c2 | |
Phil Taylor | 05f7283930 | |
Phil Taylor | 30073d07d7 | |
Phil Taylor | 30f9574dd6 | |
Phil Taylor | 22692a6897 | |
Phil Taylor | 647b51449b | |
Phil Taylor | f0cec0279c | |
Phil Taylor | 129348c12f | |
Phil Taylor | 19c16daa06 | |
Phil Taylor | 4f4527bc6b | |
Phil Taylor | e75c4873f0 | |
Phil Taylor | 6043e857e1 | |
Phil Taylor | 11c0973897 | |
Phil Taylor | 2ec20ce18b | |
Phil Taylor | eb85bb1802 | |
Phil Taylor | 7f003c588e | |
Phil Taylor | 41c5637c30 | |
Phil Taylor | 8fc9c48d5c | |
Phil Taylor | 49d1cc085a | |
Phil Taylor | 3ef1950dc2 | |
Phil Taylor | 120bd7d302 | |
Phil Taylor | 45b01cafb3 | |
Phil Taylor | 96037cd055 | |
Phil Taylor | aa002ed0b5 | |
Phil Taylor | 8ee8d23fb9 | |
Phil Taylor | fad416c5f3 | |
Phil Taylor | 360ceccdc6 | |
Phil Taylor | 88ebf74e14 | |
Phil Taylor | 4203b62327 | |
Phil Taylor | 60a1d40549 | |
Phil Taylor | 2a0b79449d | |
Phil Taylor | 7d95f2d863 | |
Phil Taylor | 0d9c7b5e30 | |
Phil Taylor | 4743cd126b | |
Phil Taylor | 9f0673ae71 | |
Phil Taylor | 395469daf3 | |
Phil Taylor | 0647caa640 | |
Phil Taylor | 52070ddbc4 | |
Phil Taylor | b7407fc108 | |
Phil Taylor | cffb2bf93a | |
Phil Taylor | 1b3edbfec1 | |
Phil Taylor | af440fbf55 | |
Phil Taylor | 886b597d56 | |
Phil Taylor | 5e6bab9d57 | |
Phil Taylor | edef09c8bf | |
Phil Taylor | 4bbd06a988 | |
Phil Taylor | a2d7ae0e56 | |
Phil Taylor | 65b4538968 | |
Phil Taylor | 87dc468ae9 | |
Phil Taylor | 445a4157b7 | |
Phil Taylor | 20f3e70d2a | |
Phil Taylor | 27e8577efe | |
Phil Taylor | eb81196238 | |
Phil Taylor | be979108e8 | |
Phil Taylor | 725914d045 | |
Phil Taylor | 389ea9c831 | |
Phil Taylor | 1f1e489cf3 | |
Phil Taylor | 8fb894f076 | |
Phil Taylor | 133fb1cf32 | |
Phil Taylor | 24133a4f70 | |
Phil Taylor | 7e40f7faf0 | |
Phil Taylor | b5676b7773 | |
Phil Taylor | a0c6243528 | |
Phil Taylor | 62eef7f0f4 | |
Phil Taylor | f9bc4e3122 | |
Phil Taylor | 28ba131135 | |
Phil Taylor | 4704b0dc4d | |
Phil Taylor | 7603201886 | |
Phil Taylor | 871c7106b6 | |
Phil Taylor | ec12e31163 | |
Phil Taylor | 1cbf77ade0 | |
Phil Taylor | d877efd234 | |
Phil Taylor | 0366d5ccb4 | |
Phil Taylor | 3f23b0fdb4 | |
Phil Taylor | 942866ee65 | |
Phil Taylor | 4483a252b6 | |
Phil Taylor | 14f78c1b36 | |
Phil Taylor | ccebdb6840 | |
Phil Taylor | 8b975218d5 | |
Phil Taylor | e271c29c41 | |
Phil Taylor | 70df0ecfd9 | |
Phil Taylor | ef3beecc64 | |
M0VSE | 4159e535fc | |
Phil Taylor | fbf28be5db | |
Phil Taylor | 05b8fe5f7c | |
Phil Taylor | 7b9a911079 | |
Phil Taylor | 6f6bf3387f | |
Phil Taylor | 8a16b467dc | |
Phil Taylor | 84a4e7c871 | |
Phil Taylor | 8037dac05e | |
Phil Taylor | acbbd40c37 |
|
@ -7,4 +7,6 @@ wfview-debug
|
|||
wfserver-debug
|
||||
wfview-release
|
||||
wfserver-release
|
||||
ui_*
|
||||
ui_*
|
||||
portaudio_x86.dll
|
||||
qcustomplot2.dll
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
|
||||
|
||||
|
||||
|
||||
## this is a merged list of CI-V addresses, type of interface(s), rates and all.
|
||||
|
||||
It has been merged from many sources but the most important ones are these:
|
||||
|
||||
1) https://www.docksideradio.com/Icom%20Radio%20Hex%20Addresses.htm
|
||||
2) http://www.plicht.de/ci-v/civ-bus-adressing/
|
||||
3) https://www.icomjapan.com/support/manual/
|
||||
|
||||
|
||||
|
||||
first of all a list that appears not to be a known CI-V address in use:
|
||||
|
||||
| model | addr |
|
||||
| ----- | ---- |
|
||||
|? | 0x06 |
|
||||
|? | 0x36 |
|
||||
|? | 0x54 |
|
||||
|? | 0x7E |
|
||||
|? | 0x82 |
|
||||
|? | 0x84 |
|
||||
|? | 0x8A |
|
||||
|? | 0x90 |
|
||||
|? | 0x92 |
|
||||
|? | 0x9E |
|
||||
|? | 0xA0 |
|
||||
|? | 0xA8 |
|
||||
|? | 0xAA |
|
||||
|
||||
|
||||
|
||||
and here the list of known CI-V addresses
|
||||
|
||||
|
||||
|
||||
| model | addr | year | interface | rate |
|
||||
| ------------ | ---- | ---- | -------------------------------------- | ---- |
|
||||
| IC-1271 | 0x24 | 1987 | TTL | auto |
|
||||
| IC-1275 | 0x18 | 1989 | TTL | auto |
|
||||
| IC-271 | 0x20 | 1983 | TTL | auto |
|
||||
| IC-275 | 0x10 | 1987 | TTL | auto |
|
||||
| IC-375 | 0x12 | 198? | TTL | auto |
|
||||
| IC-471 | 0x22 | 1984 | TTL | auto |
|
||||
| IC-475 | 0x14 | 1987 | TTL | auto |
|
||||
| IC-575 | 0x16 | 1988 | TTL | auto |
|
||||
| IC-7000 | 0x70 | 2005 | TTL | auto |
|
||||
| IC-703 | 0x68 | 2003 | TTL | auto |
|
||||
| IC-705 | 0xA4 | 2020 | USB, Bluetooth, Wifi | auto |
|
||||
| IC-706 | 0x48 | 1995 | TTL | auto |
|
||||
| IC-706MkII | 0x4E | 1997 | TTL | auto |
|
||||
| IC-706MkII-G | 0x58 | 1998 | TTL | auto |
|
||||
| IC-707 | 0x3E | 1993 | TTL | auto |
|
||||
| IC-7100 | 0x88 | 2012 | TTL | auto |
|
||||
| IC-718 | 0x5E | 2001 | TTL | auto |
|
||||
| IC-7200 | 0x76 | 2007 | TTL | auto |
|
||||
| IC-725 | 0x28 | 1988 | TTL | 1200 |
|
||||
| IC-726 | 0x30 | 1989 | TTL | auto |
|
||||
| IC-728 | 0x38 | 1992 | TTL | 1200 |
|
||||
| IC-729 | 0x3A | 1992 | TTL | 9600 |
|
||||
| IC-7300 | 0x94 | 2016 | TTL, USB | auto |
|
||||
| IC-735 | 0x04 | 1985 | TTL | 1200 |
|
||||
| IC-736 | 0x40 | 1994 | TTL | 9600 |
|
||||
| IC-737 | 0x3C | 1993 | TTL | 9600 |
|
||||
| IC-738 | 0x44 | 1994 | TTL | 9600 |
|
||||
| IC-7410 | 0x80 | 2011 | TTL, USB | auto |
|
||||
| IC-746 | 0x56 | 1998 | TTL | auto |
|
||||
| IC-746Pro | 0x66 | 2001 | TTL | auto |
|
||||
| IC-751A | 0x1C | 1985 | TTL | 1200 |
|
||||
| IC-756 | 0x50 | 1997 | TTL | auto |
|
||||
| IC-756Pro | 0x5C | 2000 | TTL | auto |
|
||||
| IC-756ProII | 0x64 | 2001 | TTL | auto |
|
||||
| IC-756ProIII | 0x6E | 2004 | TTL | auto |
|
||||
| IC-7600 | 0x7A | 2009 | TTL, USB | auto |
|
||||
| IC-7610 | 0x98 | 2017 | TTL, USB, Ethernet | auto |
|
||||
| IC-761 | 0x1E | 1987 | TTL | 1200 |
|
||||
| IC-765 | 0x2C | 1989 | TTL | 1200 |
|
||||
| IC-7700 | 0x74 | 2007 | TTL, RS-232C 9 pin, Ethernet | auto |
|
||||
| IC-775 | 0x46 | 1995 | TTL | auto |
|
||||
| IC-7800 | 0x6A | 2004 | TTL, RS-232C 9 pin, Ethernet | auto |
|
||||
| IC-78 | 0x62 | 2000 | TTL | auto |
|
||||
| IC-781 | 0x26 | 1987 | TTL | 1200 |
|
||||
| IC-785x | 0x8E | 2015 | TTL, USB, Ethernet | auto |
|
||||
| IC-820 | 0x42 | 1994 | TTL | auto |
|
||||
| IC-821 | 0x4C | 1996 | TTL | auto |
|
||||
| IC-905 | 0xAC | 2023 | USB, Ethernet | auto |
|
||||
| IC-9100 | 0x7C | 2010 | TTL, USB | auto |
|
||||
| IC-910 | 0x60 | 2001 | TTL | auto |
|
||||
| IC-9700 | 0xA2 | 2019 | TTL, USB, Ethernet | auto |
|
||||
| IC-970 | 0x2E | 1990 | TTL | auto |
|
||||
| IC-R10 | 0x52 | 1996 | TTL | auto |
|
||||
| IC-R20 | 0x6C | 2004 | TTL | auto |
|
||||
| IC-R30 | 0x9C | 2018 | TTL, Bluetooth | auto |
|
||||
| IC-R7000 | 0x08 | 1986 | TTL | auto |
|
||||
| IC-R7100 | 0x34 | 1991 | TTL | auto |
|
||||
| IC-R71 | 0x1A | 1984 | TTL | auto |
|
||||
| IC-R72 | 0x32 | 1992 | TTL | auto |
|
||||
| IC-R75 | 0x5A | 1999 | TTL, RS-232C 9 pin | auto |
|
||||
| IC-R8500 | 0x4A | 1996 | TTL, RS-232C 25 pin | auto |
|
||||
| IC-R8600 | 0x96 | 2017 | TTL, USB, Ethernet | auto |
|
||||
| IC-R9000 | 0x2A | 1989 | TTL | auto |
|
||||
| IC-R9500 | 0x72 | 2007 | TTL, RS-232C 9 pin, Ethernet | auto |
|
||||
| IC-RX7 | 0x78 | 2007 | TTL | auto |
|
||||
| ID-4100 | 0x9A | 2017 | TTL, Bluetooth | auto |
|
||||
| ID-5100 | 0x8C | 2014 | TTL, Bluetooth | auto |
|
||||
| ID-51 | 0x86 | 2012 | TTL | auto |
|
||||
| ID-52 | 0xA6 | 2021 | TTL, Bluetooth | auto |
|
34
INSTALL.md
|
@ -17,6 +17,8 @@ sudo apt-get install libopus-dev
|
|||
sudo apt-get install libeigen3-dev
|
||||
sudo apt-get install portaudio19-dev
|
||||
sudo apt-get install librtaudio-dev
|
||||
sudo apt-get install libhidapi-dev libqt5gamepad5-dev
|
||||
sudo apt-get install libudev-dev
|
||||
~~~
|
||||
Now you need to install qcustomplot. There are two versions that are commonly found in linux distros: 1.3 and 2.0. Either will work fine. If you are not sure which version your linux install comes with, simply run both commands. One will work and the other will fail, and that's fine!
|
||||
|
||||
|
@ -78,7 +80,7 @@ install wfview on suse 15.3 & up, sles 15.x or tumbleweed; this was done on a cl
|
|||
we need to add packages to be able to build the stuff.
|
||||
|
||||
- sudo zypper in --type pattern devel_basis
|
||||
- sudo zypper in libQt5Widgets-devel libqt5-qtbase-common-devel libqt5-qtserialport-devel libQt5SerialPort5 qcustomplot-devel libqcustomplot2 libQt5PrintSupport-devel libqt5-qtmultimedia-devel lv2-devel libopus-devel eigen3-devel
|
||||
- sudo zypper in libQt5Widgets-devel libqt5-qtbase-common-devel libqt5-qtserialport-devel libQt5SerialPort5 qcustomplot-devel libqcustomplot2 libQt5PrintSupport-devel libqt5-qtmultimedia-devel lv2-devel libopus-devel eigen3-devel libQt5Xml-devel portaudio-devel rtaudio-devel libqt5-qtgamepad-devel libQt5Gamepad5
|
||||
|
||||
optional (mainly for development specifics): get and install qt5:
|
||||
|
||||
|
@ -127,4 +129,34 @@ When done, create a build area, clone the repo, build and install:
|
|||
|
||||
wfview is now installed in /usr/local/bin
|
||||
|
||||
|
||||
Fedora 36:
|
||||
|
||||
2023-04-11/Knud OZ1DGN
|
||||
|
||||
|
||||
Precondition:
|
||||
|
||||
F36 KDE plasma desktop
|
||||
wfview 1.61 prebuild binary
|
||||
|
||||
Install following packages:
|
||||
sudo dnf install qcustomplot-qt5 qt5-qtmultimedia qt5-qtserialport rtaudio portaudio hidapi qt5-qtgamepad
|
||||
|
||||
sudo ln -s /usr/lib64/libqcustomplot-qt5.so.2 /usr/lib64/libqcustomplot.so.2
|
||||
|
||||
Move /usr/share/wfview to /usr/local/share:
|
||||
|
||||
sudo mv /usr/share/wfview/stylesheets/* /usr/local/share/wfview
|
||||
|
||||
|
||||
|
||||
# How to configure your RC-28 knob under Linux
|
||||
|
||||
To use RC-28 knob you need to add udev rules, please execute as root:
|
||||
|
||||
~~~
|
||||
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="0c26", ATTRS{idProduct}=="001e", MODE="0666"' >> /etc/udev/rules.d/99-ham-wfview.rules
|
||||
udevadm control --reload-rules && udevadm trigger
|
||||
~~~
|
||||
---
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
this file contains known limits and things that maybe needs fixing..
|
||||
|
||||
|
||||
7851
|
||||
|
||||
repeater controls:
|
||||
|
||||
|
||||
- quick split does not work correct?
|
||||
- split does not work correct?
|
||||
- M <--> S "change" works
|
||||
- M => S "M = S" works
|
||||
- autotrack "track" works but is slow?
|
||||
|
54
WHATSNEW
|
@ -1,52 +1,12 @@
|
|||
|
||||
The following highlights are in this 1.41-release:
|
||||
The following highlights are in this 1.6x-release since v1.60:
|
||||
|
||||
New major change is the audio transport mechanism. Lower latencies.
|
||||
About box updated to include Patreon site
|
||||
added 500 Hz step for VFO
|
||||
Added clock and UTC toggle.
|
||||
Added forced manual RTS setting
|
||||
Add RIT function and other rigctl fixes
|
||||
Adjusted window size for radios without spectrum. Thanks K5TUX.
|
||||
Allow dynamic restarting of server
|
||||
New Settings tab
|
||||
Enable High DPI Scaling
|
||||
More multi-radio support (mostly working!)
|
||||
Split LAN waterfall data for N1MM+ Spectrum Scope support: There is a combobox that allows you to select
|
||||
split/combine (or default). Split only makes sense for LAN and Combine for USB.
|
||||
added radio status display with meters for audio (speaker/mic)
|
||||
selector for audio: QT, PortAudio, RealTime audio
|
||||
version bumped to 1.4 -- rethinking of a new version schema that makes more sense
|
||||
temporary squashed logs; may redo later
|
||||
audio fixes at exit
|
||||
introduction of peak decays at the scope
|
||||
resizing of top and bottom scope/waterfall
|
||||
various fixes on the spectrum display
|
||||
+ 1.41 added color picker support for all kinds of vsual elements
|
||||
+ 1.42 added three additional second meter choices. RxAudio, TxAdio, and TxRxAudio
|
||||
+ 1.43 fixed resizing issues.
|
||||
+ 1.44 added logging window. you can send the logs to termbin.com and share the link on the forum
|
||||
+ 1.45 some more log enhancements
|
||||
moved connect button and added cancel option
|
||||
add enable/disable audioSystemServerCombo
|
||||
Fixed bug where the frequency dial skipped extra when crossing zero.
|
||||
+ 1.46 Added controls for custom scope edges, hide/show scope controls
|
||||
depending upon the scope mode the radio reports.
|
||||
Fixed clear peaks button to work with the plasma underlay.
|
||||
both audio system button are disabled when connected to radio and enabled when not.
|
||||
Remove password from log
|
||||
Fix server user handling
|
||||
+ 1.47 Added dialog box to the toFixed button where an edge can be selected.
|
||||
Fix that was stopping users being created when none existed
|
||||
compound fmv command (rigctl(d)) added
|
||||
+ 1.48 Fixed glitch when tabs are changed prior to rigcaps.
|
||||
Additional resize fixes for non-spectrum rigs.
|
||||
Hide UI elements not needed for non-spectrum radios.
|
||||
Fix that was stopping users being created when none existed
|
||||
Use date/time for log name if none specified
|
||||
Fix logfile/directory opening in Windows
|
||||
Remove redundant CL args
|
||||
Delete quit confirmation checkbox
|
||||
+1.60 released
|
||||
+1.61 many small fixes for several platforms
|
||||
+1.62 cw side tone added
|
||||
performance fix for 9700
|
||||
+1.63 started adding IC-905 (obviously untested)
|
||||
started multi-usb
|
||||
|
||||
Notes:
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@ aboutbox::aboutbox(QWidget *parent) :
|
|||
ui->topText->setText("wfview version " + QString(WFVIEW_VERSION));
|
||||
|
||||
QString head = QString("<html><head></head><body>");
|
||||
QString copyright = QString("Copyright 2017-2022 Elliott H. Liggett, W6EL. All rights reserved.<br/>wfview source code is <a href=\"https://gitlab.com/eliggett/wfview/-/blob/master/LICENSE\">licensed</a> under the GNU GPLv3.");
|
||||
QString nacode = QString("<br/><br/>Networking, audio, rigctl server, and much more written by Phil Taylor, M0VSE");
|
||||
QString copyright = QString("Copyright 2017-2023 Elliott H. Liggett, W6EL and Phil E. Taylor, M0VSE. All rights reserved.<br/>wfview source code is <a href=\"https://gitlab.com/eliggett/wfview/-/blob/master/LICENSE\">licensed</a> under the GNU GPLv3.");
|
||||
QString scm = QString("<br/><br/>Source code and issues managed by Roeland Jansen, PA3MET");
|
||||
QString doctest = QString("<br/><br/>Testing and development mentorship from Jim Nijkamp, PA8E.");
|
||||
|
||||
|
@ -86,7 +85,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.");
|
|||
|
||||
// String it all together:
|
||||
|
||||
QString aboutText = head + copyright + "\n" + nacode + "\n" + scm + "\n" + doctest + dedication + wfviewcommunityack;
|
||||
QString aboutText = head + copyright + "\n" + "\n" + scm + "\n" + doctest + dedication + wfviewcommunityack;
|
||||
aboutText.append(website + "\n" + donate + "\n"+ docs + support + contact +"\n");
|
||||
aboutText.append("\n" + ssCredit + "\n" + rsCredit + "\n");
|
||||
|
||||
|
|
|
@ -6,33 +6,41 @@ audioConverter::audioConverter(QObject* parent) : QObject(parent)
|
|||
{
|
||||
}
|
||||
|
||||
bool audioConverter::init(QAudioFormat inFormat, QAudioFormat outFormat, quint8 opusComplexity, quint8 resampleQuality)
|
||||
bool audioConverter::init(QAudioFormat inFormat, codecType inCodec, QAudioFormat outFormat, codecType outCodec, quint8 opusComplexity, quint8 resampleQuality)
|
||||
{
|
||||
|
||||
this->inFormat = inFormat;
|
||||
this->outFormat = outFormat;
|
||||
this->opusComplexity = opusComplexity;
|
||||
this->inCodec = inCodec;
|
||||
this->outFormat = outFormat;
|
||||
this->outCodec = outCodec;
|
||||
this->opusComplexity = opusComplexity;
|
||||
this->resampleQuality = resampleQuality;
|
||||
|
||||
qInfo(logAudioConverter) << "Starting audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inFormat.codec() << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outFormat.codec() << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qInfo(logAudioConverter) << "Starting audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
|
||||
|
||||
if (inFormat.byteOrder() != outFormat.byteOrder()) {
|
||||
if (inFormat.byteOrder() != outFormat.byteOrder()) {
|
||||
qInfo(logAudioConverter) << "Byteorder mismatch in:" << inFormat.byteOrder() << "out:" << outFormat.byteOrder();
|
||||
}
|
||||
#else
|
||||
qInfo(logAudioConverter) << "Starting audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleFormat() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleFormat();
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
if (inFormat.codec() == "audio/opus")
|
||||
{
|
||||
// Create instance of opus decoder
|
||||
int opus_err = 0;
|
||||
opusDecoder = opus_decoder_create(inFormat.sampleRate(), inFormat.channelCount(), &opus_err);
|
||||
qInfo(logAudioConverter()) << "Creating opus decoder: " << opus_strerror(opus_err);
|
||||
}
|
||||
if (inCodec == OPUS)
|
||||
{
|
||||
// Create instance of opus decoder
|
||||
int opus_err = 0;
|
||||
opusDecoder = opus_decoder_create(inFormat.sampleRate(), inFormat.channelCount(), &opus_err);
|
||||
qInfo(logAudioConverter()) << "Creating opus decoder: " << opus_strerror(opus_err);
|
||||
}
|
||||
|
||||
if (outFormat.codec() == "audio/opus")
|
||||
{
|
||||
// Create instance of opus encoder
|
||||
if (outCodec == OPUS)
|
||||
{
|
||||
// Create instance of opus encoder
|
||||
int opus_err = 0;
|
||||
opusEncoder = opus_encoder_create(outFormat.sampleRate(), outFormat.channelCount(), OPUS_APPLICATION_AUDIO, &opus_err);
|
||||
//opus_encoder_ctl(opusEncoder, OPUS_SET_LSB_DEPTH(16));
|
||||
|
@ -60,8 +68,13 @@ bool audioConverter::init(QAudioFormat inFormat, QAudioFormat outFormat, quint8
|
|||
audioConverter::~audioConverter()
|
||||
{
|
||||
|
||||
qInfo(logAudioConverter) << "Closing audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inFormat.codec() << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outFormat.codec() << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qInfo(logAudioConverter) << "Closing audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleType() << inFormat.sampleSize() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleType() << outFormat.sampleSize();
|
||||
#else
|
||||
qInfo(logAudioConverter) << "Closing audioConverter() Input:" << inFormat.channelCount() << "Channels of" << inCodec << inFormat.sampleRate() << inFormat.sampleFormat() <<
|
||||
"Output:" << outFormat.channelCount() << "Channels of" << outCodec << outFormat.sampleRate() << outFormat.sampleFormat();
|
||||
#endif
|
||||
|
||||
if (opusEncoder != Q_NULLPTR) {
|
||||
qInfo(logAudioConverter()) << "Destroying opus encoder";
|
||||
|
@ -87,7 +100,7 @@ bool audioConverter::convert(audioPacket audio)
|
|||
if (audio.data.size() > 0)
|
||||
{
|
||||
|
||||
if (inFormat.codec() == "audio/opus")
|
||||
if (inCodec == OPUS)
|
||||
{
|
||||
unsigned char* in = (unsigned char*)audio.data.data();
|
||||
|
||||
|
@ -100,17 +113,15 @@ bool audioConverter::convert(audioPacket audio)
|
|||
QByteArray outPacket(nSamples * sizeof(float) * inFormat.channelCount(), (char)0xff); // Preset the output buffer size.
|
||||
float* out = (float*)outPacket.data();
|
||||
|
||||
//if (audio.seq > lastAudioSequence + 1) {
|
||||
// nSamples = opus_decode_float(opusDecoder, Q_NULLPTR, 0, out, nSamples, 1);
|
||||
//}
|
||||
//else {
|
||||
nSamples = opus_decode_float(opusDecoder, in, audio.data.size(), out, nSamples, 0);
|
||||
//}
|
||||
//lastAudioSequence = audio.seq;
|
||||
int ret = opus_decode_float(opusDecoder, in, audio.data.size(), out, nSamples, 0);
|
||||
if (ret != nSamples)
|
||||
{
|
||||
qDebug(logAudio()) << "opus_decode_float: returned:" << ret << "samples, expected:" << nSamples;
|
||||
}
|
||||
audio.data.clear();
|
||||
audio.data = outPacket; // Replace incoming data with converted.
|
||||
}
|
||||
else if (inFormat.codec() == "audio/PCMU")
|
||||
else if (inCodec == PCMU)
|
||||
{
|
||||
// Current packet is "technically" 8bit so need to create a new buffer that is 16bit
|
||||
QByteArray outPacket((int)audio.data.length() * 2, (char)0xff);
|
||||
|
@ -125,33 +136,49 @@ bool audioConverter::convert(audioPacket audio)
|
|||
}
|
||||
|
||||
Eigen::VectorXf samplesF;
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 32)
|
||||
#else
|
||||
if (inFormat.sampleFormat() == QAudioFormat::Int32)
|
||||
#endif
|
||||
{
|
||||
Eigen::Ref<VectorXint32> samplesI = Eigen::Map<VectorXint32>(reinterpret_cast<qint32*>(audio.data.data()), audio.data.size() / int(sizeof(qint32)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint32>::max());
|
||||
}
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
else if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 16)
|
||||
#else
|
||||
else if (inFormat.sampleFormat() == QAudioFormat::Int16)
|
||||
#endif
|
||||
{
|
||||
Eigen::Ref<VectorXint16> samplesI = Eigen::Map<VectorXint16>(reinterpret_cast<qint16*>(audio.data.data()), audio.data.size() / int(sizeof(qint16)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint16>::max());
|
||||
}
|
||||
else if (inFormat.sampleType() == QAudioFormat::SignedInt && inFormat.sampleSize() == 8)
|
||||
{
|
||||
Eigen::Ref<VectorXint8> samplesI = Eigen::Map<VectorXint8>(reinterpret_cast<qint8*>(audio.data.data()), audio.data.size() / int(sizeof(qint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<qint8>::max());;
|
||||
}
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
else if (inFormat.sampleType() == QAudioFormat::UnSignedInt && inFormat.sampleSize() == 8)
|
||||
#else
|
||||
else if (inFormat.sampleFormat() == QAudioFormat::UInt8)
|
||||
#endif
|
||||
{
|
||||
Eigen::Ref<VectorXuint8> samplesI = Eigen::Map<VectorXuint8>(reinterpret_cast<quint8*>(audio.data.data()), audio.data.size() / int(sizeof(quint8)));
|
||||
samplesF = samplesI.cast<float>() / float(std::numeric_limits<quint8>::max());;
|
||||
}
|
||||
else if (inFormat.sampleType() == QAudioFormat::Float) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
else if (inFormat.sampleType() == QAudioFormat::Float)
|
||||
#else
|
||||
else if (inFormat.sampleFormat() == QAudioFormat::Float)
|
||||
#endif
|
||||
{
|
||||
|
||||
samplesF = Eigen::Map<Eigen::VectorXf>(reinterpret_cast<float*>(audio.data.data()), audio.data.size() / int(sizeof(float)));
|
||||
}
|
||||
else
|
||||
{
|
||||
qInfo(logAudio()) << "Unsupported Input Sample Type:" << inFormat.sampleType() << "Size:" << inFormat.sampleSize();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qInfo(logAudio()) << "Unsupported Input Sample Type:" << inFormat.sampleType() << "Size:" << inFormat.sampleSize();
|
||||
#else
|
||||
qInfo(logAudio()) << "Unsupported Input Sample Format:" << inFormat.sampleFormat();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (samplesF.size() > 0)
|
||||
|
@ -218,7 +245,7 @@ bool audioConverter::convert(audioPacket audio)
|
|||
If output is Opus so encode it now, don't do any more conversion on the output of Opus.
|
||||
*/
|
||||
|
||||
if (outFormat.codec() == "audio/opus")
|
||||
if (outCodec == OPUS)
|
||||
{
|
||||
float* in = (float*)samplesF.data();
|
||||
QByteArray outPacket(1275, (char)0xff); // Preset the output buffer size to MAXIMUM possible Opus frame size
|
||||
|
@ -246,45 +273,58 @@ bool audioConverter::convert(audioPacket audio)
|
|||
*/
|
||||
audio.data.clear();
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (outFormat.sampleType() == QAudioFormat::UnSignedInt && outFormat.sampleSize() == 8)
|
||||
#else
|
||||
if (outFormat.sampleFormat() == QAudioFormat::UInt8)
|
||||
#endif
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint8>::max());
|
||||
samplesITemp.array() += 127;
|
||||
VectorXuint8 samplesI = samplesITemp.cast<quint8>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(quint8)));
|
||||
}
|
||||
else if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 8)
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint8>::max());
|
||||
VectorXint8 samplesI = samplesITemp.cast<qint8>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint8)));
|
||||
}
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
else if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 16)
|
||||
#else
|
||||
else if (outFormat.sampleFormat() == QAudioFormat::Int16)
|
||||
#endif
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint16>::max());
|
||||
VectorXint16 samplesI = samplesITemp.cast<qint16>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint16)));
|
||||
}
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
else if (outFormat.sampleType() == QAudioFormat::SignedInt && outFormat.sampleSize() == 32)
|
||||
#else
|
||||
else if (outFormat.sampleFormat() == QAudioFormat::Int32)
|
||||
#endif
|
||||
{
|
||||
Eigen::VectorXf samplesITemp = samplesF * float(std::numeric_limits<qint32>::max());
|
||||
VectorXint32 samplesI = samplesITemp.cast<qint32>();
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesI.data()), int(samplesI.size()) * int(sizeof(qint32)));
|
||||
}
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
else if (outFormat.sampleType() == QAudioFormat::Float)
|
||||
#else
|
||||
else if (outFormat.sampleFormat() == QAudioFormat::Float)
|
||||
#endif
|
||||
{
|
||||
audio.data = QByteArray(reinterpret_cast<char*>(samplesF.data()), int(samplesF.size()) * int(sizeof(float)));
|
||||
}
|
||||
else {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qInfo(logAudio()) << "Unsupported Output Sample Type:" << outFormat.sampleType() << "Size:" << outFormat.sampleSize();
|
||||
#else
|
||||
qInfo(logAudio()) << "Unsupported Output Sample Type:" << outFormat.sampleFormat();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
As we currently don't have a float based uLaw encoder, this must be done
|
||||
after all other conversion has taken place.
|
||||
*/
|
||||
|
||||
if (outFormat.codec() == "audio/PCMU")
|
||||
if (outCodec == PCMU)
|
||||
{
|
||||
QByteArray outPacket((int)audio.data.length() / 2, (char)0xff);
|
||||
qint16* in = (qint16*)audio.data.data();
|
||||
|
|
|
@ -6,7 +6,17 @@
|
|||
#include <QMap>
|
||||
#include <QDebug>
|
||||
#include <QAudioFormat>
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioInput>
|
||||
#include <QAudioOutput>
|
||||
#else
|
||||
#include <QMediaDevices>
|
||||
#include <QAudioDevice>
|
||||
#include <QAudioSource>
|
||||
#include <QAudioSink>
|
||||
#endif
|
||||
|
||||
/* Opus and Eigen */
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -17,7 +27,7 @@
|
|||
#include <eigen3/Eigen/Eigen>
|
||||
#endif
|
||||
|
||||
enum audioType {qtAudio,portAudio,rtAudio};
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
#include "resampler/speex_resampler.h"
|
||||
|
||||
|
@ -42,7 +52,11 @@ struct audioSetup {
|
|||
bool ulaw = false;
|
||||
bool isinput;
|
||||
quint32 sampleRate;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
QAudioDeviceInfo port;
|
||||
#else
|
||||
QAudioDevice port;
|
||||
#endif
|
||||
int portInt;
|
||||
quint8 resampleQuality;
|
||||
unsigned char localAFgain;
|
||||
|
@ -59,7 +73,7 @@ public:
|
|||
~audioConverter();
|
||||
|
||||
public slots:
|
||||
bool init(QAudioFormat inFormat, QAudioFormat outFormat, quint8 opusComplexity, quint8 resampleQuality);
|
||||
bool init(QAudioFormat inFormat, codecType inCodec, QAudioFormat outFormat, codecType outCodec, quint8 opusComplexity, quint8 resampleQuality);
|
||||
bool convert(audioPacket audio);
|
||||
|
||||
signals:
|
||||
|
@ -75,6 +89,8 @@ protected:
|
|||
quint8 resampleQuality = 4;
|
||||
double resampleRatio=1.0; // Default resample ratio is 1:1
|
||||
quint32 lastAudioSequence;
|
||||
codecType inCodec;
|
||||
codecType outCodec;
|
||||
};
|
||||
|
||||
|
||||
|
@ -99,21 +115,31 @@ static inline QAudioFormat toQAudioFormat(quint8 codec, quint32 sampleRate)
|
|||
0x40 Opus 1ch
|
||||
0x80 Opus 2ch
|
||||
*/
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setCodec("audio/pcm");
|
||||
#endif
|
||||
|
||||
format.setSampleRate(sampleRate);
|
||||
|
||||
if (codec == 0x01 || codec == 0x20) {
|
||||
/* Set sample to be what is expected by the encoder and the output of the decoder */
|
||||
format.setSampleSize(16);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
format.setCodec("audio/PCMU");
|
||||
}
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
format.setSampleSize(16);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
format.setCodec("audio/PCMU");
|
||||
#else
|
||||
format.setSampleFormat(QAudioFormat::Int16);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (codec == 0x02 || codec == 0x08) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
format.setSampleSize(8);
|
||||
format.setSampleType(QAudioFormat::UnSignedInt);
|
||||
#else
|
||||
format.setSampleFormat(QAudioFormat::UInt8);
|
||||
#endif
|
||||
}
|
||||
if (codec == 0x08 || codec == 0x10 || codec == 0x20 || codec == 0x80) {
|
||||
format.setChannelCount(2);
|
||||
|
@ -122,14 +148,22 @@ static inline QAudioFormat toQAudioFormat(quint8 codec, quint32 sampleRate)
|
|||
}
|
||||
|
||||
if (codec == 0x04 || codec == 0x10) {
|
||||
format.setSampleSize(16);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
format.setSampleSize(16);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
#else
|
||||
format.setSampleFormat(QAudioFormat::Int16);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (codec == 0x40 || codec == 0x80) {
|
||||
format.setSampleSize(32);
|
||||
format.setSampleType(QAudioFormat::Float);
|
||||
format.setCodec("audio/opus");
|
||||
if (codec == 0x40 || codec == 0x80) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
format.setSampleSize(32);
|
||||
format.setSampleType(QAudioFormat::Float);
|
||||
format.setCodec("audio/opus");
|
||||
#else
|
||||
format.setSampleFormat(QAudioFormat::Float);
|
||||
#endif
|
||||
}
|
||||
|
||||
return format;
|
||||
|
|
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
wfview class to enumerate audio devices and assist with matching saved devices
|
||||
|
||||
Written by Phil Taylor M0VSE Nov 2022.
|
||||
|
||||
*/
|
||||
|
||||
#include "audiodevices.h"
|
||||
#include "logcategories.h"
|
||||
|
||||
audioDevices::audioDevices(audioType type, QFontMetrics fm, QObject* parent) :
|
||||
QObject(parent),
|
||||
system(type),
|
||||
fm(fm)
|
||||
{
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
connect(&mediaDevices, &QMediaDevices::audioInputsChanged, this, &audioDevices::enumerate);
|
||||
connect(&mediaDevices, &QMediaDevices::audioOutputsChanged, this, &audioDevices::enumerate);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void audioDevices::enumerate()
|
||||
{
|
||||
numInputDevices = 0;
|
||||
numOutputDevices = 0;
|
||||
numCharsIn = 0;
|
||||
numCharsOut = 0;
|
||||
inputs.clear();
|
||||
outputs.clear();
|
||||
|
||||
switch (system)
|
||||
{
|
||||
case qtAudio:
|
||||
{
|
||||
Pa_Terminate();
|
||||
|
||||
qInfo(logAudio()) << "Audio device(s) found (*=default)";
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
foreach(const QAudioDeviceInfo & deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
|
||||
#else
|
||||
const auto audioInputs = mediaDevices.audioInputs();
|
||||
for (const QAudioDevice& deviceInfo : audioInputs)
|
||||
#endif
|
||||
{
|
||||
bool isDefault = false;
|
||||
if (numInputDevices == 0) {
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
defaultInputDeviceName = QString(deviceInfo.deviceName());
|
||||
#else
|
||||
defaultInputDeviceName = QString(deviceInfo.description());
|
||||
#endif
|
||||
}
|
||||
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
if (deviceInfo.realm() == audioApi || audioApi == "") {
|
||||
#endif
|
||||
/* Append Input Device Here */
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (deviceInfo.deviceName() == defaultInputDeviceName) {
|
||||
#else
|
||||
if (deviceInfo.description() == defaultInputDeviceName) {
|
||||
#endif
|
||||
isDefault = true;
|
||||
}
|
||||
|
||||
#if ((QT_VERSION >= QT_VERSION_CHECK(5,15,0)) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
inputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, deviceInfo.realm(), isDefault));
|
||||
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultInputDeviceName ? "*" : " ") <<
|
||||
"(" << numInputDevices <<" " << deviceInfo.realm() << ") Input Device : " <<
|
||||
deviceInfo.deviceName();
|
||||
#elif (QT_VERSION < QT_VERSION_CHECK(5,15,0))
|
||||
inputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, "", isDefault));
|
||||
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultInputDeviceName ? "*" : " ") <<
|
||||
"(" << numInputDevices << ") Input Device : " << deviceInfo.deviceName();
|
||||
#else
|
||||
inputs.append(new audioDevice(deviceInfo.description(), deviceInfo, "", isDefault));
|
||||
qInfo(logAudio()) << (deviceInfo.description() == defaultInputDeviceName ? "*" : " ") <<
|
||||
"(" << numInputDevices << ") Input Device : " << deviceInfo.description();
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_WFSERVER
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (fm.boundingRect(deviceInfo.deviceName()).width() > numCharsIn)
|
||||
numCharsIn = fm.boundingRect(deviceInfo.deviceName()).width();
|
||||
#else
|
||||
if (fm.boundingRect(deviceInfo.description()).width() > numCharsIn)
|
||||
numCharsIn = fm.boundingRect(deviceInfo.description()).width();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
}
|
||||
#endif
|
||||
numInputDevices++;
|
||||
}
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
foreach(const QAudioDeviceInfo & deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
|
||||
#else
|
||||
const auto audioOutputs = mediaDevices.audioOutputs();
|
||||
for (const QAudioDevice& deviceInfo : audioOutputs)
|
||||
#endif
|
||||
{
|
||||
bool isDefault = false;
|
||||
if (numOutputDevices == 0)
|
||||
{
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
defaultOutputDeviceName = QString(deviceInfo.deviceName());
|
||||
#else
|
||||
defaultOutputDeviceName = QString(deviceInfo.description());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
if (deviceInfo.realm() == "wasapi") {
|
||||
#endif
|
||||
/* Append Output Device Here */
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (deviceInfo.deviceName() == defaultOutputDeviceName) {
|
||||
#else
|
||||
if (deviceInfo.description() == defaultOutputDeviceName) {
|
||||
#endif
|
||||
isDefault = true;
|
||||
}
|
||||
|
||||
#if ((QT_VERSION >= QT_VERSION_CHECK(5,15,0)) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
outputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, deviceInfo.realm() , isDefault));
|
||||
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultOutputDeviceName ? "*" : " ") <<
|
||||
"(" << numOutputDevices << " " << deviceInfo.realm() << ") Output Device : " <<
|
||||
deviceInfo.deviceName();
|
||||
#elif (QT_VERSION < QT_VERSION_CHECK(5,15,0))
|
||||
outputs.append(new audioDevice(deviceInfo.deviceName(), deviceInfo, "", isDefault));
|
||||
qInfo(logAudio()) << (deviceInfo.deviceName() == defaultOutputDeviceName ? "*" : " ") <<
|
||||
"(" << numOutputDevices << ") Output Device : " << deviceInfo.deviceName();
|
||||
#else
|
||||
outputs.append(new audioDevice(deviceInfo.description(), deviceInfo, "", isDefault));
|
||||
qInfo(logAudio()) << (deviceInfo.description() == defaultOutputDeviceName ? "*" : " ") <<
|
||||
"(" << numOutputDevices << ") Output Device : " << deviceInfo.description();
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_WFSERVER
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (fm.boundingRect(deviceInfo.deviceName()).width() > numCharsOut)
|
||||
numCharsOut = fm.boundingRect(deviceInfo.deviceName()).width();
|
||||
#else
|
||||
if (fm.boundingRect(deviceInfo.description()).width() > numCharsOut)
|
||||
numCharsOut = fm.boundingRect(deviceInfo.description()).width();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
}
|
||||
#endif
|
||||
numOutputDevices++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case portAudio:
|
||||
{
|
||||
PaError err;
|
||||
|
||||
err = Pa_Initialize();
|
||||
|
||||
if (err != paNoError)
|
||||
{
|
||||
qInfo(logAudio()) << "ERROR: Cannot initialize Portaudio";
|
||||
return;
|
||||
}
|
||||
|
||||
qInfo(logAudio()) << "PortAudio version: " << Pa_GetVersionInfo()->versionText;
|
||||
|
||||
int numDevices = Pa_GetDeviceCount();
|
||||
qInfo(logAudio()) << "Pa_CountDevices returned" << numDevices << "audio device(s) (*=default)";
|
||||
|
||||
|
||||
const PaDeviceInfo* info;
|
||||
for (int i = 0; i < numDevices; i++)
|
||||
{
|
||||
info = Pa_GetDeviceInfo(i);
|
||||
if (info->maxInputChannels > 0) {
|
||||
bool isDefault = false;
|
||||
numInputDevices++;
|
||||
qInfo(logAudio()) << (i == Pa_GetDefaultInputDevice() ? "*" : " ") << "(" << i << ") Input Device : " << QString(info->name);
|
||||
if (i == Pa_GetDefaultInputDevice()) {
|
||||
defaultInputDeviceName = info->name;
|
||||
isDefault = true;
|
||||
}
|
||||
inputs.append(new audioDevice(QString(info->name), i,isDefault));
|
||||
#ifndef BUILD_WFSERVER
|
||||
if (fm.boundingRect(QString(info->name)).width() > numCharsIn)
|
||||
numCharsIn = fm.boundingRect(QString(info->name)).width();
|
||||
#endif
|
||||
|
||||
}
|
||||
if (info->maxOutputChannels > 0) {
|
||||
bool isDefault = false;
|
||||
numOutputDevices++;
|
||||
qInfo(logAudio()) << (i == Pa_GetDefaultOutputDevice() ? "*" : " ") << "(" << i << ") Output Device : " << QString(info->name);
|
||||
if (i == Pa_GetDefaultOutputDevice()) {
|
||||
defaultOutputDeviceName = info->name;
|
||||
isDefault = true;
|
||||
}
|
||||
outputs.append(new audioDevice(QString(info->name), i,isDefault));
|
||||
#ifndef BUILD_WFSERVER
|
||||
if (fm.boundingRect(QString(info->name)).width() > numCharsOut)
|
||||
numCharsOut = fm.boundingRect(QString(info->name)).width();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rtAudio:
|
||||
{
|
||||
Pa_Terminate();
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
RtAudio* audio = new RtAudio(RtAudio::Api::LINUX_ALSA);
|
||||
#elif defined(Q_OS_WIN)
|
||||
RtAudio* audio = new RtAudio(RtAudio::Api::WINDOWS_WASAPI);
|
||||
#elif defined(Q_OS_MACX)
|
||||
RtAudio* audio = new RtAudio(RtAudio::Api::MACOSX_CORE);
|
||||
#endif
|
||||
|
||||
|
||||
// Enumerate audio devices, need to do before settings are loaded.
|
||||
std::map<int, std::string> apiMap;
|
||||
apiMap[RtAudio::MACOSX_CORE] = "OS-X Core Audio";
|
||||
apiMap[RtAudio::WINDOWS_ASIO] = "Windows ASIO";
|
||||
apiMap[RtAudio::WINDOWS_DS] = "Windows DirectSound";
|
||||
apiMap[RtAudio::WINDOWS_WASAPI] = "Windows WASAPI";
|
||||
apiMap[RtAudio::UNIX_JACK] = "Jack Client";
|
||||
apiMap[RtAudio::LINUX_ALSA] = "Linux ALSA";
|
||||
apiMap[RtAudio::LINUX_PULSE] = "Linux PulseAudio";
|
||||
apiMap[RtAudio::LINUX_OSS] = "Linux OSS";
|
||||
apiMap[RtAudio::RTAUDIO_DUMMY] = "RtAudio Dummy";
|
||||
|
||||
std::vector< RtAudio::Api > apis;
|
||||
RtAudio::getCompiledApi(apis);
|
||||
|
||||
qInfo(logAudio()) << "RtAudio Version " << QString::fromStdString(RtAudio::getVersion());
|
||||
|
||||
qInfo(logAudio()) << "Compiled APIs:";
|
||||
for (unsigned int i = 0; i < apis.size(); i++) {
|
||||
qInfo(logAudio()) << " " << QString::fromStdString(apiMap[apis[i]]);
|
||||
}
|
||||
|
||||
RtAudio::DeviceInfo info;
|
||||
|
||||
qInfo(logAudio()) << "Current API: " << QString::fromStdString(apiMap[audio->getCurrentApi()]);
|
||||
|
||||
unsigned int devicecount = audio->getDeviceCount();
|
||||
|
||||
#if (RTAUDIO_VERSION_MAJOR > 5)
|
||||
std::vector<unsigned int> devices = audio->getDeviceIds();
|
||||
#endif
|
||||
qInfo(logAudio()) << "Found:" << devicecount << " audio device(s) (*=default)";
|
||||
|
||||
for (unsigned int i = 1; i < devicecount; i++) {
|
||||
|
||||
#if (RTAUDIO_VERSION_MAJOR > 5)
|
||||
info = audio->getDeviceInfo(devices[i]);
|
||||
#else
|
||||
info = audio->getDeviceInfo(i);
|
||||
#endif
|
||||
if (info.inputChannels > 0) {
|
||||
bool isDefault = false;
|
||||
qInfo(logAudio()) << (info.isDefaultInput ? "*" : " ") << "(" << i << ") Input Device : " << QString::fromStdString(info.name);
|
||||
numInputDevices++;
|
||||
|
||||
if (info.isDefaultInput) {
|
||||
defaultInputDeviceName = QString::fromStdString(info.name);
|
||||
isDefault = true;
|
||||
}
|
||||
|
||||
#if (RTAUDIO_VERSION_MAJOR > 5)
|
||||
inputs.append(new audioDevice(QString::fromStdString(info.name), devices[i], isDefault));
|
||||
#else
|
||||
inputs.append(new audioDevice(QString::fromStdString(info.name), i, isDefault));
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_WFSERVER
|
||||
if (fm.boundingRect(QString::fromStdString(info.name)).width() > numCharsIn)
|
||||
numCharsIn = fm.boundingRect(QString::fromStdString(info.name)).width();
|
||||
#endif
|
||||
|
||||
}
|
||||
if (info.outputChannels > 0) {
|
||||
bool isDefault = false;
|
||||
qInfo(logAudio()) << (info.isDefaultOutput ? "*" : " ") << "(" << i << ") Output Device : " << QString::fromStdString(info.name);
|
||||
numOutputDevices++;
|
||||
|
||||
if (info.isDefaultOutput) {
|
||||
defaultOutputDeviceName = QString::fromStdString(info.name);
|
||||
isDefault = true;
|
||||
}
|
||||
|
||||
#if (RTAUDIO_VERSION_MAJOR > 5)
|
||||
outputs.append(new audioDevice(QString::fromStdString(info.name), devices[i], isDefault));
|
||||
#else
|
||||
outputs.append(new audioDevice(QString::fromStdString(info.name), i, isDefault));
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_WFSERVER
|
||||
if (fm.boundingRect(QString::fromStdString(info.name)).width() > numCharsOut)
|
||||
numCharsOut = fm.boundingRect(QString::fromStdString(info.name)).width();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
delete audio;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
emit updated();
|
||||
|
||||
}
|
||||
|
||||
audioDevices::~audioDevices()
|
||||
{
|
||||
outputs.clear();
|
||||
inputs.clear();
|
||||
}
|
||||
|
||||
QStringList audioDevices::getInputs()
|
||||
{
|
||||
QStringList list;
|
||||
|
||||
for (int f = 0; f < inputs.size(); f++) {
|
||||
list.append(inputs[f]->name);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QStringList audioDevices::getOutputs()
|
||||
{
|
||||
QStringList list;
|
||||
|
||||
for (int f = 0; f < outputs.size(); f++) {
|
||||
list.append(outputs[f]->name);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int audioDevices::findInput(QString type, QString name)
|
||||
{
|
||||
int ret = -1;
|
||||
int def = -1;
|
||||
int usb = -1;
|
||||
QString msg;
|
||||
QTextStream s(&msg);
|
||||
|
||||
for (int f = 0; f < inputs.size(); f++)
|
||||
{
|
||||
//qInfo(logAudio()) << "Found device" << inputs[f].name;
|
||||
if (inputs[f]->name.startsWith(name)) {
|
||||
s << type << " Audio input device " << name << " found! ";
|
||||
ret = f;
|
||||
}
|
||||
if (inputs[f]->isDefault == true)
|
||||
{
|
||||
def = f;
|
||||
}
|
||||
if (inputs[f]->name.toUpper().contains("USB")) {
|
||||
// This is a USB device...
|
||||
usb = f;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
s << type << " Audio input device " << name << " Not found: ";
|
||||
|
||||
if (inputs.size() == 1) {
|
||||
s << "Selecting first device " << inputs[0]->name;
|
||||
ret = 0;
|
||||
}
|
||||
else if (usb > -1 && type != "Client")
|
||||
{
|
||||
s << " Selecting found USB device " << inputs[usb]->name;
|
||||
ret = usb;
|
||||
}
|
||||
else if (def > -1)
|
||||
{
|
||||
s << " Selecting default device " << inputs[def]->name;
|
||||
ret = def;
|
||||
}
|
||||
else {
|
||||
s << " and no default device found, aborting!";
|
||||
}
|
||||
}
|
||||
|
||||
qInfo(logAudio()) << msg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int audioDevices::findOutput(QString type, QString name)
|
||||
{
|
||||
int ret = -1;
|
||||
int def = -1;
|
||||
int usb = -1;
|
||||
QString msg;
|
||||
QTextStream s(&msg);
|
||||
|
||||
for (int f = 0; f < outputs.size(); f++)
|
||||
{
|
||||
//qInfo(logAudio()) << "Found device" << outputs[f].name;
|
||||
if (outputs[f]->name.startsWith(name)) {
|
||||
ret = f;
|
||||
s << type << " Audio output device " << name << " found! ";
|
||||
}
|
||||
if (outputs[f]->isDefault == true)
|
||||
{
|
||||
def = f;
|
||||
}
|
||||
if (outputs[f]->name.toUpper().contains("USB")) {
|
||||
// This is a USB device...
|
||||
usb = f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
s << type << " Audio output device " << name << " Not found: ";
|
||||
|
||||
if (outputs.size() == 1) {
|
||||
s << " Selecting first device " << outputs[0]->name;
|
||||
ret = 0;
|
||||
}
|
||||
else if (usb > -1 && type != "Client")
|
||||
{
|
||||
s << " Selecting found USB device " << outputs[usb]->name;
|
||||
ret = usb;
|
||||
}
|
||||
else if (def > -1)
|
||||
{
|
||||
s << " Selecting default device " << outputs[def]->name;
|
||||
ret = def;
|
||||
}
|
||||
else {
|
||||
s << " and no default device found, aborting!";
|
||||
}
|
||||
}
|
||||
qInfo(logAudio()) << msg;
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef AUDIODEVICES_H
|
||||
#define AUDIODEVICES_H
|
||||
#include <QObject>
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
#include <QAudioDeviceInfo>
|
||||
#else
|
||||
#include <QMediaDevices>
|
||||
#include <QAudioDevice>
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
#include <QFontMetrics>
|
||||
|
||||
#include <portaudio.h>
|
||||
#ifndef Q_OS_LINUX
|
||||
#include "RtAudio.h"
|
||||
#else
|
||||
#include "rtaudio/RtAudio.h"
|
||||
#endif
|
||||
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
|
||||
struct audioDevice {
|
||||
audioDevice(QString name, int deviceInt, bool isDefault) : name(name), deviceInt(deviceInt), isDefault(isDefault) {};
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
audioDevice(QString name, const QAudioDeviceInfo deviceInfo, QString realm, bool isDefault) : name(name), deviceInfo(deviceInfo), realm(realm), isDefault(isDefault) {};
|
||||
#else
|
||||
audioDevice(QString name, QAudioDevice deviceInfo, QString realm, bool isDefault) : name(name), deviceInfo(deviceInfo), realm(realm), isDefault(isDefault) {};
|
||||
#endif
|
||||
|
||||
QString name;
|
||||
int deviceInt;
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
const QAudioDeviceInfo deviceInfo;
|
||||
#else
|
||||
QAudioDevice deviceInfo;
|
||||
#endif
|
||||
|
||||
QString realm;
|
||||
bool isDefault;
|
||||
};
|
||||
|
||||
class audioDevices : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit audioDevices(audioType type, QFontMetrics fm, QObject* parent = nullptr);
|
||||
~audioDevices();
|
||||
void setAudioType(audioType type) { system = type; };
|
||||
audioType getAudioType() { return system; };
|
||||
int getNumCharsIn() { return numCharsIn; };
|
||||
int getNumCharsOut() { return numCharsOut; };
|
||||
|
||||
QString getInputName(int num) { return inputs[num]->name; };
|
||||
QString getOutputName(int num) { return outputs[num]->name; };
|
||||
|
||||
int getInputDeviceInt(int num) { return inputs[num]->deviceInt; };
|
||||
int getOutputDeviceInt(int num) { return outputs[num]->deviceInt; };
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
const QAudioDeviceInfo getInputDeviceInfo(int num) { return inputs[num]->deviceInfo; };
|
||||
const QAudioDeviceInfo getOutputDeviceInfo(int num) { return outputs[num]->deviceInfo; };
|
||||
#else
|
||||
const QAudioDevice getInputDeviceInfo(int num) { return inputs[num]->deviceInfo; };
|
||||
const QAudioDevice getOutputDeviceInfo(int num) { return outputs[num]->deviceInfo; };
|
||||
#endif
|
||||
|
||||
void enumerate();
|
||||
|
||||
QStringList getInputs();
|
||||
QStringList getOutputs();
|
||||
|
||||
int findInput(QString type, QString name);
|
||||
int findOutput(QString type, QString name);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
QMediaDevices mediaDevices;
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
protected:
|
||||
private:
|
||||
|
||||
audioType system;
|
||||
QFontMetrics fm;
|
||||
QString defaultInputDeviceName;
|
||||
QString defaultOutputDeviceName;
|
||||
int numInputDevices;
|
||||
int numOutputDevices;
|
||||
QList<audioDevice*> inputs;
|
||||
QList<audioDevice*> outputs;
|
||||
int numCharsIn = 0;
|
||||
int numCharsOut = 0;
|
||||
QString audioApi = "wasapi";
|
||||
|
||||
};
|
||||
|
||||
#endif
|
167
audiohandler.cpp
|
@ -46,89 +46,127 @@ audioHandler::~audioHandler()
|
|||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "audio handler starting:" << setup.name;
|
||||
if (setup.port.isNull())
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "No audio device was found. You probably need to install libqt5multimedia-plugins.";
|
||||
#ifdef Q_OS_LINUX
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "No audio device was found. You probably need to install libqt5multimedia-plugins.";
|
||||
#else
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio device is NULL, please check device selection in settings.";
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name <<
|
||||
", bits" << inFormat.sampleSize() <<
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
", bits" << radioFormat.sampleSize() <<
|
||||
#else
|
||||
", format" << radioFormat.sampleFormat() <<
|
||||
#endif
|
||||
", codec" << setup.codec <<
|
||||
", latency" << setup.latency <<
|
||||
", localAFGain" << setup.localAFgain <<
|
||||
", radioChan" << inFormat.channelCount() <<
|
||||
", radioChan" << radioFormat.channelCount() <<
|
||||
", resampleQuality" << setup.resampleQuality <<
|
||||
", samplerate" << inFormat.sampleRate() <<
|
||||
", samplerate" << radioFormat.sampleRate() <<
|
||||
", uLaw" << setup.ulaw;
|
||||
|
||||
inFormat = toQAudioFormat(setup.codec, setup.sampleRate);
|
||||
radioFormat = toQAudioFormat(setup.codec, setup.sampleRate);
|
||||
codec = LPCM;
|
||||
if (setup.codec == 0x01 || setup.codec == 0x20)
|
||||
codec = PCMU;
|
||||
else if (setup.codec == 0x40 || setup.codec == 0x40)
|
||||
codec = OPUS;
|
||||
|
||||
|
||||
outFormat = setup.port.preferredFormat();
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Preferred Format: SampleSize" << outFormat.sampleSize() << "Channel Count" << outFormat.channelCount() <<
|
||||
"Sample Rate" << outFormat.sampleRate() << "Codec" << outFormat.codec() << "Sample Type" << outFormat.sampleType();
|
||||
if (outFormat.channelCount() > 2) {
|
||||
outFormat.setChannelCount(2);
|
||||
nativeFormat = setup.port.preferredFormat();
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Preferred Format: SampleSize" << nativeFormat.sampleSize() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec << "Sample Type" << nativeFormat.sampleType();
|
||||
#else
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Preferred Format: SampleFormat" << nativeFormat.sampleFormat() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate();
|
||||
#endif
|
||||
if (nativeFormat.channelCount() > 2) {
|
||||
nativeFormat.setChannelCount(2);
|
||||
}
|
||||
else if (outFormat.channelCount() < 1)
|
||||
else if (nativeFormat.channelCount() < 1)
|
||||
{
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "No channels found, aborting setup.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outFormat.channelCount() == 1 && inFormat.channelCount() == 2) {
|
||||
outFormat.setChannelCount(2);
|
||||
if (!setup.port.isFormatSupported(outFormat)) {
|
||||
if (nativeFormat.channelCount() == 1 && radioFormat.channelCount() == 2) {
|
||||
nativeFormat.setChannelCount(2);
|
||||
if (!setup.port.isFormatSupported(nativeFormat)) {
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Cannot request stereo reverting to mono";
|
||||
outFormat.setChannelCount(1);
|
||||
nativeFormat.setChannelCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (outFormat.sampleRate() < 48000) {
|
||||
int tempRate=outFormat.sampleRate();
|
||||
outFormat.setSampleRate(48000);
|
||||
if (!setup.port.isFormatSupported(outFormat)) {
|
||||
if (nativeFormat.sampleRate() < 48000) {
|
||||
int tempRate=nativeFormat.sampleRate();
|
||||
nativeFormat.setSampleRate(48000);
|
||||
if (!setup.port.isFormatSupported(nativeFormat)) {
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Cannot request 48K, reverting to "<< tempRate;
|
||||
outFormat.setSampleRate(tempRate);
|
||||
nativeFormat.setSampleRate(tempRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (outFormat.sampleType() == QAudioFormat::UnSignedInt && outFormat.sampleSize()==8) {
|
||||
outFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
outFormat.setSampleSize(16);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
|
||||
if (!setup.port.isFormatSupported(outFormat)) {
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Cannot request 16bit Signed samples, reverting to 8bit Unsigned";
|
||||
outFormat.setSampleType(QAudioFormat::UnSignedInt);
|
||||
outFormat.setSampleSize(8);
|
||||
}
|
||||
}
|
||||
if (nativeFormat.sampleType() == QAudioFormat::UnSignedInt && nativeFormat.sampleSize() == 8) {
|
||||
nativeFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
nativeFormat.setSampleSize(16);
|
||||
|
||||
if (!setup.port.isFormatSupported(nativeFormat)) {
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Cannot request 16bit Signed samples, reverting to 8bit Unsigned";
|
||||
nativeFormat.setSampleType(QAudioFormat::UnSignedInt);
|
||||
nativeFormat.setSampleSize(8);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (nativeFormat.sampleFormat() == QAudioFormat::UInt8) {
|
||||
nativeFormat.setSampleFormat(QAudioFormat::Int16);
|
||||
|
||||
/*
|
||||
if (!setup.port.isFormatSupported(nativeFormat)) {
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Cannot request 16bit Signed samples, reverting to 8bit Unsigned";
|
||||
nativeFormat.setSampleFormat(QAudioFormat::UInt8);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (outFormat.sampleType()==QAudioFormat::SignedInt) {
|
||||
outFormat.setSampleType(QAudioFormat::Float);
|
||||
outFormat.setSampleSize(32);
|
||||
if (!setup.port.isFormatSupported(outFormat)) {
|
||||
/*
|
||||
if (nativeFormat.sampleType()==QAudioFormat::SignedInt) {
|
||||
nativeFormat.setSampleType(QAudioFormat::Float);
|
||||
nativeFormat.setSampleSize(32);
|
||||
if (!setup.port.isFormatSupported(nativeFormat)) {
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Attempt to select 32bit Float failed, reverting to SignedInt";
|
||||
outFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
outFormat.setSampleSize(16);
|
||||
nativeFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
nativeFormat.setSampleSize(16);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
if (outFormat.sampleSize() == 24) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
|
||||
if (nativeFormat.sampleSize() == 24) {
|
||||
// We can't convert this easily so use 32 bit instead.
|
||||
outFormat.setSampleSize(32);
|
||||
if (!setup.port.isFormatSupported(outFormat)) {
|
||||
nativeFormat.setSampleSize(32);
|
||||
if (!setup.port.isFormatSupported(nativeFormat)) {
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "24 bit requested and 32 bit audio not supported, try 16 bit instead";
|
||||
outFormat.setSampleSize(16);
|
||||
nativeFormat.setSampleSize(16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << outFormat.sampleSize() << "Channel Count" << outFormat.channelCount() <<
|
||||
"Sample Rate" << outFormat.sampleRate() << "Codec" << outFormat.codec() << "Sample Type" << outFormat.sampleType();
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << nativeFormat.sampleSize() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec << "Sample Type" << nativeFormat.sampleType();
|
||||
#else
|
||||
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleFormat" << nativeFormat.sampleFormat() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec;
|
||||
|
||||
#endif
|
||||
|
||||
// We "hopefully" now have a valid format that is supported so try connecting
|
||||
|
||||
|
@ -142,21 +180,32 @@ audioHandler::~audioHandler()
|
|||
}
|
||||
converter->moveToThread(converterThread);
|
||||
|
||||
connect(this, SIGNAL(setupConverter(QAudioFormat,QAudioFormat,quint8,quint8)), converter, SLOT(init(QAudioFormat,QAudioFormat,quint8,quint8)));
|
||||
connect(this, SIGNAL(setupConverter(QAudioFormat,codecType,QAudioFormat,codecType,quint8,quint8)), converter, SLOT(init(QAudioFormat,codecType,QAudioFormat,codecType,quint8,quint8)));
|
||||
connect(converterThread, SIGNAL(finished()), converter, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(sendToConverter(audioPacket)), converter, SLOT(convert(audioPacket)));
|
||||
converterThread->start(QThread::TimeCriticalPriority);
|
||||
|
||||
if (setup.isinput) {
|
||||
audioInput = new QAudioInput(setup.port, outFormat, this);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
audioInput = new QAudioInput(setup.port, nativeFormat, this);
|
||||
#else
|
||||
audioInput = new QAudioSource(setup.port, nativeFormat, this);
|
||||
#endif
|
||||
connect(audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
|
||||
emit setupConverter(outFormat, inFormat, 7, setup.resampleQuality);
|
||||
emit setupConverter(nativeFormat, codecType::LPCM, radioFormat, codec, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedInput(audioPacket)));
|
||||
}
|
||||
else {
|
||||
audioOutput = new QAudioOutput(setup.port, outFormat, this);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
audioOutput = new QAudioOutput(setup.port, nativeFormat, this);
|
||||
#else
|
||||
audioOutput = new QAudioSink(setup.port, nativeFormat, this);
|
||||
#endif
|
||||
|
||||
connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
|
||||
emit setupConverter(inFormat, outFormat, 7, setup.resampleQuality);
|
||||
emit setupConverter(radioFormat, codec, nativeFormat, codecType::LPCM, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedOutput(audioPacket)));
|
||||
}
|
||||
|
||||
|
@ -182,10 +231,10 @@ void audioHandler::start()
|
|||
if (setup.isinput) {
|
||||
//this->open(QIODevice::WriteOnly);
|
||||
//audioInput->start(this);
|
||||
#ifdef Q_OS_WIN
|
||||
audioInput->setBufferSize(inFormat.bytesForDuration(setup.latency * 100));
|
||||
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
audioInput->setBufferSize(nativeFormat.bytesForDuration(setup.latency * 100));
|
||||
#else
|
||||
audioInput->setBufferSize(inFormat.bytesForDuration(setup.latency * 1000));
|
||||
audioInput->setBufferSize(nativeFormat.bytesForDuration(setup.latency * 1000));
|
||||
#endif
|
||||
audioDevice = audioInput->start();
|
||||
connect(audioInput, SIGNAL(destroyed()), audioDevice, SLOT(deleteLater()), Qt::UniqueConnection);
|
||||
|
@ -195,10 +244,10 @@ void audioHandler::start()
|
|||
}
|
||||
else {
|
||||
// Buffer size must be set before audio is started.
|
||||
#ifdef Q_OS_WIN
|
||||
audioOutput->setBufferSize(outFormat.bytesForDuration(setup.latency * 100));
|
||||
#if (defined(Q_OS_WIN) && (QT_VERSION < QT_VERSION_CHECK(6,0,0)))
|
||||
audioOutput->setBufferSize(nativeFormat.bytesForDuration(setup.latency * 100));
|
||||
#else
|
||||
audioOutput->setBufferSize(outFormat.bytesForDuration(setup.latency * 1000));
|
||||
audioOutput->setBufferSize(nativeFormat.bytesForDuration(setup.latency * 1000));
|
||||
#endif
|
||||
audioDevice = audioOutput->start();
|
||||
connect(audioOutput, SIGNAL(destroyed()), audioDevice, SLOT(deleteLater()), Qt::UniqueConnection);
|
||||
|
@ -249,7 +298,7 @@ void audioHandler::convertedOutput(audioPacket packet) {
|
|||
|
||||
if (packet.data.size() > 0 ) {
|
||||
|
||||
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audioOutput->bufferSize() - audioOutput->bytesFree()) / 1000);
|
||||
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (nativeFormat.durationForBytes(audioOutput->bufferSize() - audioOutput->bytesFree()) / 1000);
|
||||
if (audioDevice != Q_NULLPTR) {
|
||||
if (audioDevice->write(packet.data) < packet.data.size()) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Buffer full!";
|
||||
|
@ -279,7 +328,7 @@ void audioHandler::getNextAudioChunk()
|
|||
if (audioDevice) {
|
||||
tempBuf.data.append(audioDevice->readAll());
|
||||
}
|
||||
if (tempBuf.data.length() >= outFormat.bytesForDuration(setup.blockSize * 1000)) {
|
||||
if (tempBuf.data.length() >= nativeFormat.bytesForDuration(setup.blockSize * 1000)) {
|
||||
audioPacket packet;
|
||||
packet.time = QTime::currentTime();
|
||||
packet.sent = 0;
|
||||
|
@ -287,14 +336,14 @@ void audioHandler::getNextAudioChunk()
|
|||
memcpy(&packet.guid, setup.guid, GUIDLEN);
|
||||
//QTime startProcessing = QTime::currentTime();
|
||||
packet.data.clear();
|
||||
packet.data = tempBuf.data.mid(0, outFormat.bytesForDuration(setup.blockSize * 1000));
|
||||
tempBuf.data.remove(0, outFormat.bytesForDuration(setup.blockSize * 1000));
|
||||
packet.data = tempBuf.data.mid(0, nativeFormat.bytesForDuration(setup.blockSize * 1000));
|
||||
tempBuf.data.remove(0, nativeFormat.bytesForDuration(setup.blockSize * 1000));
|
||||
|
||||
emit sendToConverter(packet);
|
||||
}
|
||||
|
||||
/* If there is still enough data in the buffer, call myself again in 20ms */
|
||||
if (tempBuf.data.length() >= outFormat.bytesForDuration(setup.blockSize * 1000)) {
|
||||
if (tempBuf.data.length() >= nativeFormat.bytesForDuration(setup.blockSize * 1000)) {
|
||||
QTimer::singleShot(setup.blockSize, this, &audioHandler::getNextAudioChunk);
|
||||
}
|
||||
|
||||
|
@ -324,7 +373,7 @@ void audioHandler::changeLatency(const quint16 newSize)
|
|||
stop();
|
||||
start();
|
||||
}
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Configured latency: " << setup.latency << "Buffer Duration:" << outFormat.durationForBytes(audioOutput->bufferSize())/1000 << "ms";
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Configured latency: " << setup.latency << "Buffer Duration:" << nativeFormat.durationForBytes(audioOutput->bufferSize())/1000 << "ms";
|
||||
|
||||
}
|
||||
int audioHandler::getLatency()
|
||||
|
|
|
@ -16,8 +16,18 @@
|
|||
/* QT Audio Headers */
|
||||
#include <QAudioOutput>
|
||||
#include <QAudioFormat>
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioInput>
|
||||
#include <QAudioOutput>
|
||||
#else
|
||||
#include <QMediaDevices>
|
||||
#include <QAudioDevice>
|
||||
#include <QAudioSource>
|
||||
#include <QAudioSink>
|
||||
#endif
|
||||
|
||||
#include <QIODevice>
|
||||
|
||||
|
||||
|
@ -60,18 +70,19 @@ public slots:
|
|||
virtual void incomingAudio(const audioPacket data);
|
||||
virtual void convertedInput(audioPacket audio);
|
||||
virtual void convertedOutput(audioPacket audio);
|
||||
virtual void getNextAudioChunk();
|
||||
|
||||
private slots:
|
||||
virtual void stateChanged(QAudio::State state);
|
||||
virtual void clearUnderrun();
|
||||
virtual void getNextAudioChunk();
|
||||
|
||||
|
||||
signals:
|
||||
void audioMessage(QString message);
|
||||
void sendLatency(quint16 newSize);
|
||||
void haveAudioData(const audioPacket& data);
|
||||
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS, quint16 latency,quint16 current,bool under,bool over);
|
||||
void setupConverter(QAudioFormat in, QAudioFormat out, quint8 opus, quint8 resamp);
|
||||
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS,quint16 latency,quint16 current,bool under,bool over);
|
||||
void setupConverter(QAudioFormat in, codecType codecIn, QAudioFormat out, codecType codecOut, quint8 opus, quint8 resamp);
|
||||
void sendToConverter(audioPacket audio);
|
||||
|
||||
|
||||
|
@ -87,12 +98,19 @@ private:
|
|||
bool isReady = false;
|
||||
bool audioBuffered = false;
|
||||
|
||||
QAudioOutput* audioOutput=Q_NULLPTR;
|
||||
QAudioInput* audioInput=Q_NULLPTR;
|
||||
QIODevice* audioDevice=Q_NULLPTR;
|
||||
QAudioFormat inFormat;
|
||||
QAudioFormat outFormat;
|
||||
|
||||
QAudioFormat radioFormat;
|
||||
QAudioFormat nativeFormat;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
QAudioOutput* audioOutput = Q_NULLPTR;
|
||||
QAudioInput* audioInput = Q_NULLPTR;
|
||||
QAudioDeviceInfo deviceInfo;
|
||||
#else
|
||||
QAudioSink* audioOutput = Q_NULLPTR;
|
||||
QAudioSource* audioInput = Q_NULLPTR;
|
||||
QAudioDevice deviceInfo;
|
||||
#endif
|
||||
|
||||
audioConverter* converter=Q_NULLPTR;
|
||||
QThread* converterThread = Q_NULLPTR;
|
||||
|
@ -121,6 +139,7 @@ private:
|
|||
OpusEncoder* encoder = Q_NULLPTR;
|
||||
OpusDecoder* decoder = Q_NULLPTR;
|
||||
QTimer* underTimer;
|
||||
codecType codec;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,314 @@
|
|||
#include "cluster.h"
|
||||
#include "logcategories.h"
|
||||
|
||||
|
||||
dxClusterClient::dxClusterClient(QObject* parent):
|
||||
QObject(parent)
|
||||
{
|
||||
qInfo(logCluster()) << "starting dxClusterClient()";
|
||||
}
|
||||
|
||||
dxClusterClient::~dxClusterClient()
|
||||
{
|
||||
qInfo(logCluster()) << "closing dxClusterClient()";
|
||||
enableUdp(false);
|
||||
enableTcp(false);
|
||||
#ifdef USESQL
|
||||
database db;
|
||||
db.close();
|
||||
#else
|
||||
QMap<QString, spotData*>::iterator spot = allSpots.begin();
|
||||
while (spot != allSpots.end())
|
||||
{
|
||||
delete spot.value(); // Stop memory leak?
|
||||
spot = allSpots.erase(spot);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void dxClusterClient::enableUdp(bool enable)
|
||||
{
|
||||
udpEnable = enable;
|
||||
if (enable)
|
||||
{
|
||||
if (udpSocket == Q_NULLPTR)
|
||||
{
|
||||
udpSocket = new QUdpSocket(this);
|
||||
bool result = udpSocket->bind(QHostAddress::AnyIPv4, udpPort);
|
||||
qInfo(logCluster()) << "Starting udpSocket() on:" << udpPort << "Result:" << result;
|
||||
|
||||
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(udpDataReceived()), Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (udpSocket != Q_NULLPTR)
|
||||
{
|
||||
qInfo(logCluster()) << "Stopping udpSocket() on:" << udpPort;
|
||||
|
||||
udpSocket->disconnect();
|
||||
delete udpSocket;
|
||||
udpSocket = Q_NULLPTR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dxClusterClient::enableTcp(bool enable)
|
||||
{
|
||||
tcpEnable = enable;
|
||||
if (enable)
|
||||
{
|
||||
tcpRegex = QRegularExpression("^DX de ([a-z-|A-Z|0-9|#|/]+):\\s+([0-9|.]+)\\s+([a-z|A-Z|0-9|/]+)+\\s+(.*)\\s+(\\d{4}Z)");
|
||||
|
||||
if (tcpSocket == Q_NULLPTR)
|
||||
{
|
||||
tcpSocket = new QTcpSocket(this);
|
||||
tcpSocket->connectToHost(tcpServerName, tcpPort);
|
||||
qInfo(logCluster()) << "Starting tcpSocket() on:" << tcpPort;
|
||||
|
||||
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(tcpDataReceived()), Qt::QueuedConnection);
|
||||
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(tcpDisconnected()));
|
||||
|
||||
tcpCleanupTimer = new QTimer(this);
|
||||
tcpCleanupTimer->setInterval(1000 * 10); // Run once a minute
|
||||
connect(tcpCleanupTimer, SIGNAL(timeout()), this, SLOT(tcpCleanup()));
|
||||
tcpCleanupTimer->start();
|
||||
authenticated = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tcpSocket != Q_NULLPTR)
|
||||
{
|
||||
sendTcpData(QString("bye\n"));
|
||||
qInfo(logCluster()) << "Disconnecting tcpSocket() on:" << tcpPort;
|
||||
if (tcpCleanupTimer != Q_NULLPTR)
|
||||
{
|
||||
tcpCleanupTimer->stop();
|
||||
delete tcpCleanupTimer;
|
||||
tcpCleanupTimer = Q_NULLPTR;
|
||||
}
|
||||
tcpSocket->disconnect();
|
||||
delete tcpSocket;
|
||||
tcpSocket = Q_NULLPTR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dxClusterClient::udpDataReceived()
|
||||
{
|
||||
QHostAddress sender;
|
||||
quint16 port;
|
||||
QByteArray datagram;
|
||||
datagram.resize(udpSocket->pendingDatagramSize());
|
||||
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
|
||||
|
||||
if (udpSpotReader.setContent(datagram))
|
||||
{
|
||||
QDomElement spot = udpSpotReader.firstChildElement("spot");
|
||||
if (spot.nodeName() == "spot")
|
||||
{
|
||||
// This is a spot?
|
||||
QString action = spot.firstChildElement("action").text();
|
||||
if (action == "add") {
|
||||
spotData* data = new spotData();
|
||||
data->dxcall = spot.firstChildElement("dxcall").text();
|
||||
data->frequency = spot.firstChildElement("frequency").text().toDouble() / 1000.0;
|
||||
data->spottercall = spot.firstChildElement("spottercall").text();
|
||||
data->timestamp = QDateTime::fromString(spot.firstChildElement("timestamp").text(),"yyyy-MM-dd hh:mm:ss");
|
||||
data->mode = spot.firstChildElement("mode").text();
|
||||
data->comment = spot.firstChildElement("comment").text();
|
||||
|
||||
#ifdef USESQL
|
||||
database db = database();
|
||||
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
|
||||
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,mode,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6','%7')\n")
|
||||
.arg("UDP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->mode).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
|
||||
db.query(query);
|
||||
#else
|
||||
bool found = false;
|
||||
QMap<QString, spotData*>::iterator spot = allSpots.find(data->dxcall);
|
||||
while (spot != allSpots.end() && spot.key() == data->dxcall && spot.value()->frequency == data->frequency) {
|
||||
found = true;
|
||||
++spot;
|
||||
}
|
||||
if (found == false) {
|
||||
allSpots.insert(data->dxcall, data);
|
||||
}
|
||||
#endif
|
||||
emit sendOutput(QString("<spot><action>add</action><dxcall>%1</dxcall><spottercall>%2</spottercall><frequency>%3</frequency><comment>%4</comment></spot>\n")
|
||||
.arg(data->dxcall).arg(data->spottercall).arg(data->frequency).arg(data->comment));
|
||||
|
||||
}
|
||||
else if (action == "delete")
|
||||
{
|
||||
QString dxcall = spot.firstChildElement("dxcall").text();
|
||||
double frequency = spot.firstChildElement("frequency").text().toDouble() / 1000.0;
|
||||
|
||||
#ifdef USESQL
|
||||
database db = database();
|
||||
QString query=QString("DELETE from spots where dxcall='%1' AND frequency=%2").arg(dxcall).arg(frequency);
|
||||
db.query(query);
|
||||
qInfo(logCluster()) << query;
|
||||
#else
|
||||
QMap<QString, spotData*>::iterator spot = allSpots.find(dxcall);
|
||||
while (spot != allSpots.end() && spot.key() == dxcall && spot.value()->frequency == frequency)
|
||||
{
|
||||
delete spot.value(); // Stop memory leak?
|
||||
spot = allSpots.erase(spot);
|
||||
}
|
||||
#endif
|
||||
emit sendOutput(QString("<spot><action>delete</action><dxcall>%1</dxcall<frequency>%3</frequency></spot>\n")
|
||||
.arg(dxcall).arg(frequency));
|
||||
}
|
||||
updateSpots();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dxClusterClient::tcpDataReceived()
|
||||
{
|
||||
QString data = QString(tcpSocket->readAll());
|
||||
|
||||
emit sendOutput(data);
|
||||
if (!authenticated) {
|
||||
if (data.contains("login:") || data.contains("call:") || data.contains("callsign:")) {
|
||||
sendTcpData(QString("%1\n").arg(tcpUserName));
|
||||
return;
|
||||
}
|
||||
if (data.contains("password:")) {
|
||||
sendTcpData(QString("%1\n").arg(tcpPassword));
|
||||
return;
|
||||
}
|
||||
if (data.contains("Hello")) {
|
||||
authenticated = true;
|
||||
enableSkimmerSpots(skimmerSpots);
|
||||
}
|
||||
}
|
||||
else {
|
||||
QRegularExpressionMatchIterator i = tcpRegex.globalMatch(data);
|
||||
while (i.hasNext()) {
|
||||
QRegularExpressionMatch match = i.next();
|
||||
if (match.hasMatch()) {
|
||||
spotData* data = new spotData();
|
||||
data->spottercall = match.captured(1);
|
||||
data->frequency = match.captured(2).toDouble() / 1000.0;
|
||||
data->dxcall = match.captured(3);
|
||||
data->comment = match.captured(4).trimmed();
|
||||
data->timestamp = QDateTime::currentDateTimeUtc();
|
||||
|
||||
#ifdef USESQL
|
||||
database db = database();
|
||||
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
|
||||
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6')\n")
|
||||
.arg("TCP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
|
||||
db.query(query);
|
||||
#else
|
||||
bool found = false;
|
||||
QMap<QString, spotData*>::iterator spot = allSpots.find(data->dxcall);
|
||||
while (spot != allSpots.end() && spot.key() == data->dxcall && spot.value()->frequency == data->frequency) {
|
||||
found = true;
|
||||
++spot;
|
||||
}
|
||||
if (found == false) {
|
||||
allSpots.insert(data->dxcall, data);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
updateSpots();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dxClusterClient::sendTcpData(QString data)
|
||||
{
|
||||
qInfo(logCluster()) << "Sending:" << data;
|
||||
if (tcpSocket != Q_NULLPTR && tcpSocket->isValid() && tcpSocket->isOpen())
|
||||
{
|
||||
tcpSocket->write(data.toLatin1());
|
||||
}
|
||||
else
|
||||
{
|
||||
qInfo(logCluster()) << "socket not open!";
|
||||
}
|
||||
}
|
||||
|
||||
void dxClusterClient::tcpCleanup()
|
||||
{
|
||||
#ifdef USESQL
|
||||
database db = database();
|
||||
db.query(QString("DELETE FROM spots where timestamp < datetime('now', '-%1 minutes')").arg(tcpTimeout));
|
||||
#else
|
||||
QMap<QString, spotData*>::iterator spot = allSpots.begin();;
|
||||
while (spot != allSpots.end()) {
|
||||
if (spot.value()->timestamp.addSecs(tcpTimeout * 60) < QDateTime::currentDateTimeUtc())
|
||||
{
|
||||
delete spot.value(); // Stop memory leak?
|
||||
spot = allSpots.erase(spot);
|
||||
}
|
||||
else
|
||||
{
|
||||
++spot;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void dxClusterClient::tcpDisconnected() {
|
||||
qWarning(logCluster()) << "TCP Cluster server disconnected...";
|
||||
// Need to start a timer and attempt reconnect.
|
||||
}
|
||||
|
||||
void dxClusterClient::freqRange(double low, double high)
|
||||
{
|
||||
lowFreq = low;
|
||||
highFreq = high;
|
||||
//qInfo(logCluster) << "New range" << low << "-" << high;
|
||||
updateSpots();
|
||||
}
|
||||
|
||||
void dxClusterClient::updateSpots()
|
||||
{
|
||||
QList<spotData> spots;
|
||||
#ifdef USESQL
|
||||
// Set the required frequency range.
|
||||
QString queryText = QString("SELECT * FROM spots WHERE frequency > %1 AND frequency < %2").arg(lowFreq).arg(highFreq);
|
||||
//QString queryText = QString("SELECT * FROM spots");
|
||||
database db;
|
||||
auto query = db.query(queryText);
|
||||
|
||||
while (query.next()) {
|
||||
// Step through all current spots within range
|
||||
spotData s = spotData();
|
||||
s.dxcall = query.value(query.record().indexOf("dxcall")).toString();
|
||||
s.frequency = query.value(query.record().indexOf("frequency")).toDouble();
|
||||
spots.append(s);
|
||||
}
|
||||
#else
|
||||
QMap<QString, spotData*>::iterator spot = allSpots.begin();;
|
||||
while (spot != allSpots.end()) {
|
||||
if (spot.value()->frequency > lowFreq && spot.value()->frequency < highFreq)
|
||||
{
|
||||
spots.append(**spot);
|
||||
}
|
||||
++spot;
|
||||
}
|
||||
|
||||
#endif
|
||||
emit sendSpots(spots);
|
||||
}
|
||||
|
||||
void dxClusterClient::enableSkimmerSpots(bool enable)
|
||||
{
|
||||
skimmerSpots = enable;
|
||||
if (authenticated) {
|
||||
if (skimmerSpots) {
|
||||
sendTcpData(QString("Set Dx Filter Skimmer\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
sendTcpData(QString("Set Dx Filter Not Skimmer\n"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef CLUSTER_H
|
||||
#define CLUSTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QUdpSocket>
|
||||
#include <QTcpSocket>
|
||||
#include <QDomDocument>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QDateTime>
|
||||
#include <QRegularExpression>
|
||||
#include <QTimer>
|
||||
|
||||
#ifdef USESQL
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#endif
|
||||
|
||||
#include <qcustomplot.h>
|
||||
|
||||
#ifdef USESQL
|
||||
#include "database.h"
|
||||
#endif
|
||||
|
||||
struct spotData {
|
||||
QString dxcall;
|
||||
double frequency;
|
||||
QString spottercall;
|
||||
QDateTime timestamp;
|
||||
QString mode;
|
||||
QString comment;
|
||||
QCPItemText* text = Q_NULLPTR;
|
||||
bool current = false;
|
||||
};
|
||||
|
||||
struct clusterSettings {
|
||||
QString server;
|
||||
int port=7300;
|
||||
QString userName;
|
||||
QString password;
|
||||
int timeout=30;
|
||||
bool isdefault;
|
||||
};
|
||||
|
||||
class dxClusterClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit dxClusterClient(QObject* parent = nullptr);
|
||||
virtual ~dxClusterClient();
|
||||
|
||||
signals:
|
||||
void addSpot(spotData* spot);
|
||||
void deleteSpot(QString dxcall);
|
||||
void deleteOldSpots(int minutes);
|
||||
void sendOutput(QString text);
|
||||
void sendSpots(QList<spotData> spots);
|
||||
|
||||
public slots:
|
||||
void udpDataReceived();
|
||||
void tcpDataReceived();
|
||||
void tcpDisconnected();
|
||||
void enableUdp(bool enable);
|
||||
void enableTcp(bool enable);
|
||||
void setUdpPort(int p) { udpPort = p; }
|
||||
void setTcpServerName(QString s) { tcpServerName = s; }
|
||||
void setTcpPort(int p) { tcpPort = p; }
|
||||
void setTcpUserName(QString s) { tcpUserName = s; }
|
||||
void setTcpPassword(QString s) { tcpPassword = s; }
|
||||
void setTcpTimeout(int p) { tcpTimeout = p; }
|
||||
void tcpCleanup();
|
||||
void freqRange(double low, double high);
|
||||
void enableSkimmerSpots(bool enable);
|
||||
|
||||
private:
|
||||
void sendTcpData(QString data);
|
||||
bool databaseOpen();
|
||||
void updateSpots();
|
||||
|
||||
bool udpEnable;
|
||||
bool tcpEnable;
|
||||
QUdpSocket* udpSocket=Q_NULLPTR;
|
||||
QTcpSocket* tcpSocket=Q_NULLPTR;
|
||||
int udpPort;
|
||||
QString tcpServerName;
|
||||
int tcpPort;
|
||||
QString tcpUserName;
|
||||
QString tcpPassword;
|
||||
int tcpTimeout;
|
||||
QDomDocument udpSpotReader;
|
||||
QRegularExpression tcpRegex;
|
||||
QMutex mutex;
|
||||
bool authenticated=false;
|
||||
QTimer* tcpCleanupTimer=Q_NULLPTR;
|
||||
#ifdef USESQL
|
||||
QSqlDatabase db;
|
||||
#endif
|
||||
double lowFreq;
|
||||
double highFreq;
|
||||
QMap<QString,spotData*> allSpots;
|
||||
bool skimmerSpots = false;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -18,6 +18,8 @@ struct colorPrefsType{
|
|||
QColor underlayFill;
|
||||
QColor plotBackground;
|
||||
QColor tuningLine;
|
||||
QColor passband;
|
||||
QColor pbt;
|
||||
|
||||
// Waterfall:
|
||||
QColor wfBackground;
|
||||
|
@ -32,6 +34,10 @@ struct colorPrefsType{
|
|||
QColor meterPeakScale;
|
||||
QColor meterLowerLine;
|
||||
QColor meterLowText;
|
||||
|
||||
// Assorted
|
||||
QColor clusterSpots;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -59,7 +59,11 @@ void commHandler::init()
|
|||
//qInfo(logSerial()) << "Serial buffer size: " << port->readBufferSize();
|
||||
|
||||
connect(port, SIGNAL(readyRead()), this, SLOT(receiveDataIn()));
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
connect(port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
|
||||
#else
|
||||
connect(port, SIGNAL(errorOccurred(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
|
||||
#endif
|
||||
lastDataReceived = QTime::currentTime();
|
||||
}
|
||||
|
||||
|
@ -99,6 +103,8 @@ void commHandler::sendDataOut(const QByteArray &writeData)
|
|||
|
||||
qint64 bytesWritten;
|
||||
|
||||
previousSent = writeData;
|
||||
|
||||
if(PTTviaRTS)
|
||||
{
|
||||
// Size: 1 2 3 4 5 6 7 8
|
||||
|
@ -122,7 +128,7 @@ void commHandler::sendDataOut(const QByteArray &writeData)
|
|||
printHex(pttreturncmd, false, true);
|
||||
emit haveDataFromPort(pttreturncmd);
|
||||
|
||||
|
||||
|
||||
mutex.unlock();
|
||||
return;
|
||||
} else if(writeData.endsWith(QByteArrayLiteral("\x1C\x00\x01\xFD")))
|
||||
|
@ -166,6 +172,15 @@ void commHandler::receiveDataIn()
|
|||
port->startTransaction();
|
||||
inPortData = port->readAll();
|
||||
|
||||
if (inPortData.startsWith("\xFC\xFC\xFC\xFC\xFC"))
|
||||
{
|
||||
// Colission detected by remote end, re-send previous command.
|
||||
qInfo(logSerial()) << "Collision detected by remote, resending previous command";
|
||||
port->commitTransaction();
|
||||
sendDataOut(previousSent);
|
||||
return;
|
||||
}
|
||||
|
||||
if(inPortData.size() == 1)
|
||||
{
|
||||
// Generally for baud <= 9600
|
||||
|
@ -181,7 +196,6 @@ void commHandler::receiveDataIn()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (inPortData.startsWith("\xFE\xFE"))
|
||||
{
|
||||
if(inPortData.contains("\xFC"))
|
||||
|
@ -206,7 +220,6 @@ void commHandler::receiveDataIn()
|
|||
//printHex(inPortData, false, true);
|
||||
while (pos > -1 && fdPos > -1) {
|
||||
combined++;
|
||||
spectrumDivisionNumber = 0;
|
||||
spectrumDivisionNumber = inPortData[pos + 3] & 0x0f;
|
||||
spectrumDivisionNumber += ((inPortData[pos + 3] & 0xf0) >> 4) * 10;
|
||||
|
||||
|
@ -222,8 +235,8 @@ void commHandler::receiveDataIn()
|
|||
|
||||
}
|
||||
else if (spectrumDivisionNumber > lastSpectrum && spectrumDivisionNumber <= spectrumDivisionMax) {
|
||||
spectrumData.insert(spectrumData.length(), inPortData.mid(pos + 4, fdPos-5));
|
||||
//qDebug() << "Added spectrum seq:" << spectrumDivisionNumber << "len" << fdPos-5;
|
||||
spectrumData.insert(spectrumData.length(), inPortData.mid(pos + 5, fdPos-5));
|
||||
//qInfo() << "Added spectrum seq:" << spectrumDivisionNumber << "len" << fdPos-5<< "Spec" << spectrumData.length();
|
||||
//printHex(inPortData.mid((pos+4),fdPos - (pos+5)), false, true);
|
||||
}
|
||||
else {
|
||||
|
@ -316,7 +329,7 @@ void commHandler::openPort()
|
|||
qInfo(logSerial()) << "Could not open serial port " << portName << " , please restart.";
|
||||
isConnected = false;
|
||||
serialError = true;
|
||||
emit haveSerialPortError(portName, "Could not open port. Please restart.");
|
||||
emit havePortError(errorType(true, portName, "Could not open port. Please restart."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <QTime>
|
||||
#include <QTimer>
|
||||
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
// This class abstracts the comm port in a useful way and connects to
|
||||
// the command creator and command parser.
|
||||
|
||||
|
@ -39,7 +41,7 @@ signals:
|
|||
void haveTextMessage(QString message); // status, debug only
|
||||
void sendDataOutToPort(const QByteArray &writeData); // not used
|
||||
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
|
||||
void haveSerialPortError(const QString port, const QString error);
|
||||
void havePortError(errorType err);
|
||||
void haveStatusUpdate(const QString text);
|
||||
|
||||
private:
|
||||
|
@ -55,6 +57,7 @@ private:
|
|||
//QDataStream stream;
|
||||
QByteArray outPortData;
|
||||
QByteArray inPortData;
|
||||
QByteArray previousSent;
|
||||
|
||||
//QDataStream outStream;
|
||||
//QDataStream inStream;
|
||||
|
|
|
@ -0,0 +1,996 @@
|
|||
#include "controllersetup.h"
|
||||
#include "ui_controllersetup.h"
|
||||
#include "logcategories.h"
|
||||
|
||||
controllerSetup::controllerSetup(QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::controllerSetup)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->tabWidget->clear();
|
||||
ui->tabWidget->hide();
|
||||
noControllersText = new QLabel("No USB controller found");
|
||||
noControllersText->setStyleSheet("QLabel { color : gray; }");
|
||||
ui->hboxLayout->addWidget(noControllersText);
|
||||
this->resize(this->sizeHint());
|
||||
}
|
||||
|
||||
controllerSetup::~controllerSetup()
|
||||
{
|
||||
qInfo(logUsbControl()) << "Deleting controllerSetup() window";
|
||||
delete noControllersText;
|
||||
delete updateDialog;
|
||||
delete ui; // Will delete all content in all tabs
|
||||
tabs.clear();
|
||||
// Step through ALL buttons and knobs setting their text to NULL (just in case)
|
||||
for (auto b = buttons->begin(); b != buttons->end(); b++)
|
||||
{
|
||||
b->text=Q_NULLPTR;
|
||||
b->bgRect=Q_NULLPTR;
|
||||
}
|
||||
|
||||
for (auto k= knobs->begin(); k != knobs->end(); k++)
|
||||
{
|
||||
k->text=Q_NULLPTR;
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::hideEvent(QHideEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
qDebug(logUsbControl()) << "Controller window hideEvent()";
|
||||
updateDialog->hide();
|
||||
}
|
||||
|
||||
void controllerSetup::on_tabWidget_currentChanged(int index)
|
||||
{
|
||||
// We may get the indexChanged event before the tabWidget has been initialized
|
||||
if (ui->tabWidget->widget(index) != Q_NULLPTR) {
|
||||
QString path = ui->tabWidget->widget(index)->objectName();
|
||||
auto tab = tabs.find(path);
|
||||
if (tab != tabs.end())
|
||||
{
|
||||
this->resize(this->sizeHint());
|
||||
}
|
||||
}
|
||||
|
||||
if (updateDialog != Q_NULLPTR)
|
||||
{
|
||||
updateDialog->hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void controllerSetup::init(usbDevMap* dev, QVector<BUTTON>* but, QVector<KNOB>* kb, QVector<COMMAND>* cmd, QMutex* mut)
|
||||
{
|
||||
// Store pointers to all current settings
|
||||
devices = dev;
|
||||
buttons = but;
|
||||
knobs = kb;
|
||||
commands = cmd;
|
||||
mutex = mut;
|
||||
|
||||
updateDialog = new QDialog(this);
|
||||
// Not sure if I like it Frameless or not?
|
||||
updateDialog->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
|
||||
|
||||
QGridLayout* udLayout = new QGridLayout(updateDialog);
|
||||
|
||||
onLabel = new QLabel("On");
|
||||
udLayout->addWidget(onLabel,0,0);
|
||||
onEvent = new QComboBox();
|
||||
udLayout->addWidget(onEvent,0,1);
|
||||
onLabel->setBuddy(onEvent);
|
||||
|
||||
offLabel = new QLabel("Off");
|
||||
udLayout->addWidget(offLabel,1,0);
|
||||
offEvent = new QComboBox();
|
||||
udLayout->addWidget(offEvent,1,1);
|
||||
offLabel->setBuddy(offEvent);
|
||||
|
||||
knobLabel = new QLabel("Knob");
|
||||
udLayout->addWidget(knobLabel,2,0);
|
||||
knobEvent = new QComboBox();
|
||||
udLayout->addWidget(knobEvent,2,1);
|
||||
knobLabel->setBuddy(knobEvent);
|
||||
|
||||
ledNumber = new QSpinBox();
|
||||
ledNumber->setPrefix("LED: ");
|
||||
ledNumber->setMinimum(0);
|
||||
udLayout->addWidget(ledNumber,3,1);
|
||||
|
||||
buttonLatch = new QCheckBox();
|
||||
buttonLatch->setText("Toggle");
|
||||
udLayout->addWidget(buttonLatch,4,0);
|
||||
|
||||
QHBoxLayout* colorLayout = new QHBoxLayout();
|
||||
udLayout->addLayout(colorLayout,4,1);
|
||||
|
||||
buttonOnColor = new QPushButton("Color");
|
||||
colorLayout->addWidget(buttonOnColor);
|
||||
|
||||
buttonOffColor = new QPushButton("Pressed");
|
||||
colorLayout->addWidget(buttonOffColor);
|
||||
|
||||
buttonIcon = new QPushButton("Icon");
|
||||
udLayout->addWidget(buttonIcon,5,0);
|
||||
iconLabel = new QLabel("<None>");
|
||||
udLayout->addWidget(iconLabel,5,1);
|
||||
udLayout->setAlignment(iconLabel,Qt::AlignCenter);
|
||||
udLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
|
||||
updateDialog->hide();
|
||||
|
||||
onEvent->clear();
|
||||
offEvent->clear();
|
||||
knobEvent->clear();
|
||||
|
||||
for (COMMAND& c : *commands) {
|
||||
if (c.cmdType == commandButton || c.cmdType == commandAny) {
|
||||
if (c.command == cmdSeparator) {
|
||||
onEvent->insertSeparator(onEvent->count());
|
||||
offEvent->insertSeparator(offEvent->count());
|
||||
|
||||
} else {
|
||||
onEvent->addItem(c.text, c.index);
|
||||
offEvent->addItem(c.text, c.index);
|
||||
}
|
||||
}
|
||||
if (c.cmdType == commandKnob || c.cmdType == commandAny) {
|
||||
if (c.command == cmdSeparator) {
|
||||
knobEvent->insertSeparator(knobEvent->count());
|
||||
} else {
|
||||
knobEvent->addItem(c.text, c.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connect(offEvent, SIGNAL(currentIndexChanged(int)), this, SLOT(offEventIndexChanged(int)));
|
||||
connect(onEvent, SIGNAL(currentIndexChanged(int)), this, SLOT(onEventIndexChanged(int)));
|
||||
connect(knobEvent, SIGNAL(currentIndexChanged(int)), this, SLOT(knobEventIndexChanged(int)));
|
||||
connect(buttonOnColor, SIGNAL(clicked()), this, SLOT(buttonOnColorClicked()));
|
||||
connect(buttonOffColor, SIGNAL(clicked()), this, SLOT(buttonOffColorClicked()));
|
||||
connect(buttonIcon, SIGNAL(clicked()), this, SLOT(buttonIconClicked()));
|
||||
connect(buttonLatch, SIGNAL(stateChanged(int)), this, SLOT(latchStateChanged(int)));
|
||||
connect(ledNumber, SIGNAL(valueChanged(int)), this, SLOT(ledNumberChanged(int)));
|
||||
}
|
||||
|
||||
void controllerSetup::showMenu(controllerScene* scene, QPoint p)
|
||||
{
|
||||
Q_UNUSED (scene) // We might want it in the future?
|
||||
|
||||
// Receive mouse event from the scene
|
||||
qDebug() << "Looking for knob or button at Point x=" << p.x() << " y=" << p.y();
|
||||
|
||||
QPoint gp = this->mapToGlobal(p);
|
||||
|
||||
|
||||
// Did the user click on a button?
|
||||
auto but = std::find_if(buttons->begin(), buttons->end(), [p, this](BUTTON& b)
|
||||
{ return (b.parent != Q_NULLPTR && b.pos.contains(p) && b.page == b.parent->currentPage && ui->tabWidget->currentWidget()->objectName() == b.path ); });
|
||||
|
||||
if (but != buttons->end())
|
||||
{
|
||||
currentButton = &(*but);
|
||||
currentKnob = Q_NULLPTR;
|
||||
qDebug() << "Button" << currentButton->num << "On Event" << currentButton->onCommand->text << "Off Event" << currentButton->offCommand->text;
|
||||
|
||||
updateDialog->setWindowTitle(QString("Update button %0").arg(but->num));
|
||||
|
||||
onEvent->blockSignals(true);
|
||||
onEvent->setCurrentIndex(onEvent->findData(currentButton->onCommand->index));
|
||||
onEvent->show();
|
||||
onLabel->show();
|
||||
onEvent->blockSignals(false);
|
||||
|
||||
offEvent->blockSignals(true);
|
||||
offEvent->setCurrentIndex(offEvent->findData(currentButton->offCommand->index));
|
||||
offEvent->show();
|
||||
offLabel->show();
|
||||
offEvent->blockSignals(false);
|
||||
knobEvent->hide();
|
||||
knobLabel->hide();
|
||||
|
||||
buttonLatch->blockSignals(true);
|
||||
buttonLatch->setChecked(currentButton->toggle);
|
||||
buttonLatch->blockSignals(false);
|
||||
buttonLatch->show();
|
||||
|
||||
ledNumber->blockSignals(true);
|
||||
ledNumber->setMaximum(currentButton->parent->type.leds);
|
||||
ledNumber->setValue(currentButton->led);
|
||||
ledNumber->blockSignals(false);
|
||||
|
||||
switch (currentButton->parent->type.model)
|
||||
{
|
||||
case RC28:
|
||||
case eCoderPlus:
|
||||
ledNumber->show();
|
||||
buttonOnColor->hide();
|
||||
buttonOffColor->hide();
|
||||
buttonIcon->hide();
|
||||
iconLabel->hide();
|
||||
break;
|
||||
case StreamDeckMini:
|
||||
case StreamDeckMiniV2:
|
||||
case StreamDeckOriginal:
|
||||
case StreamDeckOriginalV2:
|
||||
case StreamDeckOriginalMK2:
|
||||
case StreamDeckXL:
|
||||
case StreamDeckXLV2:
|
||||
case StreamDeckPlus:
|
||||
buttonOnColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOn.name(QColor::HexArgb)));
|
||||
buttonOffColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOff.name(QColor::HexArgb)));
|
||||
buttonOnColor->show();
|
||||
buttonOffColor->show();
|
||||
buttonIcon->show();
|
||||
iconLabel->setText(currentButton->iconName);
|
||||
iconLabel->show();
|
||||
break;
|
||||
default:
|
||||
buttonOnColor->hide();
|
||||
buttonOffColor->hide();
|
||||
buttonIcon->hide();
|
||||
iconLabel->hide();
|
||||
ledNumber->hide();
|
||||
break;
|
||||
}
|
||||
|
||||
updateDialog->show();
|
||||
updateDialog->move(gp);
|
||||
updateDialog->adjustSize();
|
||||
updateDialog->raise();
|
||||
} else {
|
||||
// It wasn't a button so was it a knob?
|
||||
auto kb = std::find_if(knobs->begin(), knobs->end(), [p, this](KNOB& k)
|
||||
{ return (k.parent != Q_NULLPTR && k.pos.contains(p) && k.page == k.parent->currentPage && ui->tabWidget->currentWidget()->objectName() == k.path ); });
|
||||
|
||||
if (kb != knobs->end())
|
||||
{
|
||||
currentKnob = &(*kb);
|
||||
currentButton = Q_NULLPTR;
|
||||
qDebug() << "Knob" << currentKnob->num << "Event" << currentKnob->command->text;
|
||||
|
||||
updateDialog->setWindowTitle(QString("Update knob %0").arg(kb->num));
|
||||
|
||||
knobEvent->blockSignals(true);
|
||||
knobEvent->setCurrentIndex(knobEvent->findData(currentKnob->command->index));
|
||||
knobEvent->show();
|
||||
knobLabel->show();
|
||||
knobEvent->blockSignals(false);
|
||||
onEvent->hide();
|
||||
offEvent->hide();
|
||||
onLabel->hide();
|
||||
offLabel->hide();
|
||||
buttonLatch->hide();
|
||||
buttonOnColor->hide();
|
||||
buttonOffColor->hide();
|
||||
buttonIcon->hide();
|
||||
iconLabel->hide();
|
||||
ledNumber->hide();
|
||||
|
||||
updateDialog->show();
|
||||
updateDialog->move(gp);
|
||||
updateDialog->adjustSize();
|
||||
updateDialog->raise();
|
||||
}
|
||||
else
|
||||
{
|
||||
// It wasn't either so hide the updateDialog();
|
||||
updateDialog->hide();
|
||||
currentButton = Q_NULLPTR;
|
||||
currentKnob = Q_NULLPTR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void controllerSetup::onEventIndexChanged(int index) {
|
||||
Q_UNUSED(index);
|
||||
// If command is changed, delete current command and deep copy the new command
|
||||
if (currentButton != Q_NULLPTR && onEvent->currentData().toInt() < commands->size()) {
|
||||
QMutexLocker locker(mutex);
|
||||
currentButton->onCommand = &commands->at(onEvent->currentData().toInt());
|
||||
currentButton->text->setPlainText(currentButton->onCommand->text);
|
||||
currentButton->text->setPos(currentButton->pos.center().x() - currentButton->text->boundingRect().width() / 2,
|
||||
(currentButton->pos.center().y() - currentButton->text->boundingRect().height() / 2));
|
||||
// Signal that any button programming on the device should be completed.
|
||||
if (currentButton->icon == Q_NULLPTR) {
|
||||
emit sendRequest(currentButton->parent,usbFeatureType::featureButton,currentButton->num,currentButton->onCommand->text,Q_NULLPTR,¤tButton->backgroundOn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void controllerSetup::offEventIndexChanged(int index) {
|
||||
Q_UNUSED(index);
|
||||
// If command is changed, delete current command and deep copy the new command
|
||||
if (currentButton != Q_NULLPTR && offEvent->currentData().toInt() < commands->size()) {
|
||||
QMutexLocker locker(mutex);
|
||||
currentButton->offCommand = &commands->at(offEvent->currentData().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::ledNumberChanged(int index) {
|
||||
if (currentButton != Q_NULLPTR) {
|
||||
QMutexLocker locker(mutex);
|
||||
currentButton->led = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void controllerSetup::knobEventIndexChanged(int index) {
|
||||
Q_UNUSED(index);
|
||||
// If command is changed, delete current command and deep copy the new command
|
||||
if (currentKnob != Q_NULLPTR && knobEvent->currentData().toInt() < commands->size()) {
|
||||
QMutexLocker locker(mutex);
|
||||
currentKnob->command = &commands->at(knobEvent->currentData().toInt());
|
||||
currentKnob->text->setPlainText(currentKnob->command->text);
|
||||
currentKnob->text->setPos(currentKnob->pos.center().x() - currentKnob->text->boundingRect().width() / 2,
|
||||
(currentKnob->pos.center().y() - currentKnob->text->boundingRect().height() / 2));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void controllerSetup::buttonOnColorClicked()
|
||||
{
|
||||
QColorDialog::ColorDialogOptions options;
|
||||
options.setFlag(QColorDialog::ShowAlphaChannel, false);
|
||||
options.setFlag(QColorDialog::DontUseNativeDialog, false);
|
||||
QColor selColor = QColorDialog::getColor(currentButton->backgroundOn, this, "Select Color to use for unpressed button", options);
|
||||
|
||||
if(selColor.isValid() && currentButton != Q_NULLPTR)
|
||||
{
|
||||
QMutexLocker locker(mutex);
|
||||
currentButton->backgroundOn = selColor;
|
||||
if (currentButton->graphics && currentButton->bgRect != Q_NULLPTR)
|
||||
{
|
||||
currentButton->bgRect->setBrush(currentButton->backgroundOn);
|
||||
}
|
||||
buttonOnColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOn.name(QColor::HexArgb)));
|
||||
emit sendRequest(currentButton->parent,usbFeatureType::featureButton,currentButton->num,currentButton->onCommand->text,currentButton->icon,¤tButton->backgroundOn);
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::buttonOffColorClicked()
|
||||
{
|
||||
QColorDialog::ColorDialogOptions options;
|
||||
options.setFlag(QColorDialog::ShowAlphaChannel, false);
|
||||
options.setFlag(QColorDialog::DontUseNativeDialog, false);
|
||||
QColor selColor = QColorDialog::getColor(currentButton->backgroundOff, this, "Select Color to use for pressed button", options);
|
||||
|
||||
if(selColor.isValid() && currentButton != Q_NULLPTR)
|
||||
{
|
||||
QMutexLocker locker(mutex);
|
||||
currentButton->backgroundOff = selColor;
|
||||
buttonOffColor->setStyleSheet(QString("background-color: %1").arg(currentButton->backgroundOff.name(QColor::HexArgb)));
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::buttonIconClicked()
|
||||
{
|
||||
QString file = QFileDialog::getOpenFileName(this,"Select Icon Filename",".","Images (*png *.jpg)");
|
||||
if (!file.isEmpty()) {
|
||||
QFileInfo info = QFileInfo(file);
|
||||
currentButton->iconName = info.fileName();
|
||||
iconLabel->setText(currentButton->iconName);
|
||||
QImage image;
|
||||
image.load(file);
|
||||
if (currentButton->icon != Q_NULLPTR)
|
||||
delete currentButton->icon;
|
||||
currentButton->icon = new QImage(image.scaled(currentButton->parent->type.iconSize,currentButton->parent->type.iconSize));
|
||||
} else {
|
||||
if (currentButton->icon != Q_NULLPTR)
|
||||
{
|
||||
currentButton->iconName = "";
|
||||
delete currentButton->icon;
|
||||
currentButton->icon = Q_NULLPTR;
|
||||
}
|
||||
}
|
||||
iconLabel->setText(currentButton->iconName);
|
||||
emit sendRequest(currentButton->parent,usbFeatureType::featureButton,currentButton->num,currentButton->onCommand->text,currentButton->icon, ¤tButton->backgroundOn);
|
||||
}
|
||||
|
||||
void controllerSetup::latchStateChanged(int state)
|
||||
{
|
||||
if (currentButton != Q_NULLPTR) {
|
||||
QMutexLocker locker(mutex);
|
||||
currentButton->toggle=(int)state;
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::removeDevice(USBDEVICE* dev)
|
||||
{
|
||||
QMutexLocker locker(mutex);
|
||||
|
||||
/* We need to manually delete everything that has been created for this tab */
|
||||
auto tab = tabs.find(dev->path);
|
||||
if (tab == tabs.end())
|
||||
{
|
||||
qWarning(logUsbControl()) << "Cannot find tabContent for deleted tab" << dev->path;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto b = buttons->begin();b != buttons->end(); b++)
|
||||
{
|
||||
if (b->parent == dev && b->page == dev->currentPage)
|
||||
{
|
||||
if (b->text != Q_NULLPTR) {
|
||||
tab.value()->scene->removeItem(b->text);
|
||||
delete b->text;
|
||||
b->text = Q_NULLPTR;
|
||||
}
|
||||
b->offCommand = Q_NULLPTR;
|
||||
b->onCommand = Q_NULLPTR;
|
||||
if (b->icon != Q_NULLPTR) {
|
||||
delete b->icon;
|
||||
b->icon=Q_NULLPTR;
|
||||
}
|
||||
if (b->bgRect != Q_NULLPTR) {
|
||||
tab.value()->scene->removeItem(b->bgRect);
|
||||
delete b->bgRect;
|
||||
b->bgRect = Q_NULLPTR;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (auto k = knobs->begin();k != knobs->end(); k++)
|
||||
{
|
||||
if (k->parent == dev && k->page == dev->currentPage)
|
||||
{
|
||||
if (k->text != Q_NULLPTR) {
|
||||
tab.value()->scene->removeItem(k->text);
|
||||
delete k->text;
|
||||
k->text = Q_NULLPTR;
|
||||
k->command = Q_NULLPTR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qDebug(logUsbControl()) << "Removing tab content" << dev->product;
|
||||
|
||||
if (tab.value()->bgImage != Q_NULLPTR) {
|
||||
tab.value()->scene->removeItem(tab.value()->bgImage);
|
||||
delete tab.value()->bgImage;
|
||||
}
|
||||
delete tab.value()->scene;
|
||||
|
||||
// Find the tab within the tabWidget
|
||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||
auto widget = ui->tabWidget->widget(i);
|
||||
if (widget->objectName() == dev->path) {
|
||||
ui->tabWidget->removeTab(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete tab.value();
|
||||
tabs.remove(dev->path);
|
||||
|
||||
// Hide the tabWidget if no tabs exist
|
||||
if (ui->tabWidget->count() == 0)
|
||||
{
|
||||
ui->tabWidget->hide();
|
||||
noControllersText->show();
|
||||
this->adjustSize();
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::newDevice(USBDEVICE* dev)
|
||||
{
|
||||
QMutexLocker locker(mutex);
|
||||
|
||||
for (int i=0; i<ui->tabWidget->count();i++) {
|
||||
if (ui->tabWidget->widget(i)->objectName() == dev->path)
|
||||
{
|
||||
qInfo(logUsbControl()) <<"Tab for " << dev->product << "("<< dev->path << ") Already exists!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto tab = tabs.find(dev->path);
|
||||
if (tab != tabs.end())
|
||||
{
|
||||
qInfo(logUsbControl()) <<"Tab content for " << dev->product << "("<< dev->path << ") Already exists!";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
qDebug(logUsbControl()) << "Adding new tab for" << dev->product;
|
||||
noControllersText->hide();
|
||||
|
||||
tabContent* c = new tabContent();
|
||||
|
||||
c->tab = new QWidget();
|
||||
c->widget = new QWidget();
|
||||
|
||||
c->tab->setObjectName(dev->path);
|
||||
ui->tabWidget->addTab(c->tab,dev->product);
|
||||
|
||||
// Create the different layouts required
|
||||
c->mainLayout = new QVBoxLayout(c->tab);
|
||||
c->layout = new QVBoxLayout();
|
||||
c->topLayout = new QHBoxLayout();
|
||||
c->sensLayout = new QHBoxLayout();
|
||||
c->grid = new QGridLayout();
|
||||
|
||||
c->mainLayout->addLayout(c->topLayout);
|
||||
c->mainLayout->addWidget(c->widget);
|
||||
c->widget->setLayout(c->layout);
|
||||
|
||||
c->disabled = new QCheckBox("Disable");
|
||||
c->topLayout->addWidget(c->disabled);
|
||||
connect(c->disabled, qOverload<bool>(&QCheckBox::clicked),
|
||||
[dev,this,c](bool checked) { this->disableClicked(dev,checked,c->widget); });
|
||||
c->disabled->setChecked(dev->disabled);
|
||||
|
||||
c->message = new QLabel();
|
||||
if (dev->connected) {
|
||||
c->message->setStyleSheet("QLabel { color : green; }");
|
||||
c->message->setText("Connected");
|
||||
} else {
|
||||
c->message->setStyleSheet("QLabel { color : red; }");
|
||||
c->message->setText("Not Connected");
|
||||
}
|
||||
c->topLayout->addWidget(c->message);
|
||||
c->message->setAlignment(Qt::AlignRight);
|
||||
|
||||
c->view = new QGraphicsView();
|
||||
c->layout->addWidget(c->view);
|
||||
|
||||
c->layout->addLayout(c->sensLayout);
|
||||
c->sensLabel = new QLabel("Sensitivity");
|
||||
c->sensLayout->addWidget(c->sensLabel);
|
||||
c->sens = new QSlider(Qt::Horizontal);
|
||||
c->sens->setMinimum(1);
|
||||
c->sens->setMaximum(21);
|
||||
c->sens->setInvertedAppearance(true);
|
||||
c->sensLayout->addWidget(c->sens);
|
||||
c->sens->setValue(dev->sensitivity);
|
||||
connect(c->sens, &QSlider::valueChanged,
|
||||
[dev,this](int val) { this->sensitivityMoved(dev,val); });
|
||||
|
||||
c->sensLayout->addStretch(0);
|
||||
|
||||
c->pageLabel = new QLabel("Page:");
|
||||
c->sensLayout->addWidget(c->pageLabel);
|
||||
c->page = new QSpinBox();
|
||||
c->page->setValue(1);
|
||||
c->page->setMinimum(1);
|
||||
c->page->setMaximum(dev->pages);
|
||||
c->page->setToolTip("Select current page to edit");
|
||||
c->sensLayout->addWidget(c->page);
|
||||
dev->pageSpin = c->page;
|
||||
|
||||
c->image = new QImage();
|
||||
switch (dev->type.model) {
|
||||
case shuttleXpress:
|
||||
c->image->load(":/resources/shuttlexpress.png");
|
||||
break;
|
||||
case shuttlePro2:
|
||||
c->image->load(":/resources/shuttlepro.png");
|
||||
break;
|
||||
case RC28:
|
||||
c->image->load(":/resources/rc28.png");
|
||||
break;
|
||||
case xBoxGamepad:
|
||||
c->image->load(":/resources/xbox.png");
|
||||
break;
|
||||
case eCoderPlus:
|
||||
c->image->load(":/resources/ecoder.png");
|
||||
break;
|
||||
case QuickKeys:
|
||||
c->image->load(":/resources/quickkeys.png");
|
||||
break;
|
||||
case StreamDeckOriginal:
|
||||
case StreamDeckOriginalV2:
|
||||
case StreamDeckOriginalMK2:
|
||||
c->image->load(":/resources/streamdeck.png");
|
||||
break;
|
||||
case StreamDeckMini:
|
||||
case StreamDeckMiniV2:
|
||||
c->image->load(":/resources/streamdeckmini.png");
|
||||
break;
|
||||
case StreamDeckXL:
|
||||
case StreamDeckXLV2:
|
||||
c->image->load(":/resources/streamdeckxl.png");
|
||||
break;
|
||||
case StreamDeckPlus:
|
||||
c->image->load(":/resources/streamdeckplus.png");
|
||||
break;
|
||||
case StreamDeckPedal:
|
||||
c->image->load(":/resources/streamdeckpedal.png");
|
||||
break;
|
||||
default:
|
||||
this->adjustSize();
|
||||
break;
|
||||
}
|
||||
|
||||
c->bgImage = new QGraphicsPixmapItem(QPixmap::fromImage(*c->image));
|
||||
c->view->setMinimumSize(c->bgImage->boundingRect().width() + 2, c->bgImage->boundingRect().height() + 2);
|
||||
ui->tabWidget->show();
|
||||
|
||||
c->scene = new controllerScene();
|
||||
c->view->setScene(c->scene);
|
||||
connect(c->scene, SIGNAL(showMenu(controllerScene*,QPoint)), this, SLOT(showMenu(controllerScene*,QPoint)));
|
||||
c->scene->addItem(c->bgImage);
|
||||
|
||||
|
||||
c->layout->addLayout(c->grid);
|
||||
|
||||
c->brightLabel = new QLabel("Brightness");
|
||||
c->grid->addWidget(c->brightLabel,0,0);
|
||||
c->brightness = new QComboBox();
|
||||
c->brightness->addItem("Off");
|
||||
c->brightness->addItem("Low");
|
||||
c->brightness->addItem("Medium");
|
||||
c->brightness->addItem("High");
|
||||
c->brightness->setCurrentIndex(dev->brightness);
|
||||
c->grid->addWidget(c->brightness,1,0);
|
||||
connect(c->brightness, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
[dev,this](int index) { this->brightnessChanged(dev,index); });
|
||||
|
||||
c->speedLabel = new QLabel("Speed");
|
||||
c->grid->addWidget(c->speedLabel,0,1);
|
||||
c->speed = new QComboBox();
|
||||
c->speed->addItem("Fastest");
|
||||
c->speed->addItem("Faster");
|
||||
c->speed->addItem("Normal");
|
||||
c->speed->addItem("Slower");
|
||||
c->speed->addItem("Slowest");
|
||||
c->speed->setCurrentIndex(dev->speed);
|
||||
c->grid->addWidget(c->speed,1,1);
|
||||
connect(c->speed, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
[dev,this](int index) { this->speedChanged(dev,index); });
|
||||
|
||||
c->orientLabel = new QLabel("Orientation");
|
||||
c->grid->addWidget(c->orientLabel,0,2);
|
||||
c->orientation = new QComboBox();
|
||||
c->orientation->addItem("Rotate 0");
|
||||
c->orientation->addItem("Rotate 90");
|
||||
c->orientation->addItem("Rotate 180");
|
||||
c->orientation->addItem("Rotate 270");
|
||||
c->orientation->setCurrentIndex(dev->orientation);
|
||||
c->grid->addWidget(c->orientation,1,2);
|
||||
connect(c->orientation, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
[dev,this](int index) { this->orientationChanged(dev,index); });
|
||||
|
||||
c->color = new QPushButton("Color");
|
||||
c->color->setStyleSheet(QString("background-color: %1").arg(dev->color.name(QColor::HexArgb)));
|
||||
c->grid->addWidget(c->color,1,3);
|
||||
connect(c->color, &QPushButton::clicked,
|
||||
[dev,c,this]() { this->colorPicker(dev,c->color,dev->color); });
|
||||
|
||||
c->timeoutLabel = new QLabel("Timeout");
|
||||
c->grid->addWidget(c->timeoutLabel,0,4);
|
||||
c->timeout = new QSpinBox();
|
||||
c->timeout->setValue(dev->timeout);
|
||||
c->grid->addWidget(c->timeout,1,4);
|
||||
connect(c->timeout, qOverload<int>(&QSpinBox::valueChanged),
|
||||
[dev,this](int index) { this->timeoutChanged(dev,index); });
|
||||
|
||||
c->pagesLabel = new QLabel("Num Pages");
|
||||
c->grid->addWidget(c->pagesLabel,0,5);
|
||||
c->pages = new QSpinBox();
|
||||
c->pages->setValue(dev->pages);
|
||||
c->pages->setMinimum(1);
|
||||
c->grid->addWidget(c->pages,1,5);
|
||||
connect(c->pages, qOverload<int>(&QSpinBox::valueChanged),
|
||||
[dev,this](int index) { this->pagesChanged(dev,index); });
|
||||
|
||||
for (int i=0;i<6;i++)
|
||||
c->grid->setColumnStretch(i,1);
|
||||
|
||||
c->helpText = new QLabel();
|
||||
c->helpText->setText("<p><b>Button configuration:</b> Right-click on each button to configure it.</p>");
|
||||
c->helpText->setAlignment(Qt::AlignCenter);
|
||||
c->layout->addWidget(c->helpText);
|
||||
|
||||
|
||||
c->view->setSceneRect(c->scene->itemsBoundingRect());
|
||||
|
||||
this->adjustSize();
|
||||
|
||||
numTabs++;
|
||||
tabs.insert(dev->path,c);
|
||||
|
||||
dev->uiCreated = true;
|
||||
|
||||
// Finally update the device with the default values
|
||||
emit sendRequest(dev,usbFeatureType::featureSensitivity,dev->sensitivity);
|
||||
emit sendRequest(dev,usbFeatureType::featureBrightness,dev->brightness);
|
||||
emit sendRequest(dev,usbFeatureType::featureOrientation,dev->orientation);
|
||||
emit sendRequest(dev,usbFeatureType::featureSpeed,dev->speed);
|
||||
emit sendRequest(dev,usbFeatureType::featureTimeout,dev->timeout);
|
||||
emit sendRequest(dev,usbFeatureType::featureColor,0,"", Q_NULLPTR, &dev->color);
|
||||
|
||||
|
||||
|
||||
// Attach pageChanged() here so we have access to all necessary vars
|
||||
connect(c->page, qOverload<int>(&QSpinBox::valueChanged),
|
||||
[dev, this](int index) { this->pageChanged(dev, index); });
|
||||
|
||||
// Hide all controls that are not relevant to this controller
|
||||
// We rely on being able to fallthrough case
|
||||
#if defined __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
|
||||
switch (dev->type.model) {
|
||||
case QuickKeys:
|
||||
break;
|
||||
case StreamDeckPedal:
|
||||
c->sensLabel->setVisible(false);
|
||||
c->sens->setVisible(false);
|
||||
case shuttleXpress:
|
||||
case shuttlePro2:
|
||||
case RC28:
|
||||
case xBoxGamepad:
|
||||
case eCoderPlus:
|
||||
c->brightLabel->setVisible(false);
|
||||
c->speedLabel->setVisible(false);
|
||||
c->timeoutLabel->setVisible(false);
|
||||
c->orientLabel->setVisible(false);
|
||||
c->brightness->setVisible(false);
|
||||
c->speed->setVisible(false);
|
||||
c->timeout->setVisible(false);
|
||||
c->orientation->setVisible(false);
|
||||
c->color->setVisible(false);
|
||||
break;
|
||||
case StreamDeckOriginal:
|
||||
case StreamDeckOriginalV2:
|
||||
case StreamDeckOriginalMK2:
|
||||
case StreamDeckMini:
|
||||
case StreamDeckMiniV2:
|
||||
case StreamDeckXL:
|
||||
case StreamDeckXLV2:
|
||||
c->sensLabel->setVisible(false);
|
||||
c->sens->setVisible(false); // No knobs!
|
||||
case StreamDeckPlus:
|
||||
c->speedLabel->setVisible(false);
|
||||
c->timeoutLabel->setVisible(false);
|
||||
c->orientLabel->setVisible(false);
|
||||
c->speed->setVisible(false);
|
||||
c->timeout->setVisible(false);
|
||||
c->orientation->setVisible(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't allow fallthrough elsewhere in the file.
|
||||
#if defined __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// pageChanged will update the buttons/knobs for the tab (using qTimer ensures mutex is unlocked first)
|
||||
QTimer::singleShot(0, this, [=]() { pageChanged(dev,1); });
|
||||
|
||||
}
|
||||
|
||||
void controllerSetup::sensitivityMoved(USBDEVICE* dev, int val)
|
||||
{
|
||||
qInfo(logUsbControl()) << "Setting sensitivity" << val <<"for device" << dev->product;
|
||||
emit sendRequest(dev,usbFeatureType::featureSensitivity,val);
|
||||
}
|
||||
|
||||
void controllerSetup::brightnessChanged(USBDEVICE* dev, int index)
|
||||
{
|
||||
emit sendRequest(dev,usbFeatureType::featureBrightness,index);
|
||||
}
|
||||
|
||||
void controllerSetup::orientationChanged(USBDEVICE* dev, int index)
|
||||
{
|
||||
emit sendRequest(dev,usbFeatureType::featureOrientation,index);
|
||||
}
|
||||
|
||||
void controllerSetup::speedChanged(USBDEVICE* dev, int index)
|
||||
{
|
||||
emit sendRequest(dev,usbFeatureType::featureSpeed,index);
|
||||
}
|
||||
|
||||
void controllerSetup::colorPicker(USBDEVICE* dev, QPushButton* btn, QColor current)
|
||||
{
|
||||
QColorDialog::ColorDialogOptions options;
|
||||
options.setFlag(QColorDialog::ShowAlphaChannel, false);
|
||||
options.setFlag(QColorDialog::DontUseNativeDialog, false);
|
||||
QColor selColor = QColorDialog::getColor(current, this, "Select Color", options);
|
||||
|
||||
if(selColor.isValid())
|
||||
{
|
||||
btn->setStyleSheet(QString("background-color: %1").arg(selColor.name(QColor::HexArgb)));
|
||||
emit sendRequest(dev,usbFeatureType::featureColor,0, "", Q_NULLPTR, &selColor);
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::timeoutChanged(USBDEVICE* dev, int val)
|
||||
{
|
||||
emit sendRequest(dev,usbFeatureType::featureTimeout,val);
|
||||
emit sendRequest(dev,usbFeatureType::featureOverlay,val,QString("Sleep timeout set to %0 minutes").arg(val));
|
||||
}
|
||||
|
||||
void controllerSetup::pagesChanged(USBDEVICE* dev, int val)
|
||||
{
|
||||
emit programPages(dev,val);
|
||||
dev->pageSpin->setMaximum(val); // Update pageSpin
|
||||
}
|
||||
|
||||
void controllerSetup::pageChanged(USBDEVICE* dev, int val)
|
||||
{
|
||||
|
||||
QMutexLocker locker(mutex);
|
||||
|
||||
auto tab = tabs.find(dev->path);
|
||||
if (tab == tabs.end())
|
||||
{
|
||||
qWarning(logUsbControl()) << "Cannot find tabContent while changing page" << dev->path;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (val > dev->pages)
|
||||
val=1;
|
||||
if (val < 1)
|
||||
val = dev->pages;
|
||||
|
||||
updateDialog->hide(); // Hide the dialog if the page changes.
|
||||
|
||||
dev->currentPage=val;
|
||||
|
||||
// Need to block signals so this isn't called recursively.
|
||||
dev->pageSpin->blockSignals(true);
|
||||
dev->pageSpin->setValue(val);
|
||||
dev->pageSpin->blockSignals(false);
|
||||
|
||||
// (re)set button text
|
||||
for (auto b = buttons->begin();b != buttons->end(); b++)
|
||||
{
|
||||
if (b->parent == dev)
|
||||
{
|
||||
// Make sure we delete any other pages content and then update to latest.
|
||||
if (b->text != Q_NULLPTR) {
|
||||
tab.value()->scene->removeItem(b->text);
|
||||
delete b->text;
|
||||
b->text = Q_NULLPTR;
|
||||
}
|
||||
if (b->graphics && b->bgRect != Q_NULLPTR) {
|
||||
tab.value()->scene->removeItem(b->bgRect);
|
||||
delete b->bgRect;
|
||||
b->bgRect = Q_NULLPTR;
|
||||
}
|
||||
if (b->page == dev->currentPage)
|
||||
{
|
||||
if (b->graphics)
|
||||
{
|
||||
b->bgRect = new QGraphicsRectItem(b->pos);
|
||||
b->bgRect->setBrush(b->backgroundOn);
|
||||
tab.value()->scene->addItem(b->bgRect);
|
||||
}
|
||||
b->text = new QGraphicsTextItem(b->onCommand->text);
|
||||
b->text->setDefaultTextColor(b->textColour);
|
||||
tab.value()->scene->addItem(b->text);
|
||||
b->text->setPos(b->pos.center().x() - b->text->boundingRect().width() / 2,
|
||||
(b->pos.center().y() - b->text->boundingRect().height() / 2));
|
||||
emit sendRequest(dev,usbFeatureType::featureButton,b->num,b->onCommand->text,b->icon,&b->backgroundOn);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set knob text
|
||||
|
||||
for (auto k = knobs->begin();k != knobs->end(); k++)
|
||||
{
|
||||
if (k->parent == dev) {
|
||||
if (k->text != Q_NULLPTR) {
|
||||
tab.value()->scene->removeItem(k->text);
|
||||
delete k->text;
|
||||
k->text = Q_NULLPTR;
|
||||
}
|
||||
if (k->page == dev->currentPage)
|
||||
{
|
||||
k->text = new QGraphicsTextItem(k->command->text);
|
||||
k->text->setDefaultTextColor(k->textColour);
|
||||
tab.value()->scene->addItem(k->text);
|
||||
k->text->setPos(k->pos.center().x() - k->text->boundingRect().width() / 2,
|
||||
(k->pos.center().y() - k->text->boundingRect().height() / 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::disableClicked(USBDEVICE* dev, bool clicked, QWidget* widget)
|
||||
{
|
||||
// Disable checkbox has been clicked
|
||||
emit programDisable(dev, clicked);
|
||||
|
||||
widget->setEnabled(!clicked);
|
||||
|
||||
}
|
||||
|
||||
void controllerSetup::setConnected(USBDEVICE* dev)
|
||||
{
|
||||
QMutexLocker locker(mutex);
|
||||
|
||||
|
||||
auto tab = tabs.find(dev->path);
|
||||
if (tab != tabs.end())
|
||||
{
|
||||
if (dev->connected)
|
||||
{
|
||||
tab.value()->message->setStyleSheet("QLabel { color : green; }");
|
||||
tab.value()->message->setText("Connected");
|
||||
} else {
|
||||
tab.value()->message->setStyleSheet("QLabel { color : red; }");
|
||||
tab.value()->message->setText("Not Connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::on_backupButton_clicked()
|
||||
{
|
||||
QString file = QFileDialog::getSaveFileName(this,"Select Backup Filename",".","Backup Files (*.ini)");
|
||||
if (!file.isEmpty()) {
|
||||
auto devIt = devices->find(ui->tabWidget->currentWidget()->objectName());
|
||||
if (devIt==devices->end())
|
||||
{
|
||||
qWarning(logUsbControl) << "on_restoreButton_clicked() Cannot find existing controller, aborting!";
|
||||
}
|
||||
else
|
||||
{
|
||||
emit backup(&devIt.value(), file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void controllerSetup::on_restoreButton_clicked()
|
||||
{
|
||||
QMutexLocker locker(mutex);
|
||||
|
||||
QString file = QFileDialog::getOpenFileName(this,"Select Backup Filename",".","Backup Files (*.ini)");
|
||||
if (!file.isEmpty()) {
|
||||
QString path = ui->tabWidget->currentWidget()->objectName();
|
||||
|
||||
auto devIt = devices->find(path);
|
||||
if (devIt==devices->end())
|
||||
{
|
||||
qWarning(logUsbControl) << "on_restoreButton_clicked() Cannot find existing controller, aborting!";
|
||||
return;
|
||||
}
|
||||
auto dev = &devIt.value();
|
||||
|
||||
QSettings* settings = new QSettings(file, QSettings::Format::IniFormat);
|
||||
QString version = settings->value("Version", "").toString();
|
||||
settings->beginGroup("Controller");
|
||||
QString model = settings->value("Model","").toString();
|
||||
delete settings;
|
||||
|
||||
if (model != dev->product) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("Stored controller does not match");
|
||||
msgBox.setInformativeText(QString("Backup: %0 \nCurrent: %1\n\nThis will probably not work!").arg(model,dev->product));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||
msgBox.setDefaultButton(QMessageBox::Cancel);
|
||||
int ret= msgBox.exec();
|
||||
if (ret == QMessageBox::Cancel) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (version != QString(WFVIEW_VERSION))
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("Version mismatch");
|
||||
msgBox.setInformativeText(QString("Backup was from a different version of wfview\nBackup: %0 \nCurrent: %1\n\nPlease verify compatibility").arg(version, QString(WFVIEW_VERSION)));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||
msgBox.setDefaultButton(QMessageBox::Cancel);
|
||||
int ret= msgBox.exec();
|
||||
if (ret == QMessageBox::Cancel) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
emit restore(dev, file);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
#ifndef CONTROLLERSETUP_H
|
||||
#define CONTROLLERSETUP_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsTextItem>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsRectItem>
|
||||
#include <QPoint>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QVector>
|
||||
#include <QRect>
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QAbstractItemView>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
#include <QScopedPointer>
|
||||
#include <QCheckBox>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QLayoutItem>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QColorDialog>
|
||||
#include <QWidget>
|
||||
#include <QSpinBox>
|
||||
#include <QCheckBox>
|
||||
|
||||
#include "usbcontroller.h"
|
||||
|
||||
|
||||
class controllerScene : public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
QGraphicsLineItem* item = Q_NULLPTR;
|
||||
|
||||
signals:
|
||||
void showMenu(controllerScene* scene, QPoint p);
|
||||
void buttonAction(bool pressed, QPoint p);
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent* event) {
|
||||
|
||||
if (event->button() == Qt::RightButton)
|
||||
{
|
||||
emit showMenu(this, event->scenePos().toPoint());
|
||||
}
|
||||
else if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
// Simulate a button press
|
||||
emit buttonAction(true,event->scenePos().toPoint());
|
||||
}
|
||||
else
|
||||
{
|
||||
QGraphicsScene::mousePressEvent(event);
|
||||
}
|
||||
}
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
// Simulate a button release
|
||||
emit buttonAction(false,event->scenePos().toPoint());
|
||||
}
|
||||
else
|
||||
{
|
||||
QGraphicsScene::mouseReleaseEvent(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct tabContent {
|
||||
QWidget* tab;
|
||||
QVBoxLayout* mainLayout;
|
||||
QHBoxLayout* topLayout;
|
||||
QWidget* widget;
|
||||
QVBoxLayout* layout;
|
||||
QCheckBox* disabled;
|
||||
QLabel* message;
|
||||
QGraphicsView* view;
|
||||
QLabel* pageLabel;
|
||||
QSpinBox* page;
|
||||
QHBoxLayout* sensLayout;
|
||||
QLabel* sensLabel;
|
||||
QSlider* sens;
|
||||
QImage* image;
|
||||
QGraphicsItem* bgImage = Q_NULLPTR;
|
||||
controllerScene* scene = Q_NULLPTR;
|
||||
QGridLayout* grid;
|
||||
QLabel* brightLabel;
|
||||
QComboBox* brightness;
|
||||
QLabel* speedLabel;
|
||||
QComboBox* speed;
|
||||
QLabel* orientLabel;
|
||||
QComboBox* orientation;
|
||||
QLabel* colorLabel;
|
||||
QPushButton* color;
|
||||
QLabel* timeoutLabel;
|
||||
QSpinBox* timeout;
|
||||
QLabel* pagesLabel;
|
||||
QSpinBox* pages;
|
||||
QLabel* helpText;
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class controllerSetup;
|
||||
}
|
||||
|
||||
class controllerSetup : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit controllerSetup(QWidget* parent = 0);
|
||||
~controllerSetup();
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void sendRequest(USBDEVICE* dev, usbFeatureType request, int val=0, QString text="", QImage* img=Q_NULLPTR, QColor* color=Q_NULLPTR);
|
||||
void programDisable(USBDEVICE* dev, bool disable);
|
||||
void programPages(USBDEVICE* dev, int pages);
|
||||
void backup(USBDEVICE* dev, QString path);
|
||||
void restore(USBDEVICE *dev, QString path);
|
||||
|
||||
public slots:
|
||||
void init(usbDevMap* dev, QVector<BUTTON>* but, QVector<KNOB>* kb, QVector<COMMAND>* cmd, QMutex* mut);
|
||||
void newDevice(USBDEVICE* dev);
|
||||
void removeDevice(USBDEVICE* dev);
|
||||
void showMenu(controllerScene *scene,QPoint p);
|
||||
void onEventIndexChanged(int index);
|
||||
void offEventIndexChanged(int index);
|
||||
void knobEventIndexChanged(int index);
|
||||
void ledNumberChanged(int index);
|
||||
void sensitivityMoved(USBDEVICE* dev, int val);
|
||||
void brightnessChanged(USBDEVICE* dev, int index);
|
||||
void orientationChanged(USBDEVICE* dev, int index);
|
||||
void speedChanged(USBDEVICE* dev, int index);
|
||||
void colorPicker(USBDEVICE* dev, QPushButton* btn, QColor color);
|
||||
void buttonOnColorClicked();
|
||||
void buttonOffColorClicked();
|
||||
void buttonIconClicked();
|
||||
void latchStateChanged(int state);
|
||||
|
||||
void timeoutChanged(USBDEVICE* dev, int val);
|
||||
void pageChanged(USBDEVICE* dev, int val);
|
||||
void pagesChanged(USBDEVICE* dev, int val);
|
||||
void disableClicked(USBDEVICE* dev, bool clicked, QWidget* widget);
|
||||
void setConnected(USBDEVICE* dev);
|
||||
void hideEvent(QHideEvent *event);
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
void on_backupButton_clicked();
|
||||
void on_restoreButton_clicked();
|
||||
|
||||
private:
|
||||
|
||||
usbDeviceType type = usbNone;
|
||||
Ui::controllerSetup* ui;
|
||||
QGraphicsTextItem* textItem;
|
||||
QLabel* imgLabel;
|
||||
unsigned char currentDevice = 0;
|
||||
QVector<BUTTON>* buttons;
|
||||
QVector<KNOB>* knobs;
|
||||
QVector<COMMAND>* commands;
|
||||
usbDevMap* devices;
|
||||
|
||||
BUTTON* currentButton = Q_NULLPTR;
|
||||
KNOB* currentKnob = Q_NULLPTR;
|
||||
|
||||
// Update Dialog
|
||||
QDialog * updateDialog = Q_NULLPTR;
|
||||
QComboBox* onEvent;
|
||||
QComboBox* offEvent;
|
||||
QComboBox* knobEvent;
|
||||
QLabel* onLabel;
|
||||
QLabel* offLabel;
|
||||
QLabel* knobLabel;
|
||||
QPushButton* buttonOnColor;
|
||||
QPushButton* buttonOffColor;
|
||||
QCheckBox *buttonLatch;
|
||||
QPushButton* buttonIcon;
|
||||
QLabel* iconLabel;
|
||||
QSpinBox* ledNumber;
|
||||
|
||||
QString deviceName;
|
||||
QMutex* mutex;
|
||||
QColor initialColor = Qt::white;
|
||||
|
||||
QLabel* noControllersText;
|
||||
|
||||
int numTabs=0;
|
||||
QMap<QString,tabContent*> tabs;
|
||||
|
||||
// Below are used for each tab:
|
||||
/*
|
||||
QList<QWidget *> tabs;
|
||||
QList<QVBoxLayout *> layouts;
|
||||
QList<QWidget *> widgets;
|
||||
QList<QGraphicsView *> graphicsViews;
|
||||
QList<QGraphicsScene*> scenes;
|
||||
QList<QGraphicsItem*> bgImages;
|
||||
QList<QSlider *>sensitivitys;
|
||||
|
||||
// Just used for QuickKeys device
|
||||
QList<QComboBox *>brightCombos;
|
||||
QList<QComboBox *>speedCombos;
|
||||
QList<QComboBox *>orientCombos;
|
||||
QList<QPushButton *>colorButtons;
|
||||
QList<QSpinBox *>timeoutSpins;
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,134 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>controllerSetup</class>
|
||||
<widget class="QDialog" name="controllerSetup">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>788</width>
|
||||
<height>646</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Controller setup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::North</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Tab 1</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Tab 2</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="backupButton">
|
||||
<property name="text">
|
||||
<string>Backup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="restoreButton">
|
||||
<property name="text">
|
||||
<string>Restore</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>131</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="okButton">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>okButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>controllerSetup</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>278</x>
|
||||
<y>253</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>96</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cancelButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>controllerSetup</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>369</x>
|
||||
<y>253</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>179</x>
|
||||
<y>282</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -0,0 +1,493 @@
|
|||
#include "cwsender.h"
|
||||
#include "ui_cwsender.h"
|
||||
|
||||
#include "logcategories.h"
|
||||
|
||||
cwSender::cwSender(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::cwSender)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->setWindowTitle("CW Sender");
|
||||
ui->textToSendEdit->setFocus();
|
||||
QFont f = QFont("Monospace");
|
||||
f.setStyleHint(QFont::TypeWriter);
|
||||
ui->textToSendEdit->setFont(f);
|
||||
ui->transcriptText->setFont(f);
|
||||
ui->textToSendEdit->setFocus();
|
||||
ui->statusbar->setToolTipDuration(3000);
|
||||
this->setToolTipDuration(3000);
|
||||
connect(ui->textToSendEdit->lineEdit(), &QLineEdit::textEdited, this, &cwSender::textChanged);
|
||||
}
|
||||
|
||||
cwSender::~cwSender()
|
||||
{
|
||||
qDebug(logCW()) << "Running CW Sender destructor.";
|
||||
|
||||
if (toneThread != Q_NULLPTR) {
|
||||
toneThread->quit();
|
||||
toneThread->wait();
|
||||
toneThread = Q_NULLPTR;
|
||||
tone = Q_NULLPTR;
|
||||
/* Finally disconnect all connections */
|
||||
for (auto conn: connections)
|
||||
{
|
||||
disconnect(conn);
|
||||
}
|
||||
connections.clear();
|
||||
}
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void cwSender::showEvent(QShowEvent *event)
|
||||
{
|
||||
(void)event;
|
||||
emit getCWSettings();
|
||||
QMainWindow::showEvent(event);
|
||||
}
|
||||
|
||||
void cwSender::handleKeySpeed(unsigned char wpm)
|
||||
{
|
||||
if (wpm != ui->wpmSpin->value() && (wpm >= ui->wpmSpin->minimum()) && (wpm <= ui->wpmSpin->maximum()))
|
||||
{
|
||||
ui->wpmSpin->blockSignals(true);
|
||||
QMetaObject::invokeMethod(ui->wpmSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, wpm));
|
||||
ui->wpmSpin->blockSignals(false);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(tone, [=]() {
|
||||
tone->setSpeed(wpm);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
emit setKeySpeed(ratio);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::handleDashRatio(unsigned char ratio)
|
||||
{
|
||||
double calc = double(ratio/10);
|
||||
if (calc != ui->dashSpin->value() && (calc >= ui->dashSpin->minimum()) && (ratio <= ui->dashSpin->maximum()))
|
||||
{
|
||||
ui->dashSpin->blockSignals(true);
|
||||
QMetaObject::invokeMethod(ui->dashSpin, "setValue", Qt::QueuedConnection, Q_ARG(double, calc));
|
||||
ui->dashSpin->blockSignals(false);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(tone, [=]() {
|
||||
tone->setRatio(ratio);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
emit setDashRatio(ratio);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::handlePitch(unsigned char pitch) {
|
||||
int cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0;
|
||||
if (cwPitch != ui->pitchSpin->value() && cwPitch >= ui->pitchSpin->minimum() && cwPitch <= ui->pitchSpin->maximum())
|
||||
{
|
||||
ui->pitchSpin->blockSignals(true);
|
||||
QMetaObject::invokeMethod(ui->pitchSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, cwPitch));
|
||||
ui->pitchSpin->blockSignals(false);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(tone, [=]() {
|
||||
tone->setFrequency(pitch);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
emit setPitch(tone);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::handleBreakInMode(unsigned char b)
|
||||
{
|
||||
if(b < 3)
|
||||
{
|
||||
ui->breakinCombo->blockSignals(true);
|
||||
ui->breakinCombo->setCurrentIndex(b);
|
||||
ui->breakinCombo->blockSignals(false);
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::handleCurrentModeUpdate(mode_kind mode)
|
||||
{
|
||||
this->currentMode = mode;
|
||||
if( (currentMode==modeCW) || (currentMode==modeCW_R) )
|
||||
{
|
||||
} else {
|
||||
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::textChanged(QString text)
|
||||
{
|
||||
if (ui->sendImmediateChk->isChecked() && text.size() && text.back() == ' ')
|
||||
{
|
||||
int toSend = text.mid(0, 30).size();
|
||||
if (toSend > 0) {
|
||||
ui->textToSendEdit->clearEditText();
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
ui->transcriptText->insertPlainText(text.mid(0, 30).toUpper());
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
|
||||
emit sendCW(text.mid(0, 30));
|
||||
}
|
||||
if( (currentMode != modeCW) && (currentMode != modeCW_R) )
|
||||
{
|
||||
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::on_sendBtn_clicked()
|
||||
{
|
||||
if( (ui->textToSendEdit->currentText().length() > 0) &&
|
||||
(ui->textToSendEdit->currentText().length() <= 30) )
|
||||
{
|
||||
QString text = ui->textToSendEdit->currentText();
|
||||
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
ui->transcriptText->insertPlainText(ui->textToSendEdit->currentText().toUpper()+"\n");
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
if (!ui->sendImmediateChk->isChecked())
|
||||
{
|
||||
ui->textToSendEdit->addItem(ui->textToSendEdit->currentText());
|
||||
if (ui->textToSendEdit->count() > 5) {
|
||||
ui->textToSendEdit->removeItem(0);
|
||||
}
|
||||
ui->textToSendEdit->setCurrentIndex(-1);
|
||||
} else {
|
||||
ui->textToSendEdit->clearEditText();
|
||||
ui->textToSendEdit->clear();
|
||||
}
|
||||
|
||||
ui->textToSendEdit->setFocus();
|
||||
ui->statusbar->showMessage("Sending CW", 3000);
|
||||
|
||||
emit sendCW(text);
|
||||
}
|
||||
|
||||
if( (currentMode != modeCW) && (currentMode != modeCW_R) )
|
||||
{
|
||||
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000);
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::on_stopBtn_clicked()
|
||||
{
|
||||
emit stopCW();
|
||||
ui->textToSendEdit->setFocus();
|
||||
ui->statusbar->showMessage("Stopping CW transmission.", 3000);
|
||||
}
|
||||
|
||||
//void cwSender::on_textToSendEdit_returnPressed()
|
||||
//{
|
||||
// on_sendBtn_clicked();
|
||||
//}
|
||||
|
||||
void cwSender::on_breakinCombo_activated(int brkmode)
|
||||
{
|
||||
// 0 = off, 1 = semi, 2 = full
|
||||
emit setBreakInMode((unsigned char)brkmode);
|
||||
ui->textToSendEdit->setFocus();
|
||||
}
|
||||
|
||||
void cwSender::on_wpmSpin_valueChanged(int wpm)
|
||||
{
|
||||
emit setKeySpeed((unsigned char)wpm);
|
||||
}
|
||||
|
||||
void cwSender::on_dashSpin_valueChanged(double ratio)
|
||||
{
|
||||
emit setDashRatio((unsigned char)double(ratio * 10));
|
||||
}
|
||||
|
||||
void cwSender::on_pitchSpin_valueChanged(int arg1)
|
||||
{
|
||||
// quint16 cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0;
|
||||
unsigned char pitch = 0;
|
||||
pitch = ceil((arg1 - 300) * (255.0 / 600.0));
|
||||
emit setPitch(pitch);
|
||||
}
|
||||
|
||||
void cwSender::on_macro1btn_clicked()
|
||||
{
|
||||
processMacroButton(1, ui->macro1btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro2btn_clicked()
|
||||
{
|
||||
processMacroButton(2, ui->macro2btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro3btn_clicked()
|
||||
{
|
||||
processMacroButton(3, ui->macro3btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro4btn_clicked()
|
||||
{
|
||||
processMacroButton(4, ui->macro4btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro5btn_clicked()
|
||||
{
|
||||
processMacroButton(5, ui->macro5btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro6btn_clicked()
|
||||
{
|
||||
processMacroButton(6, ui->macro6btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro7btn_clicked()
|
||||
{
|
||||
processMacroButton(7, ui->macro7btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro8btn_clicked()
|
||||
{
|
||||
processMacroButton(8, ui->macro8btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro9btn_clicked()
|
||||
{
|
||||
processMacroButton(9, ui->macro9btn);
|
||||
}
|
||||
|
||||
void cwSender::on_macro10btn_clicked()
|
||||
{
|
||||
processMacroButton(10, ui->macro10btn);
|
||||
}
|
||||
|
||||
void cwSender::on_sidetoneEnableChk_clicked(bool clicked)
|
||||
{
|
||||
ui->sidetoneLevelSlider->setEnabled(clicked);
|
||||
if (clicked && toneThread == Q_NULLPTR)
|
||||
{
|
||||
toneThread = new QThread(this);
|
||||
toneThread->setObjectName("sidetone()");
|
||||
|
||||
tone = new cwSidetone(sidetoneLevel, ui->wpmSpin->value(),ui->pitchSpin->value(),ui->dashSpin->value(),this);
|
||||
tone->moveToThread(toneThread);
|
||||
toneThread->start();
|
||||
|
||||
connections.append(connect(toneThread, &QThread::finished,
|
||||
[=]() { tone->deleteLater(); }));
|
||||
connections.append(connect(this, &cwSender::sendCW,
|
||||
[=](const QString& text) { tone->send(text); ui->sidetoneEnableChk->setEnabled(false); }));
|
||||
connections.append(connect(this, &cwSender::setKeySpeed,
|
||||
[=](const unsigned char& wpm) { tone->setSpeed(wpm); }));
|
||||
connections.append(connect(this, &cwSender::setDashRatio,
|
||||
[=](const unsigned char& ratio) { tone->setRatio(ratio); }));
|
||||
connections.append(connect(this, &cwSender::setPitch,
|
||||
[=](const unsigned char& pitch) { tone->setFrequency(pitch); }));
|
||||
connections.append(connect(this, &cwSender::setLevel,
|
||||
[=](const unsigned char& level) { tone->setLevel(level); }));
|
||||
connections.append(connect(this, &cwSender::stopCW,
|
||||
[=]() { tone->stopSending(); }));
|
||||
connections.append(connect(tone, &cwSidetone::finished,
|
||||
[=]() { ui->sidetoneEnableChk->setEnabled(true); }));
|
||||
|
||||
} else if (!clicked && toneThread != Q_NULLPTR) {
|
||||
/* disconnect all connections */
|
||||
toneThread->quit();
|
||||
toneThread->wait();
|
||||
toneThread = Q_NULLPTR;
|
||||
tone = Q_NULLPTR;
|
||||
for (auto conn: connections)
|
||||
{
|
||||
disconnect(conn);
|
||||
}
|
||||
connections.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::on_sidetoneLevelSlider_valueChanged(int val)
|
||||
{
|
||||
sidetoneLevel = val;
|
||||
emit setLevel(val);
|
||||
}
|
||||
|
||||
|
||||
void cwSender::processMacroButton(int buttonNumber, QPushButton *btn)
|
||||
{
|
||||
if(ui->macroEditChk->isChecked())
|
||||
{
|
||||
editMacroButton(buttonNumber, btn);
|
||||
} else {
|
||||
runMacroButton(buttonNumber);
|
||||
}
|
||||
ui->textToSendEdit->setFocus();
|
||||
}
|
||||
|
||||
void cwSender::runMacroButton(int buttonNumber)
|
||||
{
|
||||
if(macroText[buttonNumber].isEmpty())
|
||||
return;
|
||||
QString outText;
|
||||
if(macroText[buttonNumber].contains("%1"))
|
||||
{
|
||||
outText = macroText[buttonNumber].arg(sequenceNumber, 3, 10, QChar('0'));
|
||||
sequenceNumber++;
|
||||
ui->sequenceSpin->blockSignals(true);
|
||||
QMetaObject::invokeMethod(ui->sequenceSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, sequenceNumber));
|
||||
ui->sequenceSpin->blockSignals(false);
|
||||
} else {
|
||||
outText = macroText[buttonNumber];
|
||||
}
|
||||
|
||||
if (ui->cutNumbersChk->isChecked())
|
||||
{
|
||||
outText.replace("0", "T");
|
||||
outText.replace("9", "N");
|
||||
}
|
||||
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
ui->transcriptText->insertPlainText(outText.toUpper()+"\n");
|
||||
ui->transcriptText->moveCursor(QTextCursor::End);
|
||||
|
||||
for (int i = 0; i < outText.size(); i = i + 30) {
|
||||
emit sendCW(outText.mid(i,30));
|
||||
}
|
||||
|
||||
ui->textToSendEdit->setFocus();
|
||||
|
||||
|
||||
if( (currentMode==modeCW) || (currentMode==modeCW_R) )
|
||||
{
|
||||
ui->statusbar->showMessage(QString("Sending CW macro %1").arg(buttonNumber));
|
||||
} else {
|
||||
ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.");
|
||||
}
|
||||
}
|
||||
|
||||
void cwSender::editMacroButton(int buttonNumber, QPushButton* btn)
|
||||
{
|
||||
bool ok;
|
||||
QString promptFirst = QString("Please enter the text for macro %1,\n"
|
||||
"up to 60 characters.\n").arg(buttonNumber);
|
||||
QString promptSecond = QString("You may use \"%1\" to insert a sequence number.");
|
||||
QString prompt = promptFirst+promptSecond;
|
||||
|
||||
QString newMacroText = QInputDialog::getText(this, "Macro Edit",
|
||||
prompt,
|
||||
QLineEdit::Normal, macroText[buttonNumber], &ok).toUpper();
|
||||
if(!ok)
|
||||
return;
|
||||
|
||||
if (newMacroText.length() > 60)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QString("The text entered was too long \n"
|
||||
"(max length is 60 characters).\n"
|
||||
"Your input was %1 characters.").arg(newMacroText.length()));
|
||||
msgBox.exec();
|
||||
this->raise();
|
||||
return;
|
||||
}
|
||||
|
||||
macroText[buttonNumber] = newMacroText;
|
||||
setMacroButtonText(newMacroText, btn);
|
||||
}
|
||||
|
||||
void cwSender::setMacroButtonText(QString btnText, QPushButton *btn)
|
||||
{
|
||||
if(btn==Q_NULLPTR)
|
||||
return;
|
||||
if(btnText.isEmpty())
|
||||
return;
|
||||
|
||||
QString shortBtnName;
|
||||
if(btnText.length() <= 8)
|
||||
{
|
||||
shortBtnName = btnText;
|
||||
} else {
|
||||
shortBtnName = btnText.left(7);
|
||||
shortBtnName.append("…");
|
||||
}
|
||||
btn->setText(shortBtnName);
|
||||
}
|
||||
|
||||
void cwSender::on_sequenceSpin_valueChanged(int newSeq)
|
||||
{
|
||||
sequenceNumber = newSeq;
|
||||
ui->textToSendEdit->setFocus();
|
||||
}
|
||||
|
||||
bool cwSender::getCutNumbers()
|
||||
{
|
||||
return ui->cutNumbersChk->isChecked();
|
||||
}
|
||||
|
||||
bool cwSender::getSendImmediate()
|
||||
{
|
||||
return ui->sendImmediateChk->isChecked();
|
||||
}
|
||||
|
||||
bool cwSender::getSidetoneEnable()
|
||||
{
|
||||
return ui->sidetoneEnableChk->isChecked();
|
||||
}
|
||||
|
||||
int cwSender::getSidetoneLevel()
|
||||
{
|
||||
return ui->sidetoneLevelSlider->value();
|
||||
}
|
||||
|
||||
void cwSender::setCutNumbers(bool val)
|
||||
{
|
||||
ui->cutNumbersChk->setChecked(val);
|
||||
}
|
||||
|
||||
void cwSender::setSendImmediate(bool val)
|
||||
{
|
||||
ui->sendImmediateChk->setChecked(val);
|
||||
}
|
||||
|
||||
void cwSender::setSidetoneEnable(bool val)
|
||||
{
|
||||
ui->sidetoneEnableChk->setChecked(val);
|
||||
on_sidetoneEnableChk_clicked(val);
|
||||
}
|
||||
|
||||
void cwSender::setSidetoneLevel(int val)
|
||||
{
|
||||
QMetaObject::invokeMethod(ui->sidetoneLevelSlider, "setValue", Qt::QueuedConnection, Q_ARG(int, val));
|
||||
}
|
||||
|
||||
QStringList cwSender::getMacroText()
|
||||
{
|
||||
// This is for preference saving:
|
||||
QStringList mlist;
|
||||
for(int i=1; i < 11; i++)
|
||||
{
|
||||
mlist << macroText[i];
|
||||
}
|
||||
return mlist;
|
||||
}
|
||||
|
||||
void cwSender::setMacroText(QStringList macros)
|
||||
{
|
||||
if(macros.length() != 10)
|
||||
{
|
||||
qCritical(logCW()) << "Macro list must be exactly 10. Rejecting macro text load.";
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i=0; i < 10; i++)
|
||||
{
|
||||
macroText[i+1] = macros.at(i);
|
||||
}
|
||||
|
||||
setMacroButtonText(macroText[1], ui->macro1btn);
|
||||
setMacroButtonText(macroText[2], ui->macro2btn);
|
||||
setMacroButtonText(macroText[3], ui->macro3btn);
|
||||
setMacroButtonText(macroText[4], ui->macro4btn);
|
||||
setMacroButtonText(macroText[5], ui->macro5btn);
|
||||
setMacroButtonText(macroText[6], ui->macro6btn);
|
||||
setMacroButtonText(macroText[7], ui->macro7btn);
|
||||
setMacroButtonText(macroText[8], ui->macro8btn);
|
||||
setMacroButtonText(macroText[9], ui->macro9btn);
|
||||
setMacroButtonText(macroText[10], ui->macro10btn);
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
#ifndef CWSENDER_H
|
||||
#define CWSENDER_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QString>
|
||||
#include <QFont>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QThread>
|
||||
#include <QList>
|
||||
#include <math.h>
|
||||
#include "cwsidetone.h"
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
namespace Ui {
|
||||
class cwSender;
|
||||
}
|
||||
|
||||
class cwSender : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit cwSender(QWidget *parent = 0);
|
||||
~cwSender();
|
||||
QStringList getMacroText();
|
||||
void setMacroText(QStringList macros);
|
||||
void setCutNumbers(bool val);
|
||||
void setSendImmediate(bool val);
|
||||
void setSidetoneEnable(bool val);
|
||||
void setSidetoneLevel(int val);
|
||||
bool getCutNumbers();
|
||||
bool getSendImmediate();
|
||||
bool getSidetoneEnable();
|
||||
int getSidetoneLevel();
|
||||
|
||||
signals:
|
||||
void sendCW(QString cwMessage);
|
||||
void stopCW();
|
||||
void setKeySpeed(unsigned char wpm);
|
||||
void setDashRatio(unsigned char ratio);
|
||||
void setPitch(unsigned char pitch);
|
||||
void setLevel(int level);
|
||||
void setBreakInMode(unsigned char b);
|
||||
void getCWSettings();
|
||||
void sidetone(QString text);
|
||||
void pitchChanged(int val);
|
||||
void dashChanged(int val);
|
||||
void wpmChanged(int val);
|
||||
|
||||
public slots:
|
||||
void handleKeySpeed(unsigned char wpm);
|
||||
void handleDashRatio(unsigned char ratio);
|
||||
void handlePitch(unsigned char pitch);
|
||||
void handleBreakInMode(unsigned char b);
|
||||
void handleCurrentModeUpdate(mode_kind mode);
|
||||
|
||||
private slots:
|
||||
void on_sendBtn_clicked();
|
||||
void showEvent(QShowEvent* event);
|
||||
|
||||
void on_stopBtn_clicked();
|
||||
|
||||
//void on_textToSendEdit_returnPressed();
|
||||
|
||||
void textChanged(QString text);
|
||||
|
||||
void on_breakinCombo_activated(int index);
|
||||
|
||||
void on_wpmSpin_valueChanged(int arg1);
|
||||
|
||||
void on_dashSpin_valueChanged(double arg1);
|
||||
|
||||
void on_pitchSpin_valueChanged(int arg1);
|
||||
|
||||
void on_macro1btn_clicked();
|
||||
|
||||
void on_macro2btn_clicked();
|
||||
|
||||
void on_macro3btn_clicked();
|
||||
|
||||
void on_macro4btn_clicked();
|
||||
|
||||
void on_macro5btn_clicked();
|
||||
|
||||
void on_macro6btn_clicked();
|
||||
|
||||
void on_macro7btn_clicked();
|
||||
|
||||
void on_macro8btn_clicked();
|
||||
|
||||
void on_macro9btn_clicked();
|
||||
|
||||
void on_macro10btn_clicked();
|
||||
|
||||
void on_sequenceSpin_valueChanged(int arg1);
|
||||
|
||||
void on_sidetoneEnableChk_clicked(bool clicked);
|
||||
|
||||
void on_sidetoneLevelSlider_valueChanged(int val);
|
||||
|
||||
private:
|
||||
Ui::cwSender *ui;
|
||||
QString macroText[11];
|
||||
int sequenceNumber = 1;
|
||||
int lastSentPos = 0;
|
||||
mode_kind currentMode;
|
||||
int sidetoneLevel=0;
|
||||
void processMacroButton(int buttonNumber, QPushButton *btn);
|
||||
void runMacroButton(int buttonNumber);
|
||||
void editMacroButton(int buttonNumber, QPushButton *btn);
|
||||
void setMacroButtonText(QString btnText, QPushButton *btn);
|
||||
cwSidetone* tone=Q_NULLPTR;
|
||||
QThread* toneThread = Q_NULLPTR;
|
||||
bool sidetoneWasEnabled=false;
|
||||
QList<QMetaObject::Connection> connections;
|
||||
};
|
||||
|
||||
#endif // CWSENDER_H
|
|
@ -0,0 +1,468 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>cwSender</class>
|
||||
<widget class="QMainWindow" name="cwSender">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>835</width>
|
||||
<height>451</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Send the text in the edit box</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="0" colspan="12">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Macros</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="macro5btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="macro2btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="macro4btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QCheckBox" name="macroEditChk">
|
||||
<property name="toolTip">
|
||||
<string>Check this box to enter edit mode, where you can then press the macro buttons to edit the macros.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="macro7btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 7</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="macro3btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="macro6btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 6</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QPushButton" name="macro10btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="macro9btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 9</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="macro8btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 8</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="macro1btn">
|
||||
<property name="toolTip">
|
||||
<string>Macro Access Button</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Macro 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Seq</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="sequenceSpin">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Sequence number, for contests. </p><p>Substitute &quot;%1&quot; in your macro text to use it. </p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="12">
|
||||
<widget class="QPlainTextEdit" name="transcriptText">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>CW Transmission Transcript</string>
|
||||
</property>
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="stopBtn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Stop sending CW</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Local Sidetone Level</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="sidetoneLevelSlider">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="sidetoneEnableChk">
|
||||
<property name="text">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sendBtn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Return</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="textToSendEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Type here to send text as CW</string>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhUppercaseOnly</set>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertAtTop</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="3" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item row="3" column="0">
|
||||
<widget class="QComboBox" name="breakinCombo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Set the desired break-in mode:</p><p>1. None: You must manually key and unkey the radio.</p><p>2. Semi: Transmit is automatic and switches to receive at the end of the text.</p><p>3. Full: Same as semi, but with breaks between characters when possible.</p></body></html></string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Off</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Semi</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Full</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>PITCH (Hz):</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>WPM:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="pitchSpin">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>300</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>900</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>600</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Break In</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QDoubleSpinBox" name="dashSpin">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>2.800000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>4.500000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>3.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Dash Ratio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="wpmSpin">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set the Words Per Minute</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>48</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QCheckBox" name="cutNumbersChk">
|
||||
<property name="text">
|
||||
<string>Cut Num</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QCheckBox" name="sendImmediateChk">
|
||||
<property name="text">
|
||||
<string>Send Immed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,308 @@
|
|||
#include "cwsidetone.h"
|
||||
|
||||
#include "logcategories.h"
|
||||
|
||||
cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* parent) :
|
||||
parent(parent),
|
||||
volume(level),
|
||||
speed(speed),
|
||||
frequency(freq),
|
||||
ratio(ratio)
|
||||
{
|
||||
|
||||
/*
|
||||
* Characters to match Icom table
|
||||
* Unknown characters will return '?'
|
||||
*/
|
||||
cwTable.clear();
|
||||
cwTable['0'] = "-----";
|
||||
cwTable['1'] = ".----";
|
||||
cwTable['2'] = "..---";
|
||||
cwTable['3'] = "...--";
|
||||
cwTable['4'] = "....-";
|
||||
cwTable['5'] = ".....";
|
||||
cwTable['6'] = "-....";
|
||||
cwTable['7'] = "--...";
|
||||
cwTable['8'] = "---..";
|
||||
cwTable['9'] = "----.";
|
||||
|
||||
cwTable['A'] = ".-";
|
||||
cwTable['B'] = "-...";
|
||||
cwTable['C'] = "-.-.";
|
||||
cwTable['D'] = "-..";
|
||||
cwTable['E'] = ".";
|
||||
cwTable['F'] = "..-.";
|
||||
cwTable['G'] = "--.";
|
||||
cwTable['H'] = "....";
|
||||
cwTable['I'] = "..";
|
||||
cwTable['J'] = ".---";
|
||||
cwTable['K'] = "-.-";
|
||||
cwTable['L'] = ".-..";
|
||||
cwTable['M'] = "--";
|
||||
cwTable['N'] = "-.";
|
||||
cwTable['O'] = "---";
|
||||
cwTable['P'] = ".--.";
|
||||
cwTable['Q'] = "--.-";
|
||||
cwTable['R'] = ".-.";
|
||||
cwTable['S'] = "...";
|
||||
cwTable['T'] = "-";
|
||||
cwTable['U'] = "..-";
|
||||
cwTable['V'] = "...-";
|
||||
cwTable['W'] = ".--";
|
||||
cwTable['X'] = "-..-";
|
||||
cwTable['Y'] = "-.--";
|
||||
cwTable['Z'] = "--..";
|
||||
|
||||
cwTable['/'] = "-..-.";
|
||||
cwTable['?'] = "..--..";
|
||||
cwTable['.'] = ".-.-.-";
|
||||
cwTable['-'] = "-....-";
|
||||
cwTable[','] = "--..--";
|
||||
cwTable[':'] = "---...";
|
||||
cwTable['\''] = ".----.";
|
||||
cwTable['('] = "-.--.-";
|
||||
cwTable[')'] = "-.--.-";
|
||||
cwTable['='] = "-...-";
|
||||
cwTable['+'] = ".-.-.";
|
||||
cwTable['"'] = ".-..-.";
|
||||
|
||||
cwTable[' '] = " ";
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
cwSidetone::~cwSidetone()
|
||||
{
|
||||
qInfo(logCW()) << "cwSidetone() finished";
|
||||
this->stop();
|
||||
output->stop();
|
||||
}
|
||||
|
||||
void cwSidetone::init()
|
||||
{
|
||||
format.setSampleRate(44100);
|
||||
format.setChannelCount(1);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
format.setCodec("audio/pcm");
|
||||
format.setSampleSize(16);
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
QAudioDeviceInfo device(QAudioDeviceInfo::defaultOutputDevice());
|
||||
#else
|
||||
format.setSampleFormat(QAudioFormat::Int16);
|
||||
QAudioDevice device = QMediaDevices::defaultAudioOutput();
|
||||
#endif
|
||||
if (!device.isNull()) {
|
||||
if (!device.isFormatSupported(format)) {
|
||||
qWarning(logCW()) << "Default format not supported, using preferred";
|
||||
format = device.preferredFormat();
|
||||
}
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
output.reset(new QAudioOutput(device,format));
|
||||
#else
|
||||
output.reset(new QAudioSink(device,format));
|
||||
#endif
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 size: %3 type: %4)")
|
||||
.arg(device.deviceName()).arg(volume).arg(format.sampleRate()).arg(format.sampleSize()).arg(format.sampleType());
|
||||
#else
|
||||
qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 type: %3")
|
||||
.arg(device.description()).arg(volume).arg(format.sampleRate()).arg(format.sampleFormat());
|
||||
#endif
|
||||
}
|
||||
this->start(); // Start QIODevice
|
||||
}
|
||||
|
||||
void cwSidetone::send(QString text)
|
||||
{
|
||||
text=text.simplified();
|
||||
|
||||
for (int pos=0; pos < text.size(); pos++)
|
||||
{
|
||||
QChar ch = text.at(pos).toUpper();
|
||||
QString currentChar;
|
||||
if (ch == NULL)
|
||||
{
|
||||
currentChar = cwTable[' '];
|
||||
}
|
||||
else if (this->cwTable.contains(ch))
|
||||
{
|
||||
currentChar = cwTable[ch];
|
||||
}
|
||||
else
|
||||
{
|
||||
currentChar=cwTable['?'];
|
||||
}
|
||||
generateMorse(currentChar);
|
||||
}
|
||||
|
||||
if (output->state() == QAudio::StoppedState)
|
||||
{
|
||||
output->start(this);
|
||||
}
|
||||
else if (output->state() == QAudio::IdleState) {
|
||||
output->suspend();
|
||||
output->resume();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void cwSidetone::start()
|
||||
{
|
||||
open(QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
void cwSidetone::stop()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
qint64 cwSidetone::readData(char *data, qint64 len)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
const qint64 total = qMin(((qint64)buffer.size()), len);
|
||||
memcpy(data, buffer.constData(), total);
|
||||
buffer.remove(0,total);
|
||||
if (buffer.size() == 0) {
|
||||
emit finished();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
qint64 cwSidetone::writeData(const char *data, qint64 len)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 cwSidetone::bytesAvailable() const
|
||||
{
|
||||
return buffer.size() + QIODevice::bytesAvailable();
|
||||
}
|
||||
|
||||
void cwSidetone::generateMorse(QString morse)
|
||||
{
|
||||
|
||||
int dit = int(double(SIDETONE_MULTIPLIER / this->speed * SIDETONE_MULTIPLIER));
|
||||
int dah = int(double(dit * this->ratio));
|
||||
|
||||
|
||||
QMutexLocker locker(&mutex);
|
||||
for (int i=0;i<morse.size();i++)
|
||||
{
|
||||
QChar c = morse.at(i);
|
||||
if (c == '-')
|
||||
{
|
||||
buffer.append(generateData(dah,this->frequency));
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
buffer.append(generateData(dit,this->frequency));
|
||||
}
|
||||
else // Space char
|
||||
{
|
||||
buffer.append(generateData(dit,0));
|
||||
}
|
||||
|
||||
if (i<morse.size()-1)
|
||||
{
|
||||
buffer.append(generateData(dit,0));
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append(generateData(dit*3,0)); // inter-character space
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray cwSidetone::generateData(qint64 len, qint64 freq)
|
||||
{
|
||||
QByteArray data;
|
||||
|
||||
const int channels = format.channelCount();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
const int channelBytes = format.sampleSize() / 8;
|
||||
#else
|
||||
const int channelBytes = format.bytesPerSample();
|
||||
#endif
|
||||
|
||||
const int sampleRate = format.sampleRate();
|
||||
//qint64 length = (sampleRate * channels * channelBytes) * len / 100000;
|
||||
qint64 length = format.bytesForDuration(len);
|
||||
const int sampleBytes = channels * channelBytes;
|
||||
|
||||
length -= length % sampleBytes;
|
||||
Q_UNUSED(sampleBytes) // suppress warning in release builds
|
||||
|
||||
data.resize(length);
|
||||
unsigned char *ptr = reinterpret_cast<unsigned char *>(data.data());
|
||||
int sampleIndex = 0;
|
||||
|
||||
while (length) {
|
||||
const qreal x = (qSin(2 * M_PI * freq * qreal(sampleIndex % sampleRate) / sampleRate)) * qreal(volume/100.0);
|
||||
for (int i=0; i<channels; ++i) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt)
|
||||
*reinterpret_cast<quint8 *>(ptr) = static_cast<quint8>((1.0 + x) / 2 * 255);
|
||||
else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt)
|
||||
*reinterpret_cast<qint16 *>(ptr) = static_cast<qint16>(x * std::numeric_limits<qint16>::max());
|
||||
else if (format.sampleSize() == 32 && format.sampleType() == QAudioFormat::SignedInt)
|
||||
*reinterpret_cast<qint32 *>(ptr) = static_cast<qint32>(x * std::numeric_limits<qint32>::max());
|
||||
else if (format.sampleType() == QAudioFormat::Float)
|
||||
*reinterpret_cast<float *>(ptr) = x;
|
||||
else
|
||||
qWarning(logCW()) << QString("Unsupported sample size: %0 type: %1").arg(format.sampleSize()).arg(format.sampleType());
|
||||
#else
|
||||
if (format.sampleFormat() == QAudioFormat::UInt8)
|
||||
*reinterpret_cast<quint8 *>(ptr) = static_cast<quint8>((1.0 + x) / 2 * 255);
|
||||
else if (format.sampleFormat() == QAudioFormat::Int16)
|
||||
*reinterpret_cast<qint16 *>(ptr) = static_cast<qint16>(x * std::numeric_limits<qint16>::max());
|
||||
else if (format.sampleFormat() == QAudioFormat::Int32)
|
||||
*reinterpret_cast<qint32 *>(ptr) = static_cast<qint32>(x * std::numeric_limits<qint32>::max());
|
||||
else if (format.sampleFormat() == QAudioFormat::Float)
|
||||
*reinterpret_cast<float *>(ptr) = x;
|
||||
else
|
||||
qWarning(logCW()) << QString("Unsupported sample format: %0").arg(format.sampleFormat());
|
||||
#endif
|
||||
|
||||
ptr += channelBytes;
|
||||
length -= channelBytes;
|
||||
}
|
||||
++sampleIndex;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void cwSidetone::setSpeed(unsigned char speed)
|
||||
{
|
||||
this->speed = (int)speed;
|
||||
}
|
||||
|
||||
void cwSidetone::setFrequency(unsigned char frequency)
|
||||
{
|
||||
this->frequency = round((((600.0 / 255.0) * frequency) + 300) / 5.0) * 5.0;
|
||||
}
|
||||
|
||||
void cwSidetone::setRatio(unsigned char ratio)
|
||||
{
|
||||
this->ratio = (double)ratio/10.0;
|
||||
}
|
||||
|
||||
void cwSidetone::setLevel(int level) {
|
||||
volume = level;
|
||||
}
|
||||
|
||||
void cwSidetone::stopSending() {
|
||||
QMutexLocker locker(&mutex);
|
||||
buffer.clear();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef CWSIDETONE_H
|
||||
#define CWSIDETONE_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QAudioOutput>
|
||||
#include <QMap>
|
||||
#include <QScopedPointer>
|
||||
#include <QtMath>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioOutput>
|
||||
#else
|
||||
#include <QAudioDevice>
|
||||
#include <QAudioSink>
|
||||
#include <QMediaDevices>
|
||||
#endif
|
||||
|
||||
//#define SIDETONE_MULTIPLIER 386.0
|
||||
#define SIDETONE_MULTIPLIER 1095.46
|
||||
|
||||
class cwSidetone : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit cwSidetone(int level, int speed, int freq, double ratio, QWidget *parent = 0);
|
||||
~cwSidetone();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
qint64 readData(char *data, qint64 maxlen) override;
|
||||
qint64 writeData(const char *data, qint64 len) override;
|
||||
qint64 bytesAvailable() const override;
|
||||
qint64 size() const override { return buffer.size(); }
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
public slots:
|
||||
void send(QString text);
|
||||
void setSpeed(unsigned char speed);
|
||||
void setFrequency(unsigned char frequency);
|
||||
void setRatio(unsigned char ratio);
|
||||
void setLevel(int level);
|
||||
void stopSending();
|
||||
private:
|
||||
void init();
|
||||
|
||||
void generateMorse(QString morse);
|
||||
QByteArray generateData(qint64 len, qint64 freq);
|
||||
QByteArray buffer;
|
||||
QMap< QChar, QString> cwTable;
|
||||
QWidget* parent;
|
||||
int volume;
|
||||
int speed;
|
||||
int frequency;
|
||||
double ratio;
|
||||
QAudioFormat format;
|
||||
QMutex mutex;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
QScopedPointer<QAudioOutput> output;
|
||||
#else
|
||||
QScopedPointer<QAudioSink> output;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CWSIDETONE_H
|
|
@ -0,0 +1,107 @@
|
|||
#ifdef USESQL
|
||||
|
||||
#include "database.h"
|
||||
#include "logcategories.h"
|
||||
|
||||
database::database()
|
||||
{
|
||||
open();
|
||||
}
|
||||
|
||||
database::~database()
|
||||
{
|
||||
}
|
||||
|
||||
bool database::open()
|
||||
{
|
||||
auto name = "my_db_" + QString::number((quint64)QThread::currentThread(), 16);
|
||||
if (QSqlDatabase::contains(name))
|
||||
{
|
||||
db = QSqlDatabase::database(name);
|
||||
qu = QSqlQuery(db);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
qInfo(logCluster()) << "Creating new connection" << name;
|
||||
db = QSqlDatabase::addDatabase("QSQLITE", name);
|
||||
qu = QSqlQuery(db);
|
||||
}
|
||||
|
||||
//QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/" + "wfview.db";
|
||||
QString path = ":memory:";
|
||||
qInfo(logCluster()) << "DB Filename" << path;
|
||||
db.setDatabaseName(path);
|
||||
if (db.isValid())
|
||||
{
|
||||
db.open();
|
||||
if (check()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
qWarning(logCluster()) << "Database is not valid!";
|
||||
return false;
|
||||
}
|
||||
|
||||
void database::close()
|
||||
{
|
||||
auto name = "my_db_" + QString::number((quint64)QThread::currentThread(), 16);
|
||||
qInfo(logCluster()) << "Closing database connection:" << name;
|
||||
db.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
QSqlQuery database::query(QString query)
|
||||
{
|
||||
if (!db.isOpen())
|
||||
{
|
||||
qWarning(logCluster()) << "Query Database is not open!";
|
||||
db.open();
|
||||
}
|
||||
qu.exec(query);
|
||||
return qu;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool database::check()
|
||||
{
|
||||
if (db.isOpen()) {
|
||||
for (const auto& table : db.tables())
|
||||
{
|
||||
if (table == "spots")
|
||||
{
|
||||
qInfo(logCluster()) << "DB Contains spots table";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
qInfo(logCluster()) << "Creating spots table";
|
||||
// Spots table does not exist, need to create it.
|
||||
/*
|
||||
QString dxcall;
|
||||
double frequency;
|
||||
QString spottercall;
|
||||
QDateTime timestamp;
|
||||
QString mode;
|
||||
QString comment;
|
||||
QCPItemText* text = Q_NULLPTR;*/
|
||||
qu.exec("CREATE TABLE spots "
|
||||
"(id INTEGER PRIMARY KEY, "
|
||||
"type VARCHAR(3),"
|
||||
"dxcall VARCHAR(30),"
|
||||
"spottercall VARCHAR(30),"
|
||||
"frequency DOUBLE,"
|
||||
"timestamp DATETIME,"
|
||||
"mode VARCHAR(30),"
|
||||
"comment VARCHAR(255) )");
|
||||
qu.exec("CREATE INDEX spots_index ON spots(type,dxcall,frequency,timestamp)");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
qWarning(logCluster()) << "Database is not open";
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#ifdef USESQL
|
||||
|
||||
#ifndef DATABASE_H
|
||||
#define DATABASE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlRecord>
|
||||
#include <QThread>
|
||||
#include <QStandardPaths>
|
||||
|
||||
class database
|
||||
{
|
||||
public:
|
||||
explicit database();
|
||||
virtual ~database();
|
||||
bool open();
|
||||
void close();
|
||||
QSqlQuery query(QString query);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
private:
|
||||
bool check();
|
||||
QSqlDatabase db;
|
||||
QSqlQuery qu;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
39
freqmemory.h
|
@ -2,44 +2,7 @@
|
|||
#define FREQMEMORY_H
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
// 0 1 2 3 4
|
||||
//modes << "LSB" << "USB" << "AM" << "CW" << "RTTY";
|
||||
// 5 6 7 8 9
|
||||
// modes << "FM" << "CW-R" << "RTTY-R" << "LSB-D" << "USB-D";
|
||||
|
||||
enum mode_kind {
|
||||
modeLSB=0x00,
|
||||
modeUSB=0x01,
|
||||
modeAM=0x02,
|
||||
modeCW=0x03,
|
||||
modeRTTY=0x04,
|
||||
modeFM=0x05,
|
||||
modeCW_R=0x07,
|
||||
modeRTTY_R=0x08,
|
||||
modeLSB_D=0x80,
|
||||
modeUSB_D=0x81,
|
||||
modeDV=0x17,
|
||||
modeDD=0x27,
|
||||
modeWFM,
|
||||
modeS_AMD,
|
||||
modeS_AML,
|
||||
modeS_AMU,
|
||||
modeP25,
|
||||
modedPMR,
|
||||
modeNXDN_VN,
|
||||
modeNXDN_N,
|
||||
modeDCR,
|
||||
modePSK,
|
||||
modePSK_R
|
||||
};
|
||||
|
||||
struct mode_info {
|
||||
mode_kind mk;
|
||||
unsigned char reg;
|
||||
unsigned char filter;
|
||||
QString name;
|
||||
};
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
struct preset_kind {
|
||||
// QString name;
|
||||
|
|
|
@ -6,9 +6,13 @@ Q_LOGGING_CATEGORY(logGui, "gui")
|
|||
Q_LOGGING_CATEGORY(logLogger, "log")
|
||||
Q_LOGGING_CATEGORY(logUser, "user")
|
||||
Q_LOGGING_CATEGORY(logRig, "rig")
|
||||
Q_LOGGING_CATEGORY(logRigTraffic, "rigTraffic")
|
||||
Q_LOGGING_CATEGORY(logCW, "cw")
|
||||
Q_LOGGING_CATEGORY(logAudio, "audio")
|
||||
Q_LOGGING_CATEGORY(logUdp, "udp")
|
||||
Q_LOGGING_CATEGORY(logUdpServer, "udp.server")
|
||||
Q_LOGGING_CATEGORY(logRigCtlD, "rigctld")
|
||||
Q_LOGGING_CATEGORY(logTcpServer, "tcpserver")
|
||||
Q_LOGGING_CATEGORY(logUsbControl, "usbcontrol")
|
||||
Q_LOGGING_CATEGORY(logAudioConverter, "audioconverter")
|
||||
Q_LOGGING_CATEGORY(logCluster, "cluster")
|
||||
|
|
|
@ -9,16 +9,25 @@ Q_DECLARE_LOGGING_CATEGORY(logGui)
|
|||
Q_DECLARE_LOGGING_CATEGORY(logLogger)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logUser)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logRig)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logRigTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logCW)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logAudio)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logUdp)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logUdpServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logRigCtlD)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logTcpServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logUsbControl)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logAudioConverter)
|
||||
Q_DECLARE_LOGGING_CATEGORY(logCluster)
|
||||
|
||||
|
||||
#if defined(Q_OS_WIN) && !defined(__PRETTY_FUNCTION__)
|
||||
#define __PRETTY_FUNCTION__ __FUNCSIG__
|
||||
#endif
|
||||
|
||||
#if QT_VERSION > 0x060000
|
||||
//#define hex Qt::hex
|
||||
//#define bin Qt::bin
|
||||
#endif
|
||||
|
||||
#endif // LOGCATEGORIES_H
|
||||
|
|
|
@ -27,8 +27,11 @@ loggingWindow::loggingWindow(QString logFilename, QWidget *parent) :
|
|||
connect(socket, SIGNAL(connected()), this, SLOT(connectedToHost()));
|
||||
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnectedFromHost()));
|
||||
connect(socket, SIGNAL(readyRead()), this, SLOT(handleDataFromLoggingHost()));
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(handleLoggingHostError(QAbstractSocket::SocketError)));
|
||||
#else
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(handleLoggingHostError(QAbstractSocket::SocketError)));
|
||||
|
||||
#endif
|
||||
vertLogScroll = ui->logTextDisplay->verticalScrollBar();
|
||||
horizLogScroll = ui->logTextDisplay->horizontalScrollBar();
|
||||
|
||||
|
@ -84,10 +87,11 @@ void loggingWindow::handleDataFromLoggingHost()
|
|||
{
|
||||
clipboard->setText(URL);
|
||||
qInfo(logLogger()) << "Sent log to URL: " << URL;
|
||||
qInfo(logLogger()) << "This address already copied to the clipboard. Please paste this URL in to your support questions.";
|
||||
URLmsgBox.setText("Your log has been posted, and the URL has been copied to the clipboard.");
|
||||
URLmsgBox.setInformativeText("<b>" + URL + "</b>");
|
||||
URLmsgBox.exec();
|
||||
// For whatever reason, showing the message box hides this window.
|
||||
// For whatever reason, showing the message box hides https://termbin.com/ypxbthis window.
|
||||
this->show();
|
||||
this->raise();
|
||||
this->activateWindow();
|
||||
|
@ -124,6 +128,7 @@ void loggingWindow::handleLoggingHostError(QAbstractSocket::SocketError error)
|
|||
|
||||
default:
|
||||
qWarning(logLogger()) << "Error connecting to logging host. Check internet connection. Error code: " << error;
|
||||
ui->sendToPasteBtn->setDisabled(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
6
main.cpp
|
@ -155,7 +155,7 @@ int main(int argc, char *argv[])
|
|||
signal(SIGTERM, cleanup);
|
||||
signal(SIGKILL, cleanup);
|
||||
#endif
|
||||
w = new servermain(logFilename, settingsFile);
|
||||
w = new servermain(settingsFile);
|
||||
#else
|
||||
a.setWheelScrollLines(1); // one line per wheel click
|
||||
wfmain w(settingsFile, logFilename, debugMode);
|
||||
|
@ -203,11 +203,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
|
|||
}
|
||||
// Write to the output category of the message and the message itself
|
||||
out << context.category << ": " << msg << "\n";
|
||||
#ifdef BUILD_WFSERVER
|
||||
std::cout << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz ").toLocal8Bit().toStdString() << msg.toLocal8Bit().toStdString() << "\n";
|
||||
#endif
|
||||
text = out.readAll();
|
||||
out.flush(); // Clear the buffered data
|
||||
//mainwindow.handleLogText(test);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -493,7 +493,7 @@ void meter::drawScalePo(QPainter *qp)
|
|||
|
||||
// Here, P is now 60 watts:
|
||||
// Higher scale:
|
||||
i = i - (int)(10*dnPerWatt); // back one tick first. Otherwise i starts at 178.
|
||||
//i = i - (int)(10*dnPerWatt); // back one tick first. Otherwise i starts at 178. **Not used?**
|
||||
//qDebug() << "meter i: " << i;
|
||||
dnPerWatt = (213-143.0f) / 50.0f; // 1.4 dn per watt
|
||||
// P=5 here.
|
||||
|
|
|
@ -177,10 +177,12 @@ typedef union token_packet {
|
|||
union {
|
||||
struct {
|
||||
quint16 authstartid; // 0x20
|
||||
char unusedg[5]; // 0x22
|
||||
char unusedg2[2]; // 0x22
|
||||
quint16 resetcap; // 0x24
|
||||
char unusedg1; // 0x26
|
||||
quint16 commoncap; // 0x27
|
||||
char unusedh; // 0x29
|
||||
quint8 macaddress[6]; // 0x2a
|
||||
quint8 macaddress[6]; // 0x2a
|
||||
};
|
||||
quint8 guid[GUIDLEN]; // 0x20
|
||||
};
|
||||
|
@ -397,6 +399,49 @@ typedef union capabilities_packet {
|
|||
} *capabilities_packet_t;
|
||||
|
||||
|
||||
typedef union streamdeck_image_header {
|
||||
struct
|
||||
{
|
||||
quint8 cmd;
|
||||
quint8 suffix;
|
||||
quint8 button;
|
||||
quint8 isLast;
|
||||
quint16 length;
|
||||
quint16 index;
|
||||
};
|
||||
char packet[8];
|
||||
} *streamdeck_image_header_t;
|
||||
|
||||
typedef union streamdeck_v1_image_header {
|
||||
struct
|
||||
{
|
||||
quint8 cmd;
|
||||
quint8 suffix;
|
||||
quint16 index;
|
||||
quint8 isLast;
|
||||
quint8 button;
|
||||
quint8 unused[10];
|
||||
};
|
||||
char packet[16];
|
||||
} *streamdeck_v1_image_header_t;
|
||||
|
||||
typedef union streamdeck_lcd_header {
|
||||
struct
|
||||
{
|
||||
quint8 cmd;
|
||||
quint8 suffix;
|
||||
quint16 x;
|
||||
quint16 y;
|
||||
quint16 width;
|
||||
quint16 height;
|
||||
quint8 isLast;
|
||||
quint16 index;
|
||||
quint16 length;
|
||||
quint8 unused;
|
||||
};
|
||||
char packet[16];
|
||||
} *streamdeck_lcd_header_t;
|
||||
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
|
139
pahandler.cpp
|
@ -42,16 +42,20 @@ bool paHandler::init(audioSetup setup)
|
|||
return false;
|
||||
}
|
||||
|
||||
inFormat = toQAudioFormat(setup.codec, setup.sampleRate);
|
||||
radioFormat = toQAudioFormat(setup.codec, setup.sampleRate);
|
||||
|
||||
qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name <<
|
||||
", bits" << inFormat.sampleSize() <<
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
", bits" << radioFormat.sampleSize() <<
|
||||
#else
|
||||
", format" << radioFormat.sampleFormat() <<
|
||||
#endif
|
||||
", codec" << setup.codec <<
|
||||
", latency" << setup.latency <<
|
||||
", localAFGain" << setup.localAFgain <<
|
||||
", radioChan" << inFormat.channelCount() <<
|
||||
", radioChan" << radioFormat.channelCount() <<
|
||||
", resampleQuality" << setup.resampleQuality <<
|
||||
", samplerate" << inFormat.sampleRate() <<
|
||||
", samplerate" << radioFormat.sampleRate() <<
|
||||
", uLaw" << setup.ulaw;
|
||||
|
||||
PaError err;
|
||||
|
@ -65,6 +69,13 @@ bool paHandler::init(audioSetup setup)
|
|||
// qDebug(logAudio()) << "Portaudio initialized";
|
||||
//}
|
||||
|
||||
|
||||
codecType codec = LPCM;
|
||||
if (setup.codec == 0x01 || setup.codec == 0x20)
|
||||
codec = PCMU;
|
||||
else if (setup.codec == 0x40 || setup.codec == 0x40)
|
||||
codec = OPUS;
|
||||
|
||||
memset(&aParams, 0, sizeof(PaStreamParameters));
|
||||
|
||||
aParams.device = setup.portInt;
|
||||
|
@ -74,43 +85,52 @@ bool paHandler::init(audioSetup setup)
|
|||
|
||||
|
||||
if (setup.isinput) {
|
||||
outFormat.setChannelCount(info->maxInputChannels);
|
||||
nativeFormat.setChannelCount(info->maxInputChannels);
|
||||
}
|
||||
else {
|
||||
outFormat.setChannelCount(info->maxOutputChannels);
|
||||
nativeFormat.setChannelCount(info->maxOutputChannels);
|
||||
}
|
||||
|
||||
aParams.suggestedLatency = (float)setup.latency / 1000.0f;
|
||||
outFormat.setSampleRate(info->defaultSampleRate);
|
||||
nativeFormat.setSampleRate(info->defaultSampleRate);
|
||||
aParams.sampleFormat = paFloat32;
|
||||
outFormat.setSampleSize(32);
|
||||
outFormat.setSampleType(QAudioFormat::Float);
|
||||
outFormat.setByteOrder(QAudioFormat::LittleEndian);
|
||||
outFormat.setCodec("audio/pcm");
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
nativeFormat.setSampleSize(32);
|
||||
nativeFormat.setSampleType(QAudioFormat::Float);
|
||||
nativeFormat.setByteOrder(QAudioFormat::LittleEndian);
|
||||
nativeFormat.setCodec("audio/pcm");
|
||||
#else
|
||||
nativeFormat.setSampleFormat(QAudioFormat::Float);
|
||||
#endif
|
||||
|
||||
if (outFormat.channelCount() > 2) {
|
||||
outFormat.setChannelCount(2);
|
||||
if (nativeFormat.channelCount() > 2) {
|
||||
nativeFormat.setChannelCount(2);
|
||||
}
|
||||
else if (outFormat.channelCount() < 1)
|
||||
else if (nativeFormat.channelCount() < 1)
|
||||
{
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "No channels found, aborting setup.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inFormat.channelCount() < outFormat.channelCount()) {
|
||||
outFormat.setChannelCount(inFormat.channelCount());
|
||||
if (nativeFormat.channelCount() == 1 && radioFormat.channelCount() == 2) {
|
||||
nativeFormat.setChannelCount(2);
|
||||
}
|
||||
|
||||
aParams.channelCount = outFormat.channelCount();
|
||||
aParams.channelCount = nativeFormat.channelCount();
|
||||
|
||||
if (outFormat.sampleRate() < 44100) {
|
||||
outFormat.setSampleRate(48000);
|
||||
if (nativeFormat.sampleRate() < 44100) {
|
||||
nativeFormat.setSampleRate(48000);
|
||||
}
|
||||
|
||||
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << outFormat.sampleSize() << "Channel Count" << outFormat.channelCount() <<
|
||||
"Sample Rate" << outFormat.sampleRate() << "Codec" << outFormat.codec() << "Sample Type" << outFormat.sampleType();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << nativeFormat.sampleSize() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec << "Sample Type" << nativeFormat.sampleType();
|
||||
#else
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleFormat" << nativeFormat.sampleFormat() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec;
|
||||
#endif
|
||||
|
||||
// We "hopefully" now have a valid format that is supported so try connecting
|
||||
|
||||
|
@ -124,7 +144,7 @@ bool paHandler::init(audioSetup setup)
|
|||
}
|
||||
converter->moveToThread(converterThread);
|
||||
|
||||
connect(this, SIGNAL(setupConverter(QAudioFormat, QAudioFormat, quint8, quint8)), converter, SLOT(init(QAudioFormat, QAudioFormat, quint8, quint8)));
|
||||
connect(this, SIGNAL(setupConverter(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)), converter, SLOT(init(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)));
|
||||
connect(converterThread, SIGNAL(finished()), converter, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(sendToConverter(audioPacket)), converter, SLOT(convert(audioPacket)));
|
||||
converterThread->start(QThread::TimeCriticalPriority);
|
||||
|
@ -132,52 +152,55 @@ bool paHandler::init(audioSetup setup)
|
|||
aParams.hostApiSpecificStreamInfo = NULL;
|
||||
|
||||
// Per channel chunk size.
|
||||
this->chunkSize = (outFormat.bytesForDuration(setup.blockSize * 1000) / sizeof(float)) * outFormat.channelCount();
|
||||
this->chunkSize = nativeFormat.framesForDuration(setup.blockSize * 1000);
|
||||
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Chunk size" << this->chunkSize;
|
||||
// Check the format is supported
|
||||
|
||||
|
||||
if (setup.isinput) {
|
||||
err = Pa_IsFormatSupported(&aParams, NULL, outFormat.sampleRate());
|
||||
}
|
||||
else
|
||||
{
|
||||
err = Pa_IsFormatSupported(NULL,&aParams, outFormat.sampleRate());
|
||||
}
|
||||
|
||||
if (err != paNoError) {
|
||||
err = -1;
|
||||
int errCount = 0;
|
||||
while (err != paNoError) {
|
||||
if (setup.isinput) {
|
||||
err = Pa_IsFormatSupported(&aParams, NULL, nativeFormat.sampleRate());
|
||||
}
|
||||
else
|
||||
{
|
||||
err = Pa_IsFormatSupported(NULL, &aParams, nativeFormat.sampleRate());
|
||||
}
|
||||
if (err == paInvalidChannelCount)
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported channel count" << aParams.channelCount;
|
||||
if (aParams.channelCount == 2) {
|
||||
aParams.channelCount = 1;
|
||||
outFormat.setChannelCount(1);
|
||||
nativeFormat.setChannelCount(1);
|
||||
}
|
||||
else {
|
||||
aParams.channelCount = 2;
|
||||
outFormat.setChannelCount(2);
|
||||
nativeFormat.setChannelCount(2);
|
||||
}
|
||||
}
|
||||
else if (err == paInvalidSampleRate)
|
||||
if (err == paInvalidSampleRate)
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported sample rate" << outFormat.sampleRate();
|
||||
outFormat.setSampleRate(44100);
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported sample rate" << nativeFormat.sampleRate();
|
||||
nativeFormat.setSampleRate(44100);
|
||||
}
|
||||
else if (err == paSampleFormatNotSupported)
|
||||
if (err == paSampleFormatNotSupported)
|
||||
{
|
||||
aParams.sampleFormat = paInt16;
|
||||
outFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
outFormat.setSampleSize(16);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported sample Format" << nativeFormat.sampleType();
|
||||
nativeFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
nativeFormat.setSampleSize(16);
|
||||
#else
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported sample Format" << nativeFormat.sampleFormat();
|
||||
nativeFormat.setSampleFormat(QAudioFormat::Int16);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (setup.isinput) {
|
||||
err = Pa_IsFormatSupported(&aParams, NULL, outFormat.sampleRate());
|
||||
}
|
||||
else
|
||||
{
|
||||
err = Pa_IsFormatSupported(NULL, &aParams, outFormat.sampleRate());
|
||||
}
|
||||
if (err != paNoError) {
|
||||
errCount++;
|
||||
if (errCount > 5) {
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "Cannot find suitable format, aborting:" << Pa_GetErrorText(err);
|
||||
return false;
|
||||
}
|
||||
|
@ -185,13 +208,13 @@ bool paHandler::init(audioSetup setup)
|
|||
|
||||
if (setup.isinput) {
|
||||
|
||||
err = Pa_OpenStream(&audio, &aParams, 0, outFormat.sampleRate(), this->chunkSize, paNoFlag, &paHandler::staticWrite, (void*)this);
|
||||
emit setupConverter(outFormat, inFormat, 7, setup.resampleQuality);
|
||||
err = Pa_OpenStream(&audio, &aParams, 0, nativeFormat.sampleRate(), this->chunkSize, paNoFlag, &paHandler::staticWrite, (void*)this);
|
||||
emit setupConverter(nativeFormat, codecType::LPCM, radioFormat, codec, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedInput(audioPacket)));
|
||||
}
|
||||
else {
|
||||
err = Pa_OpenStream(&audio, 0, &aParams, outFormat.sampleRate(), this->chunkSize, paNoFlag, NULL, NULL);
|
||||
emit setupConverter(inFormat, outFormat, 7, setup.resampleQuality);
|
||||
err = Pa_OpenStream(&audio, 0, &aParams, nativeFormat.sampleRate(), this->chunkSize, paNoFlag, NULL, NULL);
|
||||
emit setupConverter(radioFormat, codec, nativeFormat, codecType::LPCM, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedOutput(audioPacket)));
|
||||
}
|
||||
|
||||
|
@ -224,7 +247,13 @@ void paHandler::setVolume(unsigned char volume)
|
|||
void paHandler::incomingAudio(audioPacket packet)
|
||||
{
|
||||
packet.volume = volume;
|
||||
emit sendToConverter(packet);
|
||||
if (Pa_IsStreamActive(audio) == 1) {
|
||||
emit sendToConverter(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pa_StartStream(audio);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -242,7 +271,7 @@ int paHandler::writeData(const void* inputBuffer, void* outputBuffer,
|
|||
packet.sent = 0;
|
||||
packet.volume = volume;
|
||||
memcpy(&packet.guid, setup.guid, GUIDLEN);
|
||||
packet.data.append((char*)inputBuffer, nFrames*inFormat.channelCount()*sizeof(float));
|
||||
packet.data.append((char*)inputBuffer, nFrames*nativeFormat.bytesPerFrame());
|
||||
emit sendToConverter(packet);
|
||||
|
||||
if (status == paInputUnderflow) {
|
||||
|
@ -266,7 +295,7 @@ void paHandler::convertedOutput(audioPacket packet) {
|
|||
if (packet.data.size() > 0) {
|
||||
|
||||
if (Pa_IsStreamActive(audio) == 1) {
|
||||
PaError err = Pa_WriteStream(audio, (char*)packet.data.data(), packet.data.size() / sizeof(float) / outFormat.channelCount());
|
||||
PaError err = Pa_WriteStream(audio, (char*)packet.data.data(), packet.data.size() / nativeFormat.bytesPerFrame());
|
||||
|
||||
if (err != paNoError) {
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Error writing audio!";
|
||||
|
@ -298,6 +327,8 @@ void paHandler::convertedInput(audioPacket packet)
|
|||
void paHandler::changeLatency(const quint16 newSize)
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << setup.latency;
|
||||
setup.latency = newSize;
|
||||
latencyAllowance = 0;
|
||||
}
|
||||
|
||||
int paHandler::getLatency()
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
|
||||
int getLatency();
|
||||
|
||||
|
||||
using audioHandler::getNextAudioChunk;
|
||||
void getNextAudioChunk(QByteArray& data);
|
||||
quint16 getAmplitude();
|
||||
|
||||
|
@ -56,7 +56,7 @@ signals:
|
|||
void sendLatency(quint16 newSize);
|
||||
void haveAudioData(const audioPacket& data);
|
||||
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS, quint16 latency, quint16 current, bool under, bool over);
|
||||
void setupConverter(QAudioFormat in, QAudioFormat out, quint8 opus, quint8 resamp);
|
||||
void setupConverter(QAudioFormat in, codecType codecIn, QAudioFormat out, codecType codecOut, quint8 opus, quint8 resamp);
|
||||
void sendToConverter(audioPacket audio);
|
||||
|
||||
private:
|
||||
|
@ -85,12 +85,13 @@ private:
|
|||
qreal volume = 1.0;
|
||||
|
||||
audioSetup setup;
|
||||
QAudioFormat inFormat;
|
||||
QAudioFormat outFormat;
|
||||
QAudioFormat radioFormat;
|
||||
QAudioFormat nativeFormat;
|
||||
audioConverter* converter = Q_NULLPTR;
|
||||
QThread* converterThread = Q_NULLPTR;
|
||||
bool isUnderrun = false;
|
||||
bool isOverrun = false;
|
||||
int latencyAllowance = 0;
|
||||
};
|
||||
|
||||
#endif // PAHANDLER_H
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef PREFS_H
|
||||
#define PREFS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QMap>
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
|
||||
struct preferences {
|
||||
// Program:
|
||||
QString version;
|
||||
int majorVersion = 0;
|
||||
int minorVersion = 0;
|
||||
QString gitShort;
|
||||
|
||||
// Interface:
|
||||
bool useFullScreen;
|
||||
bool useSystemTheme;
|
||||
int wfEnable;
|
||||
bool drawPeaks;
|
||||
underlay_t underlayMode = underlayNone;
|
||||
int underlayBufferSize = 64;
|
||||
bool wfAntiAlias;
|
||||
bool wfInterpolate;
|
||||
int wftheme;
|
||||
int plotFloor;
|
||||
int plotCeiling;
|
||||
QString stylesheetPath;
|
||||
unsigned int wflength;
|
||||
bool confirmExit;
|
||||
bool confirmPowerOff;
|
||||
meterKind meter2Type;
|
||||
bool clickDragTuningEnable;
|
||||
|
||||
// Radio:
|
||||
unsigned char radioCIVAddr;
|
||||
bool CIVisRadioModel;
|
||||
bool forceRTSasPTT;
|
||||
int polling_ms;
|
||||
QString serialPortRadio;
|
||||
quint32 serialPortBaud;
|
||||
QString virtualSerialPort;
|
||||
unsigned char localAFgain;
|
||||
audioType audioSystem;
|
||||
|
||||
// Controls:
|
||||
bool enablePTT;
|
||||
bool niceTS;
|
||||
bool automaticSidebandSwitching = true;
|
||||
bool enableUSBControllers;
|
||||
|
||||
// LAN:
|
||||
bool enableLAN;
|
||||
bool enableRigCtlD;
|
||||
quint16 rigCtlPort;
|
||||
int currentColorPresetNumber = 0;
|
||||
quint16 tcpPort;
|
||||
quint8 waterfallFormat;
|
||||
|
||||
// Cluster:
|
||||
bool clusterUdpEnable;
|
||||
bool clusterTcpEnable;
|
||||
int clusterUdpPort;
|
||||
QString clusterTcpServerName;
|
||||
QString clusterTcpUserName;
|
||||
QString clusterTcpPassword;
|
||||
int clusterTimeout;
|
||||
bool clusterSkimmerSpotsEnable;
|
||||
|
||||
};
|
||||
|
||||
#endif // PREFS_H
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef PRINTHEX_H
|
||||
#define PRINTHEX_H
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
|
||||
#include "logcategories.h"
|
||||
|
||||
QString inline getHex(const QByteArray &pdata)
|
||||
{
|
||||
QString head = "---- Begin hex dump -----:\n";
|
||||
QString sdata("DATA: ");
|
||||
QString index("INDEX: ");
|
||||
|
||||
for(int i=0; i < pdata.length(); i++)
|
||||
{
|
||||
sdata.append(QString("%1 ").arg((unsigned char)pdata[i], 2, 16, QChar('0')) );
|
||||
index.append(QString("%1 ").arg(i, 2, 10, QChar('0')));
|
||||
}
|
||||
|
||||
sdata.append("\n");
|
||||
index.append("\n");
|
||||
|
||||
QString tail = "---- End hex dump -----\n";
|
||||
return head + sdata + index + tail;
|
||||
}
|
||||
|
||||
void inline printHexNow(const QByteArray &pdata, const QLoggingCategory &cat)
|
||||
{
|
||||
QString d = getHex(pdata);
|
||||
// These lines are needed to keep the formatting as expected in the log file
|
||||
if(d.endsWith("\n"))
|
||||
{
|
||||
d.chop(1);
|
||||
}
|
||||
QStringList s = d.split("\n");
|
||||
for(int i=0; i < s.length(); i++)
|
||||
{
|
||||
qDebug(cat) << s.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PRINTHEX_H
|
|
@ -90,7 +90,7 @@ void pttyHandler::openPort()
|
|||
qInfo(logSerial()) << "Could not open pseudo terminal port, please restart.";
|
||||
isConnected = false;
|
||||
serialError = true;
|
||||
emit haveSerialPortError(portName, "Could not open pseudo terminal port. Please restart.");
|
||||
emit havePortError(errorType(portName, "Could not open pseudo terminal port. Please restart."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QtSerialPort/QSerialPort>
|
||||
|
||||
#include "rigidentities.h"
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
// This class abstracts the comm port in a useful way and connects to
|
||||
// the command creator and command parser.
|
||||
|
@ -34,7 +35,7 @@ private slots:
|
|||
signals:
|
||||
void haveTextMessage(QString message); // status, debug only
|
||||
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
|
||||
void haveSerialPortError(const QString port, const QString error);
|
||||
void havePortError(errorType err);
|
||||
void haveStatusUpdate(const QString text);
|
||||
|
||||
private:
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
static const int SIZE = 16;
|
||||
static const QString greenSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.145, y1:0.16, x2:1, y2:1, stop:0 rgba(20, 252, 7, 255), stop:1 rgba(25, 134, 5, 255));").arg(SIZE / 2);
|
||||
static const QString redSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.145, y1:0.16, x2:0.92, y2:0.988636, stop:0 rgba(255, 12, 12, 255), stop:0.869347 rgba(103, 0, 0, 255));").arg(SIZE / 2);
|
||||
static const QString rgSplitSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(255, 0, 0, 255), stop:1.0 rgba(0, 255, 0, 255));").arg(SIZE / 2);
|
||||
static const QString orangeSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.232, y1:0.272, x2:0.98, y2:0.959773, stop:0 rgba(255, 113, 4, 255), stop:1 rgba(91, 41, 7, 255))").arg(SIZE / 2);
|
||||
static const QString blueSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.04, y1:0.0565909, x2:0.799, y2:0.795, stop:0 rgba(203, 220, 255, 255), stop:0.41206 rgba(0, 115, 255, 255), stop:1 rgba(0, 49, 109, 255));").arg(SIZE / 2);
|
||||
static const QString blankSS = QString("color: white;border-radius: %1;background-color: qlineargradient(spread:pad, x1:0.04, y1:0.0565909, x2:0.799, y2:0.795, stop:0 rgba(203, 220, 255, 0), stop:0.41206 rgba(0, 115, 255, 0), stop:1 rgba(0, 49, 109, 0));").arg(SIZE / 2);
|
||||
|
@ -19,7 +20,7 @@ QLedLabel::QLedLabel(QWidget* parent) :
|
|||
|
||||
void QLedLabel::setState(State state)
|
||||
{
|
||||
qInfo() << "setState" << state;
|
||||
//Debug() << "LED: setState" << state;
|
||||
switch (state) {
|
||||
case StateOk:
|
||||
setStyleSheet(greenSS);
|
||||
|
@ -36,6 +37,9 @@ void QLedLabel::setState(State state)
|
|||
case StateBlank:
|
||||
setStyleSheet(blankSS);
|
||||
break;
|
||||
case StateSplitErrorOk:
|
||||
setStyleSheet(rgSplitSS);
|
||||
break;
|
||||
default:
|
||||
setStyleSheet(blueSS);
|
||||
break;
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
StateOkBlue,
|
||||
StateWarning,
|
||||
StateError,
|
||||
StateSplitErrorOk,
|
||||
StateBlank
|
||||
};
|
||||
|
||||
|
|
|
@ -2,31 +2,7 @@
|
|||
#define REPEATERATTRIBUTES_H
|
||||
#include <QMetaType>
|
||||
|
||||
enum duplexMode {
|
||||
dmSplitOff=0x00,
|
||||
dmSplitOn=0x01,
|
||||
dmSimplex=0x10,
|
||||
dmDupMinus=0x11,
|
||||
dmDupPlus=0x12,
|
||||
dmDupRPS=0x13,
|
||||
dmDupAutoOn=0x26,
|
||||
dmDupAutoOff=0x36
|
||||
};
|
||||
// TODO: Remove this file as it does nothing.
|
||||
|
||||
// Here, T=tone, D=DCS, N=none
|
||||
// And the naming convention order is Transmit Receive
|
||||
enum rptAccessTxRx {
|
||||
ratrNN=0x00,
|
||||
ratrTN=0x01, // "TONE" (T only)
|
||||
ratrNT=0x02, // "TSQL" (R only)
|
||||
ratrDD=0x03, // "DTCS" (TR)
|
||||
ratrDN=0x06, // "DTCS(T)"
|
||||
ratrTD=0x07, // "TONE(T) / TSQL(R)"
|
||||
ratrDT=0x08, // "DTCS(T) / TSQL(R)"
|
||||
ratrTT=0x09 // "TONE(T) / TSQL(R)"
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(enum duplexMode)
|
||||
Q_DECLARE_METATYPE(enum rptAccessTxRx)
|
||||
|
||||
#endif // REPEATERATTRIBUTES_H
|
||||
|
|
|
@ -7,20 +7,13 @@ repeaterSetup::repeaterSetup(QWidget *parent) :
|
|||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->autoTrackLiveBtn->setEnabled(false); // until we set split enabled.
|
||||
ui->warningFMLabel->setVisible(false);
|
||||
// populate the CTCSS combo box:
|
||||
populateTones();
|
||||
|
||||
// populate the DCS combo box:
|
||||
populateDTCS();
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
ui->debugBtn->setVisible(true);
|
||||
ui->rptReadRigBtn->setVisible(true);
|
||||
#else
|
||||
ui->debugBtn->setVisible(false);
|
||||
ui->rptReadRigBtn->setVisible(false);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
repeaterSetup::~repeaterSetup()
|
||||
|
@ -48,7 +41,6 @@ void repeaterSetup::setRig(rigCapabilities inRig)
|
|||
ui->toneTone->setDisabled(true);
|
||||
ui->toneTSQL->setDisabled(true);
|
||||
}
|
||||
|
||||
if(rig.hasDTCS)
|
||||
{
|
||||
ui->rptDTCSCombo->setDisabled(false);
|
||||
|
@ -61,6 +53,55 @@ void repeaterSetup::setRig(rigCapabilities inRig)
|
|||
ui->rptDTCSInvertRx->setDisabled(true);
|
||||
ui->rptDTCSInvertTx->setDisabled(true);
|
||||
}
|
||||
if(rig.hasVFOAB)
|
||||
{
|
||||
ui->selABtn->setDisabled(false);
|
||||
ui->selBBtn->setDisabled(false);
|
||||
ui->aEqBBtn->setDisabled(false);
|
||||
ui->swapABBtn->setDisabled(false);
|
||||
} else {
|
||||
ui->selABtn->setDisabled(true);
|
||||
ui->selBBtn->setDisabled(true);
|
||||
ui->aEqBBtn->setDisabled(true);
|
||||
ui->swapABBtn->setDisabled(true);
|
||||
}
|
||||
if(rig.hasVFOMS)
|
||||
{
|
||||
ui->selMainBtn->setDisabled(false);
|
||||
ui->selSubBtn->setDisabled(false);
|
||||
ui->mEqSBtn->setDisabled(false);
|
||||
ui->swapMSBtn->setDisabled(false);
|
||||
} else {
|
||||
ui->selMainBtn->setDisabled(true);
|
||||
ui->selSubBtn->setDisabled(true);
|
||||
ui->mEqSBtn->setDisabled(true);
|
||||
ui->swapMSBtn->setDisabled(true);
|
||||
}
|
||||
if(rig.hasVFOMS && rig.hasVFOAB)
|
||||
{
|
||||
// Rigs that have both AB and MS
|
||||
// do not have a swap AB command.
|
||||
ui->swapABBtn->setDisabled(true);
|
||||
}
|
||||
if(rig.hasSpecifyMainSubCmd)
|
||||
{
|
||||
ui->setRptrSubVFOBtn->setEnabled(true);
|
||||
ui->setToneSubVFOBtn->setEnabled(true);
|
||||
ui->setSplitRptrToneChk->setEnabled(true);
|
||||
} else {
|
||||
ui->setRptrSubVFOBtn->setDisabled(true);
|
||||
ui->setToneSubVFOBtn->setDisabled(true);
|
||||
ui->setSplitRptrToneChk->setDisabled(true);
|
||||
}
|
||||
ui->rptAutoBtn->setEnabled(rig.hasRepeaterModes);
|
||||
ui->rptDupMinusBtn->setEnabled(rig.hasRepeaterModes);
|
||||
ui->rptDupPlusBtn->setEnabled(rig.hasRepeaterModes);
|
||||
ui->rptSimplexBtn->setEnabled(rig.hasRepeaterModes);
|
||||
ui->rptrOffsetEdit->setEnabled(rig.hasRepeaterModes);
|
||||
ui->rptrOffsetSetBtn->setEnabled(rig.hasRepeaterModes);
|
||||
ui->setToneSubVFOBtn->setEnabled(rig.hasSpecifyMainSubCmd);
|
||||
ui->setRptrSubVFOBtn->setEnabled(rig.hasSpecifyMainSubCmd);
|
||||
ui->quickSplitChk->setVisible(rig.hasQuickSplitCommand);
|
||||
}
|
||||
|
||||
void repeaterSetup::populateTones()
|
||||
|
@ -235,44 +276,81 @@ void repeaterSetup::populateDTCS()
|
|||
void repeaterSetup::receiveDuplexMode(duplexMode dm)
|
||||
{
|
||||
currentdm = dm;
|
||||
ui->splitEnableChk->blockSignals(true);
|
||||
switch(dm)
|
||||
{
|
||||
case dmSimplex:
|
||||
case dmSplitOff:
|
||||
ui->splitOffBtn->setChecked(true);
|
||||
ui->autoTrackLiveBtn->setDisabled(true);
|
||||
break;
|
||||
case dmSplitOn:
|
||||
ui->splitEnableChk->setChecked(true);
|
||||
ui->rptSimplexBtn->setChecked(false);
|
||||
ui->rptDupPlusBtn->setChecked(false);
|
||||
ui->autoTrackLiveBtn->setEnabled(true);
|
||||
ui->rptDupMinusBtn->setChecked(false);
|
||||
break;
|
||||
case dmSimplex:
|
||||
ui->rptSimplexBtn->setChecked(true);
|
||||
//ui->splitEnableChk->setChecked(false);
|
||||
ui->autoTrackLiveBtn->setDisabled(true);
|
||||
break;
|
||||
case dmDupPlus:
|
||||
ui->rptDupPlusBtn->setChecked(true);
|
||||
//ui->splitEnableChk->setChecked(false);
|
||||
ui->autoTrackLiveBtn->setDisabled(true);
|
||||
break;
|
||||
case dmDupMinus:
|
||||
ui->rptDupMinusBtn->setChecked(true);
|
||||
//ui->splitEnableChk->setChecked(false);
|
||||
ui->autoTrackLiveBtn->setDisabled(true);
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Did not understand duplex/split/repeater value of " << (unsigned char)dm;
|
||||
break;
|
||||
}
|
||||
ui->splitEnableChk->blockSignals(false);
|
||||
}
|
||||
|
||||
void repeaterSetup::handleRptAccessMode(rptAccessTxRx tmode)
|
||||
{
|
||||
// ratrXY
|
||||
// X = Transmit (T)one or (N)one or (D)CS
|
||||
// Y = Receive (T)sql or (N)one or (D)CS
|
||||
switch(tmode)
|
||||
{
|
||||
case ratrNN:
|
||||
ui->toneNone->setChecked(true);
|
||||
break;
|
||||
case ratrTT:
|
||||
ui->toneTSQL->setChecked(true);
|
||||
break;
|
||||
case ratrTN:
|
||||
ui->toneTone->setChecked(true);
|
||||
break;
|
||||
case ratrDD:
|
||||
ui->toneDTCS->setChecked(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case ratrNN:
|
||||
ui->toneNone->setChecked(true);
|
||||
break;
|
||||
case ratrTT:
|
||||
case ratrNT:
|
||||
ui->toneTSQL->setChecked(true);
|
||||
break;
|
||||
case ratrTN:
|
||||
ui->toneTone->setChecked(true);
|
||||
break;
|
||||
case ratrDD:
|
||||
ui->toneDTCS->setChecked(true);
|
||||
break;
|
||||
case ratrTONEoff:
|
||||
ui->toneTone->setChecked(false);
|
||||
break;
|
||||
case ratrTONEon:
|
||||
ui->toneTone->setChecked(true);
|
||||
break;
|
||||
case ratrTSQLoff:
|
||||
ui->toneTSQL->setChecked(false);
|
||||
break;
|
||||
case ratrTSQLon:
|
||||
ui->toneTSQL->setChecked(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if( !ui->toneTSQL->isChecked() && !ui->toneTone->isChecked() && !ui->toneDTCS->isChecked())
|
||||
{
|
||||
ui->toneNone->setChecked(true);
|
||||
}
|
||||
|
||||
(void)tmode;
|
||||
}
|
||||
|
||||
void repeaterSetup::handleTone(quint16 tone)
|
||||
|
@ -296,11 +374,112 @@ void repeaterSetup::handleDTCS(quint16 dcode, bool tinv, bool rinv)
|
|||
ui->rptDTCSInvertRx->setChecked(rinv);
|
||||
}
|
||||
|
||||
void repeaterSetup::handleUpdateCurrentMainFrequency(freqt mainfreq)
|
||||
{
|
||||
if(amTransmitting)
|
||||
return;
|
||||
|
||||
// Track if autoTrack enabled, split enabled, and there's a split defined.
|
||||
if(ui->autoTrackLiveBtn->isChecked() && (currentdm == dmSplitOn) && !ui->splitOffsetEdit->text().isEmpty())
|
||||
{
|
||||
if(currentMainFrequency.Hz != mainfreq.Hz)
|
||||
{
|
||||
this->currentMainFrequency = mainfreq;
|
||||
if(!ui->splitTransmitFreqEdit->hasFocus())
|
||||
{
|
||||
if(usedPlusSplit)
|
||||
{
|
||||
on_splitPlusButton_clicked();
|
||||
} else {
|
||||
on_splitMinusBtn_clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ui->setSplitRptrToneChk->isChecked())
|
||||
{
|
||||
// TODO, not really needed if the op
|
||||
// just sets the tone when needed, as it will do both bands.
|
||||
}
|
||||
}
|
||||
this->currentMainFrequency = mainfreq;
|
||||
}
|
||||
|
||||
void repeaterSetup::handleUpdateCurrentMainMode(mode_info m)
|
||||
{
|
||||
// Used to set the secondary VFO to the same mode
|
||||
// (generally FM)
|
||||
// NB: We don't accept values during transmit as they
|
||||
// may represent the inactive VFO
|
||||
if(!amTransmitting)
|
||||
{
|
||||
this->currentModeMain = m;
|
||||
this->modeTransmitVFO = m;
|
||||
this->modeTransmitVFO.VFO = inactiveVFO;
|
||||
if(m.mk == modeFM)
|
||||
ui->warningFMLabel->setVisible(false);
|
||||
else
|
||||
ui->warningFMLabel->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::handleRptOffsetFrequency(freqt f)
|
||||
{
|
||||
// Called when a new offset is available from the radio.
|
||||
QString offsetstr = QString::number(f.Hz / double(1E6), 'f', 4);
|
||||
|
||||
if(!ui->rptrOffsetEdit->hasFocus())
|
||||
{
|
||||
ui->rptrOffsetEdit->setText(offsetstr);
|
||||
currentOffset = f;
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::handleTransmitStatus(bool amTransmitting)
|
||||
{
|
||||
this->amTransmitting = amTransmitting;
|
||||
}
|
||||
|
||||
void repeaterSetup::showEvent(QShowEvent *event)
|
||||
{
|
||||
emit getDuplexMode();
|
||||
emit getSplitModeEnabled();
|
||||
if(rig.hasRepeaterModes)
|
||||
emit getRptDuplexOffset();
|
||||
QMainWindow::showEvent(event);
|
||||
(void)event;
|
||||
}
|
||||
|
||||
void repeaterSetup::on_splitEnableChk_clicked()
|
||||
{
|
||||
emit setDuplexMode(dmSplitOn);
|
||||
ui->autoTrackLiveBtn->setEnabled(true);
|
||||
|
||||
if(ui->autoTrackLiveBtn->isChecked() && !ui->splitOffsetEdit->text().isEmpty())
|
||||
{
|
||||
if(usedPlusSplit)
|
||||
{
|
||||
on_splitPlusButton_clicked();
|
||||
} else {
|
||||
on_splitMinusBtn_clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_splitOffBtn_clicked()
|
||||
{
|
||||
emit setDuplexMode(dmSplitOff);
|
||||
ui->autoTrackLiveBtn->setDisabled(true);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_rptSimplexBtn_clicked()
|
||||
{
|
||||
// Simplex
|
||||
emit setDuplexMode(dmDupAutoOff);
|
||||
emit setDuplexMode(dmSimplex);
|
||||
emit setDuplexMode(dmSplitOff);
|
||||
if(rig.hasRepeaterModes)
|
||||
{
|
||||
emit setDuplexMode(dmDupAutoOff);
|
||||
emit setDuplexMode(dmSimplex);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_rptDupPlusBtn_clicked()
|
||||
|
@ -324,20 +503,29 @@ void repeaterSetup::on_rptAutoBtn_clicked()
|
|||
emit setDuplexMode(dmDupAutoOn);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_rptReadRigBtn_clicked()
|
||||
{
|
||||
emit getDuplexMode();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_rptToneCombo_activated(int tindex)
|
||||
{
|
||||
quint16 tone=0;
|
||||
tone = (quint16)ui->rptToneCombo->itemData(tindex).toUInt();
|
||||
rptrTone_t rt;
|
||||
rt.tone = tone;
|
||||
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
|
||||
if(ui->toneTone->isChecked())
|
||||
{
|
||||
emit setTone(tone);
|
||||
emit setTone(rt);
|
||||
if(updateSub)
|
||||
{
|
||||
rt.useSecondaryVFO = true;
|
||||
emit setTone(rt);
|
||||
}
|
||||
|
||||
} else if (ui->toneTSQL->isChecked()) {
|
||||
emit setTSQL(tone);
|
||||
emit setTSQL(rt);
|
||||
if(updateSub)
|
||||
{
|
||||
rt.useSecondaryVFO = true;
|
||||
emit setTone(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,45 +541,304 @@ void repeaterSetup::on_rptDTCSCombo_activated(int index)
|
|||
void repeaterSetup::on_toneNone_clicked()
|
||||
{
|
||||
rptAccessTxRx rm;
|
||||
rptrAccessData_t rd;
|
||||
rm = ratrNN;
|
||||
emit setRptAccessMode(rm);
|
||||
rd.accessMode = rm;
|
||||
emit setRptAccessMode(rd);
|
||||
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
|
||||
|
||||
if(updateSub)
|
||||
{
|
||||
rd.useSecondaryVFO = true;
|
||||
emit setRptAccessMode(rd);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_toneTone_clicked()
|
||||
{
|
||||
rptAccessTxRx rm;
|
||||
rptrAccessData_t rd;
|
||||
rm = ratrTN;
|
||||
emit setRptAccessMode(rm);
|
||||
emit setTone((quint16)ui->rptToneCombo->currentData().toUInt());
|
||||
rd.accessMode = rm;
|
||||
rptrTone_t rt;
|
||||
rt.tone = (quint16)ui->rptToneCombo->currentData().toUInt();
|
||||
emit setRptAccessMode(rd);
|
||||
emit setTone(rt);
|
||||
|
||||
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
|
||||
|
||||
if(updateSub)
|
||||
{
|
||||
rd.useSecondaryVFO = true;
|
||||
rt.useSecondaryVFO = true;
|
||||
emit setRptAccessMode(rd);
|
||||
emit setTone(rt);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_toneTSQL_clicked()
|
||||
{
|
||||
rptAccessTxRx rm;
|
||||
rptrAccessData_t rd;
|
||||
rm = ratrTT;
|
||||
emit setRptAccessMode(rm);
|
||||
emit setTSQL((quint16)ui->rptToneCombo->currentData().toUInt());
|
||||
rptrTone_t rt;
|
||||
rt.tone = (quint16)ui->rptToneCombo->currentData().toUInt();
|
||||
rd.accessMode = rm;
|
||||
emit setRptAccessMode(rd);
|
||||
emit setTSQL(rt);
|
||||
bool updateSub = ui->setSplitRptrToneChk->isEnabled() && ui->setSplitRptrToneChk->isChecked();
|
||||
|
||||
if(updateSub)
|
||||
{
|
||||
rd.useSecondaryVFO = true;
|
||||
rt.useSecondaryVFO = true;
|
||||
emit setRptAccessMode(rd);
|
||||
emit setTone(rt);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_toneDTCS_clicked()
|
||||
{
|
||||
rptAccessTxRx rm;
|
||||
rptrAccessData_t rd;
|
||||
quint16 dcode=0;
|
||||
|
||||
rm = ratrDD;
|
||||
emit setRptAccessMode(rm);
|
||||
rd.accessMode = ratrDD;
|
||||
emit setRptAccessMode(rd);
|
||||
|
||||
bool tinv = ui->rptDTCSInvertTx->isChecked();
|
||||
bool rinv = ui->rptDTCSInvertRx->isChecked();
|
||||
dcode = (quint16)ui->rptDTCSCombo->currentData().toUInt();
|
||||
emit setDTCS(dcode, tinv, rinv);
|
||||
// TODO: DTCS with subband
|
||||
}
|
||||
|
||||
void repeaterSetup::on_debugBtn_clicked()
|
||||
quint64 repeaterSetup::getFreqHzFromKHzString(QString khz)
|
||||
{
|
||||
// TODO: Move these four commands to wfview's startup command list (place at the end)
|
||||
//emit getTone();
|
||||
//emit getTSQL();
|
||||
//emit getDTCS();
|
||||
emit getRptAccessMode();
|
||||
// This function takes a string containing a number in KHz,
|
||||
// and creates an accurate quint64 in Hz.
|
||||
quint64 fhz = 0;
|
||||
bool ok = true;
|
||||
if(khz.isEmpty())
|
||||
{
|
||||
qWarning() << "KHz offset was empty!";
|
||||
return fhz;
|
||||
}
|
||||
if(khz.contains("."))
|
||||
{
|
||||
// "600.245" becomes "600"
|
||||
khz.chop(khz.indexOf("."));
|
||||
}
|
||||
fhz = 1E3 * khz.toUInt(&ok);
|
||||
if(!ok)
|
||||
{
|
||||
qWarning() << "Could not understand user KHz text";
|
||||
}
|
||||
return fhz;
|
||||
}
|
||||
|
||||
quint64 repeaterSetup::getFreqHzFromMHzString(QString MHz)
|
||||
{
|
||||
// This function takes a string containing a number in KHz,
|
||||
// and creates an accurate quint64 in Hz.
|
||||
quint64 fhz = 0;
|
||||
bool ok = true;
|
||||
if(MHz.isEmpty())
|
||||
{
|
||||
qWarning() << "MHz string was empty!";
|
||||
return fhz;
|
||||
}
|
||||
if(MHz.contains("."))
|
||||
{
|
||||
int decimalPtIndex = MHz.indexOf(".");
|
||||
// "29.623"
|
||||
// indexOf(".") = 2
|
||||
// length = 6
|
||||
// We want the right 4xx 3 characters.
|
||||
QString KHz = MHz.right(MHz.length() - decimalPtIndex - 1);
|
||||
MHz.chop(MHz.length() - decimalPtIndex);
|
||||
if(KHz.length() != 6)
|
||||
{
|
||||
QString zeros = QString("000000");
|
||||
zeros.chop(KHz.length());
|
||||
KHz.append(zeros);
|
||||
}
|
||||
//qInfo() << "KHz string: " << KHz;
|
||||
fhz = MHz.toUInt(&ok) * 1E6; if(!ok) goto handleError;
|
||||
fhz += KHz.toUInt(&ok) * 1; if(!ok) goto handleError;
|
||||
//qInfo() << "Fhz: " << fhz;
|
||||
} else {
|
||||
// Frequency was already MHz (unlikely but what can we do?)
|
||||
fhz = MHz.toUInt(&ok) * 1E6; if(!ok) goto handleError;
|
||||
}
|
||||
return fhz;
|
||||
|
||||
handleError:
|
||||
qWarning() << "Could not understand user MHz text " << MHz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void repeaterSetup::on_splitPlusButton_clicked()
|
||||
{
|
||||
quint64 hzOffset = getFreqHzFromKHzString(ui->splitOffsetEdit->text());
|
||||
quint64 txfreqhz;
|
||||
freqt f;
|
||||
QString txString;
|
||||
if(hzOffset)
|
||||
{
|
||||
txfreqhz = currentMainFrequency.Hz + hzOffset;
|
||||
f.Hz = txfreqhz;
|
||||
f.VFO = inactiveVFO;
|
||||
f.MHzDouble = f.Hz/1E6;
|
||||
txString = QString::number(f.Hz / double(1E6), 'f', 6);
|
||||
ui->splitTransmitFreqEdit->setText(txString);
|
||||
usedPlusSplit = true;
|
||||
emit setTransmitFrequency(f);
|
||||
emit setTransmitMode(modeTransmitVFO);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_splitMinusBtn_clicked()
|
||||
{
|
||||
quint64 hzOffset = getFreqHzFromKHzString(ui->splitOffsetEdit->text());
|
||||
quint64 txfreqhz;
|
||||
freqt f;
|
||||
QString txString;
|
||||
if(hzOffset)
|
||||
{
|
||||
txfreqhz = currentMainFrequency.Hz - hzOffset;
|
||||
f.Hz = txfreqhz;
|
||||
f.VFO = inactiveVFO;
|
||||
f.MHzDouble = f.Hz/1E6;
|
||||
txString = QString::number(f.Hz / double(1E6), 'f', 6);
|
||||
ui->splitTransmitFreqEdit->setText(txString);
|
||||
usedPlusSplit = false;
|
||||
emit setTransmitFrequency(f);
|
||||
emit setTransmitMode(modeTransmitVFO);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_splitTxFreqSetBtn_clicked()
|
||||
{
|
||||
quint64 fHz = getFreqHzFromMHzString(ui->splitTransmitFreqEdit->text());
|
||||
freqt f;
|
||||
if(fHz)
|
||||
{
|
||||
f.Hz = fHz;
|
||||
f.VFO = inactiveVFO;
|
||||
f.MHzDouble = f.Hz/1E6;
|
||||
emit setTransmitFrequency(f);
|
||||
emit setTransmitMode(modeTransmitVFO);
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_splitTransmitFreqEdit_returnPressed()
|
||||
{
|
||||
this->on_splitTxFreqSetBtn_clicked();
|
||||
ui->splitTransmitFreqEdit->clearFocus();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_selABtn_clicked()
|
||||
{
|
||||
vfo_t v = vfoA;
|
||||
emit selectVFO(v);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_selBBtn_clicked()
|
||||
{
|
||||
vfo_t v = vfoB;
|
||||
emit selectVFO(v);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_aEqBBtn_clicked()
|
||||
{
|
||||
emit equalizeVFOsAB();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_swapABBtn_clicked()
|
||||
{
|
||||
emit swapVFOs();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_selMainBtn_clicked()
|
||||
{
|
||||
vfo_t v = vfoMain;
|
||||
emit selectVFO(v);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_selSubBtn_clicked()
|
||||
{
|
||||
vfo_t v = vfoSub;
|
||||
emit selectVFO(v);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_mEqSBtn_clicked()
|
||||
{
|
||||
emit equalizeVFOsMS();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_swapMSBtn_clicked()
|
||||
{
|
||||
emit swapVFOs();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_setToneSubVFOBtn_clicked()
|
||||
{
|
||||
// Perhaps not needed
|
||||
// Set the secondary VFO to the selected tone
|
||||
// TODO: DTCS
|
||||
rptrTone_t rt;
|
||||
rt.tone = (quint16)ui->rptToneCombo->currentData().toUInt();
|
||||
rt.useSecondaryVFO = true;
|
||||
emit setTone(rt);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_setRptrSubVFOBtn_clicked()
|
||||
{
|
||||
// Perhaps not needed
|
||||
// Set the secondary VFO to the selected repeater mode
|
||||
rptrAccessData_t rd;
|
||||
rd.useSecondaryVFO = true;
|
||||
|
||||
if(ui->toneTone->isChecked())
|
||||
rd.accessMode=ratrTN;
|
||||
if(ui->toneNone->isChecked())
|
||||
rd.accessMode=ratrNN;
|
||||
if(ui->toneTSQL->isChecked())
|
||||
rd.accessMode=ratrTT;
|
||||
if(ui->toneDTCS->isChecked())
|
||||
rd.accessMode=ratrDD;
|
||||
|
||||
emit setRptAccessMode(rd);
|
||||
}
|
||||
|
||||
void repeaterSetup::on_rptrOffsetSetBtn_clicked()
|
||||
{
|
||||
freqt f;
|
||||
f.Hz = getFreqHzFromMHzString(ui->rptrOffsetEdit->text());
|
||||
f.MHzDouble = f.Hz/1E6;
|
||||
f.VFO=activeVFO;
|
||||
if(f.Hz != 0)
|
||||
{
|
||||
emit setRptDuplexOffset(f);
|
||||
}
|
||||
ui->rptrOffsetEdit->clearFocus();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_rptrOffsetEdit_returnPressed()
|
||||
{
|
||||
this->on_rptrOffsetSetBtn_clicked();
|
||||
}
|
||||
|
||||
void repeaterSetup::on_setSplitRptrToneChk_clicked(bool checked)
|
||||
{
|
||||
if(checked)
|
||||
{
|
||||
on_setRptrSubVFOBtn_clicked();
|
||||
on_setToneSubVFOBtn_clicked();
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSetup::on_quickSplitChk_clicked(bool checked)
|
||||
{
|
||||
emit setQuickSplit(checked);
|
||||
}
|
||||
|
|
|
@ -23,14 +23,29 @@ public:
|
|||
signals:
|
||||
void getDuplexMode();
|
||||
void setDuplexMode(duplexMode dm);
|
||||
void setTone(quint16 tone);
|
||||
void setTSQL(quint16 tsql);
|
||||
void setTone(rptrTone_t tone);
|
||||
void setTSQL(rptrTone_t tsql);
|
||||
void setDTCS(quint16 dcode, bool tinv, bool rinv);
|
||||
void getTone();
|
||||
void getTSQL();
|
||||
void getDTCS();
|
||||
void setRptAccessMode(rptAccessTxRx tmode);
|
||||
void setRptAccessMode(rptrAccessData_t rd);
|
||||
void getRptAccessMode();
|
||||
void setRptDuplexOffset(freqt f);
|
||||
void getRptDuplexOffset();
|
||||
// Split:
|
||||
void getSplitModeEnabled();
|
||||
void setQuickSplit(bool qsOn);
|
||||
void getTransmitFrequency();
|
||||
// Use the duplexMode to communicate split.
|
||||
// void setSplitModeEnabled(bool splitEnabled);
|
||||
void setTransmitFrequency(freqt transmitFreq);
|
||||
void setTransmitMode(mode_info m);
|
||||
// VFO:
|
||||
void selectVFO(vfo_t v); // A,B,M,S
|
||||
void equalizeVFOsAB();
|
||||
void equalizeVFOsMS();
|
||||
void swapVFOs();
|
||||
|
||||
public slots:
|
||||
void receiveDuplexMode(duplexMode dm);
|
||||
|
@ -38,29 +53,80 @@ public slots:
|
|||
void handleTone(quint16 tone);
|
||||
void handleTSQL(quint16 tsql);
|
||||
void handleDTCS(quint16 dcscode, bool tinv, bool rinv);
|
||||
// void handleSplitMode(bool splitEnabled);
|
||||
// void handleSplitFrequency(freqt transmitFreq);
|
||||
void handleUpdateCurrentMainFrequency(freqt mainfreq);
|
||||
void handleUpdateCurrentMainMode(mode_info m);
|
||||
void handleTransmitStatus(bool amTransmitting);
|
||||
void handleRptOffsetFrequency(freqt f);
|
||||
|
||||
private slots:
|
||||
void showEvent(QShowEvent *event);
|
||||
void on_rptSimplexBtn_clicked();
|
||||
void on_rptDupPlusBtn_clicked();
|
||||
void on_rptDupMinusBtn_clicked();
|
||||
void on_rptAutoBtn_clicked();
|
||||
void on_rptReadRigBtn_clicked();
|
||||
void on_rptToneCombo_activated(int index);
|
||||
void on_rptDTCSCombo_activated(int index);
|
||||
void on_debugBtn_clicked();
|
||||
void on_toneNone_clicked();
|
||||
void on_toneTone_clicked();
|
||||
void on_toneTSQL_clicked();
|
||||
void on_toneDTCS_clicked();
|
||||
void on_toneDTCS_clicked();
|
||||
void on_splitPlusButton_clicked();
|
||||
void on_splitMinusBtn_clicked();
|
||||
|
||||
void on_splitTxFreqSetBtn_clicked();
|
||||
|
||||
void on_selABtn_clicked();
|
||||
|
||||
void on_selBBtn_clicked();
|
||||
|
||||
void on_aEqBBtn_clicked();
|
||||
|
||||
void on_swapABBtn_clicked();
|
||||
|
||||
void on_selMainBtn_clicked();
|
||||
|
||||
void on_selSubBtn_clicked();
|
||||
|
||||
void on_mEqSBtn_clicked();
|
||||
|
||||
void on_swapMSBtn_clicked();
|
||||
|
||||
void on_setToneSubVFOBtn_clicked();
|
||||
|
||||
void on_setRptrSubVFOBtn_clicked();
|
||||
|
||||
void on_rptrOffsetSetBtn_clicked();
|
||||
|
||||
void on_splitOffBtn_clicked();
|
||||
|
||||
void on_splitEnableChk_clicked();
|
||||
|
||||
void on_rptrOffsetEdit_returnPressed();
|
||||
|
||||
void on_splitTransmitFreqEdit_returnPressed();
|
||||
|
||||
void on_setSplitRptrToneChk_clicked(bool checked);
|
||||
|
||||
void on_quickSplitChk_clicked(bool checked);
|
||||
|
||||
private:
|
||||
Ui::repeaterSetup *ui;
|
||||
|
||||
freqt currentMainFrequency;
|
||||
void populateTones();
|
||||
void populateDTCS();
|
||||
quint64 getFreqHzFromKHzString(QString khz);
|
||||
quint64 getFreqHzFromMHzString(QString MHz);
|
||||
|
||||
rigCapabilities rig;
|
||||
bool haveRig = false;
|
||||
duplexMode currentdm;
|
||||
mode_info currentModeMain;
|
||||
mode_info modeTransmitVFO;
|
||||
freqt currentOffset;
|
||||
bool usedPlusSplit = false;
|
||||
bool amTransmitting = false;
|
||||
};
|
||||
|
||||
#endif // REPEATERSETUP_H
|
||||
|
|
410
repeatersetup.ui
|
@ -6,62 +6,27 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>217</height>
|
||||
<width>1071</width>
|
||||
<height>231</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1071</width>
|
||||
<height>230</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>1071</width>
|
||||
<height>231</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Repeater Setup</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rptReadRigBtn">
|
||||
<property name="text">
|
||||
<string>Read Current Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="debugBtn">
|
||||
<property name="text">
|
||||
<string>Debug</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
|
@ -71,7 +36,13 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<widget class="QGroupBox" name="rptGrpbox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Repeater Duplex</string>
|
||||
</property>
|
||||
|
@ -116,15 +87,328 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QPushButton" name="rptrOffsetSetBtn">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Set the repeater offset for radios using Repeater modes. Only available on radios that have repeater modes. Radios using Split should instead use the provided Split Mode section with a custom Offset. </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Offset (MHz):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="rptrOffsetEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Rpt Offset (MHz)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="splitModeGrpbox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Split Mode</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="splitEnableChk">
|
||||
<property name="toolTip">
|
||||
<string>Turn on Split</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Split On</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">rptDuplexBtns</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="splitOffBtn">
|
||||
<property name="toolTip">
|
||||
<string>Turn off Split</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Split Off</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">rptDuplexBtns</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="quickSplitChk">
|
||||
<property name="text">
|
||||
<string>QuickSplit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="setSplitRptrToneChk">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Click here to automatically set the sub VFO (transmit VFO) tone. Only available on some radios. Other radios may take care of this for you.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Rpt Tone</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoTrackLiveBtn">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Click here to continually set the transmit VFO to match the receive VFO with the offset accounted for. </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>AutoTrack</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Offset (KHz):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="splitOffsetEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enter the desired split offset in KHz.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="splitPlusButton">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>55</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Set the transmit frequency to the receive frequency PLUS the offset. Sets the radio sub VFO and also populates the wfview text box (as a convenience). </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Split+</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="splitMinusBtn">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>55</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Set the transmit frequency to the receive frequency PLUS the offset. Sets the radio sub VFO and also populates the wfview text box (as a convenience). </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Split-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Tx Freq (MHz):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="splitTransmitFreqEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="splitTxFreqSetBtn">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>116</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Set the transmit frequency manually. Not needed if the Split+ or Split- button was used. </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>220</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>VFO</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="swapABBtn">
|
||||
<property name="toolTip">
|
||||
<string>Swap VFO A with VFO B. Some radios do not support this.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Swap AB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="selSubBtn">
|
||||
<property name="toolTip">
|
||||
<string>Select the Sub VFO</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sel Sub</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="selMainBtn">
|
||||
<property name="toolTip">
|
||||
<string>Select the Main VFO</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sel Main</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="selBBtn">
|
||||
<property name="toolTip">
|
||||
<string>Select VFO B</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sel B</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="selABtn">
|
||||
<property name="toolTip">
|
||||
<string>Select VFO A</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sel A</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="aEqBBtn">
|
||||
<property name="toolTip">
|
||||
<string>Set VFO B to VFO A</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>A=B</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="mEqSBtn">
|
||||
<property name="toolTip">
|
||||
<string>Set the SUB VFO to match the Main VFO</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>M=>S</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="swapMSBtn">
|
||||
<property name="toolTip">
|
||||
<string>Swap the Main VFO and Sub VFO</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Swap MS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Repeater Tone Type</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="warningFMLabel">
|
||||
<property name="text">
|
||||
<string>Only available in FM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="toneNone">
|
||||
<property name="text">
|
||||
|
@ -165,11 +449,27 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="setRptrSubVFOBtn">
|
||||
<property name="toolTip">
|
||||
<string>Set the Tone Mode for the Sub VFO. Not available on all radios.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Sub VFO</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Tone Selection</string>
|
||||
</property>
|
||||
|
@ -220,6 +520,16 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="setToneSubVFOBtn">
|
||||
<property name="toolTip">
|
||||
<string>Set the Sub VFO to the selected Tone. Not available on all radios and not available for DTCS.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Sub VFO</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -96,11 +96,11 @@ static void speex_free(void* ptr) { free(ptr); }
|
|||
#define UINT32_MAX 4294967295U
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSE
|
||||
#if defined(USE_SSE) && !defined(__aarch64__)
|
||||
#include "resample_sse.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_NEON
|
||||
#if defined(USE_NEON) || defined(__aarch64__)
|
||||
#include "resample_neon.h"
|
||||
#endif
|
||||
|
||||
|
@ -294,7 +294,7 @@ static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef* win
|
|||
else if (fabs(x) > .5 * N)
|
||||
return 0;
|
||||
/*FIXME: Can it really be any slower than this? */
|
||||
return cutoff * sin(M_PI * xx) / (M_PI * xx) * compute_func(fabs(2. * x / N), window_func);
|
||||
return (spx_word16_t)(cutoff * (float)(sin(M_PI * xx) / (M_PI * xx) * compute_func((float)fabs(2. * x / N), window_func)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -324,7 +324,7 @@ static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
|
|||
/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
|
||||
interp[3] = -0.33333f * frac + 0.5f * frac * frac - 0.16667f * frac * frac * frac;
|
||||
/* Just to make sure we don't have rounding problems */
|
||||
interp[2] = 1. - interp[0] - interp[1] - interp[3];
|
||||
interp[2] = (spx_word16_t) (1. - interp[0] - interp[1] - interp[3]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -419,7 +419,7 @@ static int resampler_basic_direct_double(SpeexResamplerState* st, spx_uint32_t c
|
|||
sum = inner_product_double(sinct, iptr, N);
|
||||
#endif
|
||||
|
||||
out[out_stride * out_sample++] = PSHR32(sum, 15);
|
||||
out[out_stride * out_sample++] = (spx_word16_t)PSHR32(sum, 15);
|
||||
last_sample += int_advance;
|
||||
samp_frac_num += frac_advance;
|
||||
if (samp_frac_num >= den_rate)
|
||||
|
@ -539,7 +539,7 @@ static int resampler_basic_interpolate_double(SpeexResamplerState* st, spx_uint3
|
|||
sum = MULT16_32_Q15(interp[0], accum[0]) + MULT16_32_Q15(interp[1], accum[1]) + MULT16_32_Q15(interp[2], accum[2]) + MULT16_32_Q15(interp[3], accum[3]);
|
||||
#else
|
||||
cubic_coef(frac, interp);
|
||||
sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
|
||||
sum = (spx_word16_t)interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
|
||||
#endif
|
||||
|
||||
out[out_stride * out_sample++] = PSHR32(sum, 15);
|
||||
|
@ -673,7 +673,7 @@ static int update_filter(SpeexResamplerState* st)
|
|||
for (i = 0; i < st->den_rate; i++)
|
||||
{
|
||||
spx_int32_t j;
|
||||
for (j = 0; j < st->filt_len; j++)
|
||||
for (j = 0; j < (spx_int32_t)st->filt_len; j++)
|
||||
{
|
||||
st->sinc_table[i * st->filt_len + j] = sinc(st->cutoff, ((j - (spx_int32_t)st->filt_len / 2 + 1) - ((float)i) / st->den_rate), st->filt_len, quality_map[st->quality].window_func);
|
||||
}
|
||||
|
@ -710,7 +710,7 @@ static int update_filter(SpeexResamplerState* st)
|
|||
/* Adding buffer_size to filt_len won't overflow here because filt_len
|
||||
could be multiplied by sizeof(spx_word16_t) above. */
|
||||
min_alloc_size = st->filt_len - 1 + st->buffer_size;
|
||||
if (min_alloc_size > st->mem_alloc_size)
|
||||
if (min_alloc_size > st->mem_alloc_size && st->nb_channels>0)
|
||||
{
|
||||
spx_word16_t* mem;
|
||||
if (INT_MAX / sizeof(spx_word16_t) / st->nb_channels < min_alloc_size)
|
||||
|
@ -934,7 +934,7 @@ EXPORT int speex_resampler_process_int(SpeexResamplerState* st, spx_uint32_t cha
|
|||
EXPORT int speex_resampler_process_float(SpeexResamplerState* st, spx_uint32_t channel_index, const float* in, spx_uint32_t* in_len, float* out, spx_uint32_t* out_len)
|
||||
#endif
|
||||
{
|
||||
int j;
|
||||
spx_uint32_t j;
|
||||
spx_uint32_t ilen = *in_len;
|
||||
spx_uint32_t olen = *out_len;
|
||||
spx_word16_t* x = st->mem + channel_index * st->mem_alloc_size;
|
||||
|
@ -976,7 +976,7 @@ EXPORT int speex_resampler_process_float(SpeexResamplerState* st, spx_uint32_t c
|
|||
EXPORT int speex_resampler_process_int(SpeexResamplerState* st, spx_uint32_t channel_index, const spx_int16_t* in, spx_uint32_t* in_len, spx_int16_t* out, spx_uint32_t* out_len)
|
||||
#endif
|
||||
{
|
||||
int j;
|
||||
spx_uint32_t j;
|
||||
const int istride_save = st->in_stride;
|
||||
const int ostride_save = st->out_stride;
|
||||
spx_uint32_t ilen = *in_len;
|
||||
|
@ -1246,4 +1246,4 @@ EXPORT const char* speex_resampler_strerror(int err)
|
|||
default:
|
||||
return "Unknown error. Bad error code or strange version mismatch.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#define OVERRIDE_INNER_PRODUCT_SINGLE
|
||||
static inline float inner_product_single(const float* a, const float* b, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
float ret;
|
||||
__m128 sum = _mm_setzero_ps();
|
||||
for (i = 0; i < len; i += 8)
|
||||
|
@ -55,7 +55,7 @@ static inline float inner_product_single(const float* a, const float* b, unsigne
|
|||
|
||||
#define OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
|
||||
static inline float interpolate_product_single(const float* a, const float* b, unsigned int len, const spx_uint32_t oversample, float* frac) {
|
||||
int i;
|
||||
unsigned int i;
|
||||
float ret;
|
||||
__m128 sum = _mm_setzero_ps();
|
||||
__m128 f = _mm_loadu_ps(frac);
|
||||
|
@ -71,13 +71,13 @@ static inline float interpolate_product_single(const float* a, const float* b, u
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_SSE2
|
||||
#if defined(USE_SSE2) && !defined(__aarch64__)
|
||||
#include <emmintrin.h>
|
||||
#define OVERRIDE_INNER_PRODUCT_DOUBLE
|
||||
|
||||
static inline double inner_product_double(const float* a, const float* b, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
double ret;
|
||||
__m128d sum = _mm_setzero_pd();
|
||||
__m128 t;
|
||||
|
@ -98,7 +98,7 @@ static inline double inner_product_double(const float* a, const float* b, unsign
|
|||
|
||||
#define OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
|
||||
static inline double interpolate_product_double(const float* a, const float* b, unsigned int len, const spx_uint32_t oversample, float* frac) {
|
||||
int i;
|
||||
unsigned int i;
|
||||
double ret;
|
||||
__m128d sum;
|
||||
__m128d sum1 = _mm_setzero_pd();
|
||||
|
@ -125,4 +125,4 @@ static inline double interpolate_product_double(const float* a, const float* b,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
Po Szerokość: | Wysokość: | Rozmiar: 321 KiB |
|
@ -1,10 +1,11 @@
|
|||
#!/bin/bash
|
||||
echo "This script copies the following items into your system:"
|
||||
echo ""
|
||||
echo "icon: wfview.png to /usr/share/pixmaps/"
|
||||
echo "icon: unix_icons/wfview.png to /usr/share/icons/hicolor/256x256/apps/"
|
||||
echo "wfview application to /usr/local/bin/"
|
||||
echo "wfview.desktop to /usr/share/applications/"
|
||||
echo "qdarkstyle stylesheet to /usr/share/wfview/stylesheets"
|
||||
echo "org.wfview.wfview.metainfo.xml metadata file to /usr/share/metainfo/"
|
||||
echo "qdarkstyle stylesheet to /usr/share/wfview/stylesheets/"
|
||||
|
||||
echo ""
|
||||
echo "This script MUST be run from the build directory. Do not run it from the source directory!"
|
||||
|
@ -30,7 +31,8 @@ echo ""
|
|||
|
||||
cp wfview /usr/local/bin/wfview
|
||||
cp wfview.desktop /usr/share/applications/
|
||||
cp wfview.png /usr/share/pixmaps/
|
||||
cp unix_icons/wfview.png /usr/share/icons/hicolor/256x256/apps/
|
||||
cp org.wfview.wfview.metainfo.xml /usr/share/metainfo/
|
||||
mkdir -p /usr/share/wfview/stylesheets
|
||||
cp -r qdarkstyle /usr/share/wfview/stylesheets/
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>org.wfview.wfview</id>
|
||||
<launchable type="desktop-id">wfview.desktop</launchable>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0-or-later</project_license>
|
||||
<name>wfview</name>
|
||||
<developer_name>Elliott H. Liggett</developer_name>
|
||||
<summary>Open Source interface for Icom transceivers</summary>
|
||||
<description>
|
||||
<p>
|
||||
wfview is a program developed by amateur radio enthusiasts to control modern Icom ham radios. It provides the user with controls
|
||||
that may be comfortably operated from a keyboard, mouse, or touch screen interface. wfview is free and open source software.
|
||||
</p>
|
||||
<p>
|
||||
wfview has been developed with an eye towards compatibility. Even though our target platform consists of modern-era transceivers,
|
||||
wfview’s command dictionary is focused on commands with the most compatibility. Many of Icom’s transceivers from the last 20 years
|
||||
will work to some degree with wfview, and we are always adding more.
|
||||
</p>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image type="source">https://wfview.org/wp-content/uploads/2021/11/7300-remote-screenshot.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">https://wfview.org</url>
|
||||
<url type="bugtracker">https://gitlab.com/eliggett/wfview/-/issues</url>
|
||||
<content_rating type="oars-1.1"/>
|
||||
</component>
|
Po Szerokość: | Wysokość: | Rozmiar: 113 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 106 KiB |
|
@ -1,5 +1,16 @@
|
|||
<RCC>
|
||||
<qresource prefix="resources">
|
||||
<file>wfview.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/resources">
|
||||
<file>wfview.png</file>
|
||||
<file>shuttlexpress.png</file>
|
||||
<file>shuttlepro.png</file>
|
||||
<file>rc28.png</file>
|
||||
<file>ecoder.png</file>
|
||||
<file>quickkeys.png</file>
|
||||
<file>xbox.png</file>
|
||||
<file>streamdeck.png</file>
|
||||
<file>streamdeckmini.png</file>
|
||||
<file>streamdeckxl.png</file>
|
||||
<file>streamdeckpedal.png</file>
|
||||
<file>streamdeckplus.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
Po Szerokość: | Wysokość: | Rozmiar: 185 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 428 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 179 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 331 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 396 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 217 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 412 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 53 KiB |
|
@ -18,5 +18,7 @@
|
|||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.usb</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
Po Szerokość: | Wysokość: | Rozmiar: 240 KiB |
1215
rigcommander.cpp
123
rigcommander.h
|
@ -5,7 +5,7 @@
|
|||
#include <QMutexLocker>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
#include "wfviewtypes.h"
|
||||
#include "commhandler.h"
|
||||
#include "pttyhandler.h"
|
||||
#include "udphandler.h"
|
||||
|
@ -23,48 +23,6 @@
|
|||
// note: using a define because switch case doesn't even work with const unsigned char. Surprised me.
|
||||
#define compCivAddr 0xE1
|
||||
|
||||
enum meterKind {
|
||||
meterNone=0,
|
||||
meterS,
|
||||
meterCenter,
|
||||
meterSWR,
|
||||
meterPower,
|
||||
meterALC,
|
||||
meterComp,
|
||||
meterVoltage,
|
||||
meterCurrent,
|
||||
meterRxdB,
|
||||
meterTxMod,
|
||||
meterRxAudio,
|
||||
meterAudio,
|
||||
meterLatency
|
||||
};
|
||||
|
||||
enum spectrumMode {
|
||||
spectModeCenter=0x00,
|
||||
spectModeFixed=0x01,
|
||||
spectModeScrollC=0x02,
|
||||
spectModeScrollF=0x03,
|
||||
spectModeUnknown=0xff
|
||||
};
|
||||
|
||||
struct freqt {
|
||||
quint64 Hz;
|
||||
double MHzDouble;
|
||||
};
|
||||
|
||||
struct datekind {
|
||||
uint16_t year;
|
||||
unsigned char month;
|
||||
unsigned char day;
|
||||
};
|
||||
|
||||
struct timekind {
|
||||
unsigned char hours;
|
||||
unsigned char minutes;
|
||||
bool isMinus;
|
||||
};
|
||||
|
||||
class rigCommander : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -112,21 +70,31 @@ public slots:
|
|||
|
||||
// Frequency, Mode, BSR:
|
||||
void setFrequency(unsigned char vfo, freqt freq);
|
||||
void getFrequency(unsigned char vfo);
|
||||
void getFrequency();
|
||||
void selectVFO(vfo_t vfo);
|
||||
void equalizeVFOsAB();
|
||||
void equalizeVFOsMS();
|
||||
void exchangeVFOs();
|
||||
void setMode(unsigned char mode, unsigned char modeFilter);
|
||||
void setMode(mode_info);
|
||||
void getMode();
|
||||
void setDataMode(bool dataOn, unsigned char filter);
|
||||
void getDataMode();
|
||||
void getSplit();
|
||||
void setSplit(bool splitEnabled);
|
||||
void getBandStackReg(char band, char regCode);
|
||||
void getRitEnabled();
|
||||
void getRitValue();
|
||||
void setRitValue(int ritValue);
|
||||
void setRitEnable(bool ritEnabled);
|
||||
void setPassband(quint16 pass);
|
||||
|
||||
// PTT, ATU, ATT, Antenna, and Preamp:
|
||||
void getPTT();
|
||||
void setPTT(bool pttOn);
|
||||
void sendCW(QString textToSend);
|
||||
void sendStopCW();
|
||||
void startATU();
|
||||
void setATU(bool enabled);
|
||||
void getATUStatus();
|
||||
|
@ -136,16 +104,16 @@ public slots:
|
|||
void setAttenuator(unsigned char att);
|
||||
void setPreamp(unsigned char pre);
|
||||
void setAntenna(unsigned char ant, bool rx);
|
||||
void setNb(bool enabled);
|
||||
void getNb();
|
||||
void setNr(bool enabled);
|
||||
void getNr();
|
||||
void setNB(bool enabled);
|
||||
void getNB();
|
||||
void setNR(bool enabled);
|
||||
void getNR();
|
||||
void setAutoNotch(bool enabled);
|
||||
void getAutoNotch();
|
||||
void setToneEnabled(bool enabled);
|
||||
void getToneEnabled();
|
||||
void setToneSql(bool enabled);
|
||||
void getToneSql();
|
||||
void getToneSqlEnabled();
|
||||
void setCompressor(bool enabled);
|
||||
void getCompressor();
|
||||
void setMonitor(bool enabled);
|
||||
|
@ -154,21 +122,40 @@ public slots:
|
|||
void getVox();
|
||||
void setBreakIn(unsigned char type);
|
||||
void getBreakIn();
|
||||
void setKeySpeed(unsigned char wpm);
|
||||
void getKeySpeed();
|
||||
void setManualNotch(bool enabled);
|
||||
void getManualNotch();
|
||||
|
||||
void getPassband();
|
||||
void getNBLevel();
|
||||
void getNRLevel(); void getCwPitch();
|
||||
void setCwPitch(unsigned char pitch);
|
||||
void getDashRatio();
|
||||
void setDashRatio(unsigned char ratio);
|
||||
void getPskTone();
|
||||
void setPskTone(unsigned char tone);
|
||||
void getRttyMark();
|
||||
void setRttyMark(unsigned char mark);
|
||||
|
||||
// Repeater:
|
||||
void setDuplexMode(duplexMode dm);
|
||||
void getDuplexMode();
|
||||
void setQuickSplit(bool qsOn);
|
||||
void getTransmitFrequency();
|
||||
void setTone(quint16 tone);
|
||||
void setTSQL(quint16 tsql);
|
||||
void setTone(rptrTone_t t);
|
||||
void setTSQL(rptrTone_t t);
|
||||
void setTone(quint16 t);
|
||||
void setTSQL(quint16 t);
|
||||
void getTSQL();
|
||||
void getTone();
|
||||
void setDTCS(quint16 dcscode, bool tinv, bool rinv);
|
||||
void getDTCS();
|
||||
void setRptAccessMode(rptAccessTxRx ratr);
|
||||
void setRptAccessMode(rptrAccessData_t ratr);
|
||||
void getRptAccessMode();
|
||||
void setRptDuplexOffset(freqt f);
|
||||
void getRptDuplexOffset();
|
||||
|
||||
// Get Levels:
|
||||
void getLevels(); // all supported levels
|
||||
|
@ -181,7 +168,7 @@ public slots:
|
|||
void getTxLevel();
|
||||
void getMicGain();
|
||||
void getCompLevel();
|
||||
void getMonitorLevel();
|
||||
void getMonitorGain();
|
||||
void getVoxGain();
|
||||
void getAntiVoxGain();
|
||||
void getUSBGain();
|
||||
|
@ -207,13 +194,15 @@ public slots:
|
|||
void setACCGain(unsigned char gain);
|
||||
void setACCGain(unsigned char gain, unsigned char ab);
|
||||
void setCompLevel(unsigned char compLevel);
|
||||
void setMonitorLevel(unsigned char monitorLevel);
|
||||
void setMonitorGain(unsigned char monitorLevel);
|
||||
void setVoxGain(unsigned char gain);
|
||||
void setAntiVoxGain(unsigned char gain);
|
||||
void setModInput(rigInput input, bool dataOn);
|
||||
void setModInputLevel(rigInput input, unsigned char level);
|
||||
void setAfMute(bool muteOn);
|
||||
void setDialLock(bool lockOn);
|
||||
void setNBLevel(unsigned char level);
|
||||
void setNRLevel(unsigned char level);
|
||||
|
||||
// NB, NR, IP+:
|
||||
void setIPP(bool enabled);
|
||||
|
@ -266,7 +255,7 @@ public slots:
|
|||
// UDP:
|
||||
void handleNewData(const QByteArray& data);
|
||||
void receiveAudioData(const audioPacket& data);
|
||||
void handleSerialPortError(const QString port, const QString errorText);
|
||||
void handlePortError(errorType err);
|
||||
void changeLatency(const quint16 value);
|
||||
void dataFromServer(QByteArray data);
|
||||
void receiveBaudRate(quint32 baudrate);
|
||||
|
@ -288,7 +277,7 @@ public slots:
|
|||
signals:
|
||||
// Communication:
|
||||
void commReady();
|
||||
void haveSerialPortError(const QString port, const QString errorText);
|
||||
void havePortError(errorType err);
|
||||
void haveStatusUpdate(const networkStatus status);
|
||||
void haveNetworkAudioLevels(const networkAudioLevels l);
|
||||
void dataForComm(const QByteArray &outData);
|
||||
|
@ -309,6 +298,7 @@ signals:
|
|||
void haveSpectrumMode(spectrumMode spectmode);
|
||||
void haveScopeEdge(char edge);
|
||||
void haveSpectrumRefLevel(int level);
|
||||
void haveScopeOutOfRange(bool outOfRange);
|
||||
|
||||
// Rig ID:
|
||||
void haveRigID(rigCapabilities rigCaps);
|
||||
|
@ -321,6 +311,10 @@ signals:
|
|||
void haveBandStackReg(freqt f, char mode, char filter, bool dataOn);
|
||||
void haveRitEnabled(bool ritEnabled);
|
||||
void haveRitFrequency(int ritHz);
|
||||
void havePassband(quint16 pass);
|
||||
void haveCwPitch(unsigned char pitch);
|
||||
void havePskTone(unsigned char tone);
|
||||
void haveRttyMark(unsigned char mark);
|
||||
|
||||
// Repeater:
|
||||
void haveDuplexMode(duplexMode);
|
||||
|
@ -328,6 +322,7 @@ signals:
|
|||
void haveTone(quint16 tone);
|
||||
void haveTSQL(quint16 tsql);
|
||||
void haveDTCS(quint16 dcscode, bool tinv, bool rinv);
|
||||
void haveRptOffsetFrequency(freqt f);
|
||||
|
||||
// Levels:
|
||||
void haveRfGain(unsigned char level);
|
||||
|
@ -339,9 +334,16 @@ signals:
|
|||
void haveTxPower(unsigned char level);
|
||||
void haveMicGain(unsigned char level);
|
||||
void haveCompLevel(unsigned char level);
|
||||
void haveMonitorLevel(unsigned char level);
|
||||
void haveMonitorGain(unsigned char level);
|
||||
void haveVoxGain(unsigned char gain);
|
||||
void haveAntiVoxGain(unsigned char gain);
|
||||
void haveNBLevel(unsigned char level);
|
||||
void haveNRLevel(unsigned char level);
|
||||
void haveVox(bool en);
|
||||
void haveMonitor(bool en);
|
||||
void haveComp(bool en);
|
||||
void haveNB(bool en);
|
||||
void haveNR(bool en);
|
||||
|
||||
// Modulation source and gain:
|
||||
void haveModInput(rigInput input, bool isData);
|
||||
|
@ -371,6 +373,12 @@ signals:
|
|||
void havePreamp(unsigned char pre);
|
||||
void haveAntenna(unsigned char ant,bool rx);
|
||||
|
||||
// CW:
|
||||
void haveKeySpeed(unsigned char wpm);
|
||||
void haveCWBreakMode(unsigned char bmode);
|
||||
void haveDashRatio(unsigned char ratio);
|
||||
|
||||
|
||||
// Rig State
|
||||
void stateInfo(rigstate* state);
|
||||
|
||||
|
@ -385,13 +393,15 @@ private:
|
|||
void setup();
|
||||
QByteArray stripData(const QByteArray &data, unsigned char cutPosition);
|
||||
void parseData(QByteArray data); // new data come here
|
||||
void parseCommand();
|
||||
void parseCommand(); // Entry point for complete commands
|
||||
unsigned char bcdHexToUChar(unsigned char in);
|
||||
unsigned char bcdHexToUChar(unsigned char hundreds, unsigned char tensunits);
|
||||
unsigned int bcdHexToUInt(unsigned char hundreds, unsigned char tensunits);
|
||||
QByteArray bcdEncodeInt(unsigned int);
|
||||
void parseFrequency();
|
||||
freqt parseFrequency(QByteArray data, unsigned char lastPosition); // supply index where Mhz is found
|
||||
freqt parseFrequencyRptOffset(QByteArray data);
|
||||
QByteArray makeFreqPayloadRptOffset(freqt freq);
|
||||
QByteArray makeFreqPayload(double frequency);
|
||||
QByteArray makeFreqPayload(freqt freq);
|
||||
QByteArray encodeTone(quint16 tone, bool tinv, bool rinv);
|
||||
|
@ -463,6 +473,7 @@ private:
|
|||
quint16 spectAmpMax;
|
||||
quint16 spectLenMax;
|
||||
spectrumMode oldScopeMode;
|
||||
bool wasOutOfRange = false;
|
||||
|
||||
bool usingNativeLAN; // indicates using OEM LAN connection (705,7610,9700,7850)
|
||||
bool lookingForRig;
|
||||
|
|
1832
rigctld.cpp
55
rigctld.h
|
@ -337,12 +337,12 @@ signals:
|
|||
void onStarted();
|
||||
void onStopped();
|
||||
void sendData(QString data);
|
||||
void setFrequency(unsigned char vfo, freqt freq);
|
||||
void setFrequency(quint8 vfo, freqt freq);
|
||||
void setPTT(bool state);
|
||||
void setMode(unsigned char mode, unsigned char modeFilter);
|
||||
void setDataMode(bool dataOn, unsigned char modeFilter);
|
||||
void setVFO(unsigned char vfo);
|
||||
void setSplit(unsigned char split);
|
||||
void setMode(quint8 mode, quint8 modeFilter);
|
||||
void setDataMode(bool dataOn, quint8 modeFilter);
|
||||
void setVFO(quint8 vfo);
|
||||
void setSplit(quint8 split);
|
||||
void setDuplexMode(duplexMode dm);
|
||||
void stateUpdated();
|
||||
// Power
|
||||
|
@ -350,19 +350,19 @@ signals:
|
|||
void sendPowerOff();
|
||||
|
||||
// Att/preamp
|
||||
void setAttenuator(unsigned char att);
|
||||
void setPreamp(unsigned char pre);
|
||||
void setAttenuator(quint8 att);
|
||||
void setPreamp(quint8 pre);
|
||||
|
||||
//Level set
|
||||
void setRfGain(unsigned char level);
|
||||
void setAfGain(unsigned char level);
|
||||
void setSql(unsigned char level);
|
||||
void setMicGain(unsigned char);
|
||||
void setCompLevel(unsigned char);
|
||||
void setTxPower(unsigned char);
|
||||
void setMonitorLevel(unsigned char);
|
||||
void setVoxGain(unsigned char);
|
||||
void setAntiVoxGain(unsigned char);
|
||||
void setRfGain(quint8 level);
|
||||
void setAfGain(quint8 level);
|
||||
void setSql(quint8 level);
|
||||
void setMicGain(quint8);
|
||||
void setCompLevel(quint8);
|
||||
void setTxPower(quint8);
|
||||
void setMonitorGain(quint8);
|
||||
void setVoxGain(quint8);
|
||||
void setAntiVoxGain(quint8);
|
||||
void setSpectrumRefLevel(int);
|
||||
|
||||
|
||||
|
@ -403,15 +403,20 @@ private:
|
|||
rigstate* rigState = Q_NULLPTR;
|
||||
rigCtlD* parent;
|
||||
bool chkVfoEecuted=false;
|
||||
QString getMode(unsigned char mode, bool datamode);
|
||||
unsigned char getMode(QString modeString);
|
||||
QString getFilter(unsigned char mode, unsigned char filter);
|
||||
QString generateFreqRange(bandType band);
|
||||
unsigned char getAntennas();
|
||||
quint64 getRadioModes();
|
||||
QString getAntName(unsigned char ant);
|
||||
unsigned char antFromName(QString name);
|
||||
int getCalibratedValue(unsigned char meter,cal_table_t cal);
|
||||
unsigned long crcTable[256];
|
||||
unsigned long doCrc(unsigned char* p, size_t n);
|
||||
void genCrc(unsigned long crcTable[]);
|
||||
QString getMode(quint8 mode, bool datamode);
|
||||
quint8 getMode(QString modeString);
|
||||
QString getFilter(quint8 mode, quint8 filter);
|
||||
quint8 getAntennas();
|
||||
quint64 getRadioModes(QString mode = "");
|
||||
QString getAntName(quint8 ant);
|
||||
quint8 antFromName(QString name);
|
||||
quint8 vfoFromName(QString vfo);
|
||||
QString getVfoName(quint8 vfo);
|
||||
|
||||
int getCalibratedValue(quint8 meter,cal_table_t cal);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -7,84 +7,7 @@ model_kind determineRadioModel(unsigned char rigID)
|
|||
{
|
||||
|
||||
model_kind rig;
|
||||
|
||||
switch(rigID)
|
||||
{
|
||||
case model7100:
|
||||
rig = model7100;
|
||||
break;
|
||||
case model7200:
|
||||
rig = model7200;
|
||||
break;
|
||||
case model7300:
|
||||
rig = model7300;
|
||||
break;
|
||||
case modelR8600:
|
||||
rig = modelR8600;
|
||||
break;
|
||||
case model7000:
|
||||
rig = model7000;
|
||||
break;
|
||||
case model7410:
|
||||
rig = model7410;
|
||||
break;
|
||||
case model7600:
|
||||
rig = model7600;
|
||||
break;
|
||||
case model7610:
|
||||
rig = model7610;
|
||||
break;
|
||||
case model7700:
|
||||
rig = model7700;
|
||||
break;
|
||||
case model7800:
|
||||
rig = model7800;
|
||||
break;
|
||||
case model7850:
|
||||
rig = model7850;
|
||||
break;
|
||||
case model9700:
|
||||
rig = model9700;
|
||||
break;
|
||||
case model706:
|
||||
rig = model706;
|
||||
break;
|
||||
case model705:
|
||||
rig = model705;
|
||||
break;
|
||||
case model718:
|
||||
rig = model718;
|
||||
break;
|
||||
case model736:
|
||||
rig = model736;
|
||||
break;
|
||||
case model746:
|
||||
rig = model746;
|
||||
break;
|
||||
case model756pro:
|
||||
rig = model756pro;
|
||||
break;
|
||||
case model756proii:
|
||||
rig = model756proii;
|
||||
break;
|
||||
case model756proiii:
|
||||
rig = model756proiii;
|
||||
break;
|
||||
case model910h:
|
||||
rig = model910h;
|
||||
break;
|
||||
case model9100:
|
||||
rig = model9100;
|
||||
break;
|
||||
default:
|
||||
rig = modelUnknown;
|
||||
break;
|
||||
}
|
||||
rig = (model_kind)rigID;
|
||||
|
||||
return rig;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
// 7850 and 7851 have the same commands and are essentially identical
|
||||
|
||||
|
||||
enum model_kind {
|
||||
model7100 = 0x88,
|
||||
model7200 = 0x76,
|
||||
|
@ -27,14 +28,19 @@ enum model_kind {
|
|||
model7410 = 0x80,
|
||||
model7850 = 0x8E,
|
||||
model9700 = 0xA2,
|
||||
model703 = 0x68,
|
||||
model705 = 0xA4,
|
||||
model706 = 0x58,
|
||||
model718 = 0x5E,
|
||||
model736 = 0x40,
|
||||
model737 = 0x3C,
|
||||
model738 = 0x44,
|
||||
model746 = 0x56,
|
||||
model756 = 0x50,
|
||||
model756pro = 0x5C,
|
||||
model756proii = 0x64,
|
||||
model756proiii = 0x6E,
|
||||
model905 = 0xAC,
|
||||
model910h = 0x60,
|
||||
model9100 = 0x7C,
|
||||
modelUnknown = 0xFF
|
||||
|
@ -50,7 +56,12 @@ enum rigInput{ inputMic=0,
|
|||
inputUnknown=0xff
|
||||
};
|
||||
|
||||
enum bandType { band23cm=0,
|
||||
enum availableBands {
|
||||
band3cm = 0,
|
||||
band6cm,
|
||||
band9cm,
|
||||
band13cm,
|
||||
band23cm,
|
||||
band70cm,
|
||||
band2m,
|
||||
bandAir,
|
||||
|
@ -82,7 +93,10 @@ enum centerSpansType {
|
|||
cs250k = 6,
|
||||
cs500k = 7,
|
||||
cs1M = 8,
|
||||
cs2p5M = 9
|
||||
cs2p5M = 9,
|
||||
cs5M = 10,
|
||||
cs10M = 11,
|
||||
cs25M = 12,
|
||||
};
|
||||
|
||||
struct centerSpanData {
|
||||
|
@ -90,6 +104,18 @@ struct centerSpanData {
|
|||
QString name;
|
||||
};
|
||||
|
||||
struct bandType {
|
||||
bandType(availableBands band, quint64 lowFreq, quint64 highFreq, mode_kind defaultMode) :
|
||||
band(band), lowFreq(lowFreq), highFreq(highFreq), defaultMode(defaultMode) {}
|
||||
|
||||
bandType() {}
|
||||
|
||||
availableBands band;
|
||||
quint64 lowFreq;
|
||||
quint64 highFreq;
|
||||
mode_kind defaultMode;
|
||||
};
|
||||
|
||||
model_kind determineRadioModel(unsigned char rigID);
|
||||
|
||||
struct rigCapabilities {
|
||||
|
@ -106,17 +132,21 @@ struct rigCapabilities {
|
|||
|
||||
QVector<rigInput> inputs;
|
||||
|
||||
bool hasSpectrum;
|
||||
bool hasSpectrum=true;
|
||||
quint8 spectSeqMax;
|
||||
quint16 spectAmpMax;
|
||||
quint16 spectLenMax;
|
||||
|
||||
bool hasNB = false;
|
||||
QByteArray nbCommand;
|
||||
|
||||
bool hasDD;
|
||||
bool hasDV;
|
||||
bool hasATU;
|
||||
|
||||
bool hasCTCSS;
|
||||
bool hasDTCS;
|
||||
bool hasRepeaterModes = false;
|
||||
|
||||
bool hasTransmit;
|
||||
bool hasPTTCommand;
|
||||
|
@ -130,12 +160,20 @@ struct rigCapabilities {
|
|||
|
||||
bool hasRXAntenna;
|
||||
|
||||
bool hasSpecifyMainSubCmd = false; // 0x29
|
||||
bool hasVFOMS = false;
|
||||
bool hasVFOAB = true; // 0x07 [00||01]
|
||||
|
||||
bool hasAdvancedRptrToneCmds = false;
|
||||
bool hasQuickSplitCommand = false;
|
||||
QByteArray quickSplitCommand;
|
||||
|
||||
std::vector <unsigned char> attenuators;
|
||||
std::vector <unsigned char> preamps;
|
||||
std::vector <unsigned char> antennas;
|
||||
std::vector <centerSpanData> scopeCenterSpans;
|
||||
std::vector <bandType> bands;
|
||||
unsigned char bsr[20] = {0};
|
||||
unsigned char bsr[24] = {0};
|
||||
|
||||
std::vector <mode_info> modes;
|
||||
|
||||
|
|
59
rigstate.h
|
@ -12,12 +12,13 @@
|
|||
#include "rigidentities.h"
|
||||
|
||||
// Meters at the end as they are ALWAYS updated from the rig!
|
||||
enum stateTypes { VFOAFREQ, VFOBFREQ, CURRENTVFO, PTT, MODE, FILTER, DUPLEX, DATAMODE, ANTENNA, RXANTENNA, CTCSS, TSQL, DTCS, CSQL,
|
||||
PREAMP, AGC, ATTENUATOR, MODINPUT, AFGAIN, RFGAIN, SQUELCH, RFPOWER, MICGAIN, COMPLEVEL, MONITORLEVEL, VOXGAIN, ANTIVOXGAIN,
|
||||
enum stateTypes { VFOAFREQ, VFOBFREQ, CURRENTVFO, PTT, MODE, FILTER, PASSBAND, DUPLEX, DATAMODE, ANTENNA, RXANTENNA, CTCSS, TSQL, DTCS, CSQL,
|
||||
PREAMP, AGC, ATTENUATOR, MODINPUT, AFGAIN, RFGAIN, SQUELCH, RFPOWER, MICGAIN, COMPLEVEL, MONITORLEVEL, BAL, KEYSPD,
|
||||
VOXGAIN, ANTIVOXGAIN, CWPITCH, NOTCHF, IF, PBTIN, PBTOUT, APF, NR, NB, NBDEPTH, NBWIDTH, RIGINPUT, POWERONOFF, RITVALUE,
|
||||
FAGCFUNC, NBFUNC, COMPFUNC, VOXFUNC, TONEFUNC, TSQLFUNC, SBKINFUNC, FBKINFUNC, ANFFUNC, NRFUNC, AIPFUNC, APFFUNC, MONFUNC, MNFUNC,RFFUNC,
|
||||
AROFUNC, MUTEFUNC, VSCFUNC, REVFUNC, SQLFUNC, ABMFUNC, BCFUNC, MBCFUNC, RITFUNC, AFCFUNC, SATMODEFUNC, SCOPEFUNC,
|
||||
NBLEVEL, NBDEPTH, NBWIDTH, NRLEVEL, RIGINPUT, POWERONOFF, RITVALUE,
|
||||
RESUMEFUNC, TBURSTFUNC, TUNERFUNC, LOCKFUNC, SMETER, POWERMETER, SWRMETER, ALCMETER, COMPMETER, VOLTAGEMETER, CURRENTMETER
|
||||
ANN, APO, BACKLIGHT, BEEP, TIME, BAT, KEYLIGHT,
|
||||
RESUMEFUNC, TBURSTFUNC, TUNERFUNC, LOCKFUNC, SMETER, POWERMETER, SWRMETER, ALCMETER, COMPMETER, VOLTAGEMETER, CURRENTMETER,
|
||||
};
|
||||
|
||||
struct value {
|
||||
|
@ -38,9 +39,9 @@ public:
|
|||
QDateTime whenUpdated(stateTypes s) { return map[s]._dateUpdated; }
|
||||
|
||||
void set(stateTypes s, quint64 x, bool u) {
|
||||
if (x != map[s]._value) {
|
||||
if ((x != (quint64)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = (quint64)x;
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
|
@ -48,9 +49,19 @@ public:
|
|||
}
|
||||
}
|
||||
void set(stateTypes s, qint32 x, bool u) {
|
||||
if ((quint64)x != map[s]._value) {
|
||||
if ((x != (qint32)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = (quint64)x;
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
_mutex.unlock();
|
||||
}
|
||||
}
|
||||
void set(stateTypes s, qint16 x, bool u) {
|
||||
if ((x != (qint16)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
|
@ -58,9 +69,9 @@ public:
|
|||
}
|
||||
}
|
||||
void set(stateTypes s, quint16 x, bool u) {
|
||||
if ((quint64)x != map[s]._value) {
|
||||
if ((x != (quint16)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = (quint64)x;
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
|
@ -68,9 +79,9 @@ public:
|
|||
}
|
||||
}
|
||||
void set(stateTypes s, quint8 x, bool u) {
|
||||
if ((quint64)x != map[s]._value) {
|
||||
if ((x != (quint8)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = (quint64)x;
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
|
@ -78,9 +89,9 @@ public:
|
|||
}
|
||||
}
|
||||
void set(stateTypes s, bool x, bool u) {
|
||||
if ((quint64)x != map[s]._value) {
|
||||
if ((x != (bool)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = (quint64)x;
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
|
@ -88,9 +99,9 @@ public:
|
|||
}
|
||||
}
|
||||
void set(stateTypes s, duplexMode x, bool u) {
|
||||
if ((quint64)x != map[s]._value) {
|
||||
if ((x != (duplexMode)map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = (quint64)x;
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
|
@ -99,9 +110,9 @@ public:
|
|||
}
|
||||
|
||||
void set(stateTypes s, rigInput x, bool u) {
|
||||
if ((quint64)x != map[s]._value) {
|
||||
if ((x != map[s]._value) && ((!u && !map[s]._updated) || (u))) {
|
||||
_mutex.lock();
|
||||
map[s]._value = (quint64)x;
|
||||
map[s]._value = quint64(x);
|
||||
map[s]._valid = true;
|
||||
map[s]._updated = u;
|
||||
map[s]._dateUpdated = QDateTime::currentDateTime();
|
||||
|
@ -110,12 +121,14 @@ public:
|
|||
}
|
||||
|
||||
bool getBool(stateTypes s) { return map[s]._value != 0; }
|
||||
quint8 getChar(stateTypes s) { return (quint8)map[s]._value; }
|
||||
quint16 getInt16(stateTypes s) { return (qint16)map[s]._value; }
|
||||
qint32 getInt32(stateTypes s) { return (qint32)map[s]._value; }
|
||||
quint8 getChar(stateTypes s) { return quint8(map[s]._value); }
|
||||
qint16 getInt16(stateTypes s) { return qint16(map[s]._value); }
|
||||
quint16 getUInt16(stateTypes s) { return quint16(map[s]._value); }
|
||||
qint32 getInt32(stateTypes s) { return qint32(map[s]._value); }
|
||||
quint32 getUInt32(stateTypes s) { return quint32(map[s]._value); }
|
||||
quint64 getInt64(stateTypes s) { return map[s]._value; }
|
||||
duplexMode getDuplex(stateTypes s) { return(duplexMode)map[s]._value; }
|
||||
rigInput getInput(stateTypes s) { return(rigInput)map[s]._value; }
|
||||
duplexMode getDuplex(stateTypes s) { return duplexMode(map[s]._value); }
|
||||
rigInput getInput(stateTypes s) { return rigInput(map[s]._value); }
|
||||
QMap<stateTypes, value> map;
|
||||
|
||||
|
||||
|
|
121
rthandler.cpp
|
@ -6,7 +6,7 @@
|
|||
#include <objbase.h>
|
||||
#endif
|
||||
|
||||
#define RT_EXCEPTION
|
||||
#undef RT_EXCEPTION
|
||||
|
||||
rtHandler::rtHandler(QObject* parent)
|
||||
{
|
||||
|
@ -55,16 +55,20 @@ bool rtHandler::init(audioSetup setup)
|
|||
return false;
|
||||
}
|
||||
|
||||
inFormat = toQAudioFormat(setup.codec, setup.sampleRate);
|
||||
radioFormat = toQAudioFormat(setup.codec, setup.sampleRate);
|
||||
|
||||
qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name <<
|
||||
", bits" << inFormat.sampleSize() <<
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
", bits" << radioFormat.sampleSize() <<
|
||||
#else
|
||||
", format" << radioFormat.sampleFormat() <<
|
||||
#endif
|
||||
", codec" << setup.codec <<
|
||||
", latency" << setup.latency <<
|
||||
", localAFGain" << setup.localAFgain <<
|
||||
", radioChan" << inFormat.channelCount() <<
|
||||
", radioChan" << radioFormat.channelCount() <<
|
||||
", resampleQuality" << setup.resampleQuality <<
|
||||
", samplerate" << inFormat.sampleRate() <<
|
||||
", samplerate" << radioFormat.sampleRate() <<
|
||||
", uLaw" << setup.ulaw;
|
||||
|
||||
#if !defined(Q_OS_MACX)
|
||||
|
@ -80,6 +84,12 @@ bool rtHandler::init(audioSetup setup)
|
|||
audio = new RtAudio(RtAudio::Api::MACOSX_CORE);
|
||||
#endif
|
||||
|
||||
codecType codec = LPCM;
|
||||
if (setup.codec == 0x01 || setup.codec == 0x20)
|
||||
codec = PCMU;
|
||||
else if (setup.codec == 0x40 || setup.codec == 0x40)
|
||||
codec = OPUS;
|
||||
|
||||
options.numberOfBuffers = int(setup.latency/setup.blockSize);
|
||||
|
||||
if (setup.portInt > 0) {
|
||||
|
@ -104,13 +114,18 @@ bool rtHandler::init(audioSetup setup)
|
|||
goto errorHandler;
|
||||
}
|
||||
#endif
|
||||
#ifdef RT_EXCEPTION
|
||||
if (info.probed)
|
||||
{
|
||||
#endif
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") successfully probed";
|
||||
|
||||
RtAudioFormat sampleFormat;
|
||||
outFormat.setByteOrder(QAudioFormat::LittleEndian);
|
||||
outFormat.setCodec("audio/pcm");
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
nativeFormat.setByteOrder(QAudioFormat::LittleEndian);
|
||||
nativeFormat.setCodec("audio/pcm");
|
||||
#endif
|
||||
|
||||
if (info.nativeFormats == 0)
|
||||
{
|
||||
|
@ -128,45 +143,61 @@ bool rtHandler::init(audioSetup setup)
|
|||
|
||||
qInfo(logAudio()) << " Preferred sample rate:" << info.preferredSampleRate;
|
||||
if (setup.isinput) {
|
||||
outFormat.setChannelCount(info.inputChannels);
|
||||
nativeFormat.setChannelCount(info.inputChannels);
|
||||
}
|
||||
else {
|
||||
outFormat.setChannelCount(info.outputChannels);
|
||||
nativeFormat.setChannelCount(info.outputChannels);
|
||||
}
|
||||
|
||||
qInfo(logAudio()) << " Channels:" << outFormat.channelCount();
|
||||
qInfo(logAudio()) << " Channels:" << nativeFormat.channelCount();
|
||||
|
||||
if (outFormat.channelCount() > 2) {
|
||||
outFormat.setChannelCount(2);
|
||||
if (nativeFormat.channelCount() > 2) {
|
||||
nativeFormat.setChannelCount(2);
|
||||
}
|
||||
else if (outFormat.channelCount() < 1)
|
||||
else if (nativeFormat.channelCount() < 1)
|
||||
{
|
||||
qCritical(logAudio()) << (setup.isinput ? "Input" : "Output") << "No channels found, aborting setup.";
|
||||
goto errorHandler;
|
||||
}
|
||||
|
||||
aParams.nChannels = outFormat.channelCount();
|
||||
if (nativeFormat.channelCount() == 1 && radioFormat.channelCount() == 2) {
|
||||
nativeFormat.setChannelCount(2);
|
||||
}
|
||||
|
||||
aParams.nChannels = nativeFormat.channelCount();
|
||||
|
||||
|
||||
outFormat.setSampleRate(info.preferredSampleRate);
|
||||
nativeFormat.setSampleRate(info.preferredSampleRate);
|
||||
|
||||
if (outFormat.sampleRate() < 44100) {
|
||||
outFormat.setSampleRate(48000);
|
||||
if (nativeFormat.sampleRate() < 44100) {
|
||||
nativeFormat.setSampleRate(48000);
|
||||
}
|
||||
|
||||
if (info.nativeFormats & RTAUDIO_FLOAT32) {
|
||||
outFormat.setSampleType(QAudioFormat::Float);
|
||||
outFormat.setSampleSize(32);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
nativeFormat.setSampleType(QAudioFormat::Float);
|
||||
nativeFormat.setSampleSize(32);
|
||||
#else
|
||||
nativeFormat.setSampleFormat(QAudioFormat::Float);
|
||||
#endif
|
||||
sampleFormat = RTAUDIO_FLOAT32;
|
||||
}
|
||||
else if (info.nativeFormats & RTAUDIO_SINT32) {
|
||||
outFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
outFormat.setSampleSize(32);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
nativeFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
nativeFormat.setSampleSize(32);
|
||||
#else
|
||||
nativeFormat.setSampleFormat(QAudioFormat::Int32);
|
||||
#endif
|
||||
sampleFormat = RTAUDIO_SINT32;
|
||||
}
|
||||
else if (info.nativeFormats & RTAUDIO_SINT16) {
|
||||
outFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
outFormat.setSampleSize(16);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
nativeFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
nativeFormat.setSampleSize(16);
|
||||
#else
|
||||
nativeFormat.setSampleFormat(QAudioFormat::Int16);
|
||||
#endif
|
||||
sampleFormat = RTAUDIO_SINT16;
|
||||
}
|
||||
else {
|
||||
|
@ -175,9 +206,13 @@ bool rtHandler::init(audioSetup setup)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << outFormat.sampleSize() << "Channel Count" << outFormat.channelCount() <<
|
||||
"Sample Rate" << outFormat.sampleRate() << "Codec" << outFormat.codec() << "Sample Type" << outFormat.sampleType();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleSize" << nativeFormat.sampleSize() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << nativeFormat.codec() << "Sample Type" << nativeFormat.sampleType();
|
||||
#else
|
||||
qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Selected format: SampleFormat" << nativeFormat.sampleFormat() << "Channel Count" << nativeFormat.channelCount() <<
|
||||
"Sample Rate" << nativeFormat.sampleRate() << "Codec" << codec;
|
||||
#endif
|
||||
|
||||
// We "hopefully" now have a valid format that is supported so try connecting
|
||||
converter = new audioConverter();
|
||||
|
@ -190,26 +225,26 @@ bool rtHandler::init(audioSetup setup)
|
|||
}
|
||||
converter->moveToThread(converterThread);
|
||||
|
||||
connect(this, SIGNAL(setupConverter(QAudioFormat, QAudioFormat, quint8, quint8)), converter, SLOT(init(QAudioFormat, QAudioFormat, quint8, quint8)));
|
||||
connect(this, SIGNAL(setupConverter(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)), converter, SLOT(init(QAudioFormat, codecType, QAudioFormat, codecType, quint8, quint8)));
|
||||
connect(converterThread, SIGNAL(finished()), converter, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(sendToConverter(audioPacket)), converter, SLOT(convert(audioPacket)));
|
||||
converterThread->start(QThread::TimeCriticalPriority);
|
||||
|
||||
|
||||
// Per channel chunk size.
|
||||
this->chunkSize = (outFormat.bytesForDuration(setup.blockSize * 1000) / (outFormat.sampleSize()/8) / outFormat.channelCount());
|
||||
this->chunkSize = nativeFormat.framesForDuration(setup.blockSize * 1000);
|
||||
|
||||
#ifdef RT_EXCEPTION
|
||||
try {
|
||||
#endif
|
||||
if (setup.isinput) {
|
||||
audio->openStream(NULL, &aParams, sampleFormat, outFormat.sampleRate(), &this->chunkSize, &staticWrite, this, &options);
|
||||
emit setupConverter(outFormat, inFormat, 7, setup.resampleQuality);
|
||||
audio->openStream(NULL, &aParams, sampleFormat, nativeFormat.sampleRate(), &this->chunkSize, &staticWrite, this, &options);
|
||||
emit setupConverter(nativeFormat, codecType::LPCM, radioFormat, codec, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedInput(audioPacket)));
|
||||
}
|
||||
else {
|
||||
audio->openStream(&aParams, NULL, sampleFormat, outFormat.sampleRate(), &this->chunkSize, &staticRead, this , &options);
|
||||
emit setupConverter(inFormat, outFormat, 7, setup.resampleQuality);
|
||||
audio->openStream(&aParams, NULL, sampleFormat, nativeFormat.sampleRate(), &this->chunkSize, &staticRead, this , &options);
|
||||
emit setupConverter(radioFormat, codec, nativeFormat, codecType::LPCM, 7, setup.resampleQuality);
|
||||
connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedOutput(audioPacket)));
|
||||
}
|
||||
audio->startStream();
|
||||
|
@ -224,13 +259,15 @@ bool rtHandler::init(audioSetup setup)
|
|||
goto errorHandler;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RT_EXCEPTION
|
||||
}
|
||||
else
|
||||
{
|
||||
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << QString::fromStdString(info.name) << "(" << aParams.deviceId << ") could not be probed, check audio configuration!";
|
||||
goto errorHandler;
|
||||
}
|
||||
|
||||
#endif
|
||||
this->setVolume(setup.localAFgain);
|
||||
|
||||
|
||||
|
@ -268,8 +305,7 @@ int rtHandler::readData(void* outputBuffer, void* inputBuffer,
|
|||
{
|
||||
Q_UNUSED(inputBuffer);
|
||||
Q_UNUSED(streamTime);
|
||||
int nBytes = nFrames * outFormat.channelCount() * (outFormat.sampleSize()/8);
|
||||
|
||||
int nBytes = nFrames * nativeFormat.bytesPerFrame();
|
||||
//lastSentSeq = packet.seq;
|
||||
if (arrayBuffer.length() >= nBytes) {
|
||||
if (audioMutex.tryLock(0)) {
|
||||
|
@ -305,8 +341,9 @@ int rtHandler::writeData(void* outputBuffer, void* inputBuffer,
|
|||
packet.sent = 0;
|
||||
packet.volume = volume;
|
||||
memcpy(&packet.guid, setup.guid, GUIDLEN);
|
||||
packet.data.append((char*)inputBuffer, nFrames *outFormat.channelCount() * (outFormat.sampleSize()/8));
|
||||
packet.data.append((char*)inputBuffer, nFrames * nativeFormat.bytesPerFrame());
|
||||
emit sendToConverter(packet);
|
||||
|
||||
if (status == RTAUDIO_INPUT_OVERFLOW) {
|
||||
isUnderrun = true;
|
||||
}
|
||||
|
@ -328,9 +365,9 @@ void rtHandler::convertedOutput(audioPacket packet)
|
|||
audioMutex.lock();
|
||||
arrayBuffer.append(packet.data);
|
||||
audioMutex.unlock();
|
||||
amplitude = packet.amplitudePeak;
|
||||
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audio->getStreamLatency() * (outFormat.sampleSize() / 8) * outFormat.channelCount())/1000);
|
||||
emit haveLevels(getAmplitude(), packet.amplitudeRMS, setup.latency, currentLatency, isUnderrun, isOverrun);
|
||||
amplitude = packet.amplitudePeak;
|
||||
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (nativeFormat.durationForBytes(audio->getStreamLatency() * nativeFormat.bytesPerFrame()) / 1000);
|
||||
emit haveLevels(getAmplitude(), packet.amplitudeRMS, setup.latency, currentLatency, isUnderrun, isOverrun);
|
||||
}
|
||||
|
||||
|
||||
|
@ -339,9 +376,9 @@ void rtHandler::convertedInput(audioPacket packet)
|
|||
{
|
||||
if (packet.data.size() > 0) {
|
||||
emit haveAudioData(packet);
|
||||
amplitude = packet.amplitudePeak;
|
||||
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (outFormat.durationForBytes(audio->getStreamLatency() * (outFormat.sampleSize() / 8) * outFormat.channelCount())/1000);
|
||||
emit haveLevels(getAmplitude(), static_cast<quint16>(packet.amplitudeRMS * 255.0), setup.latency, currentLatency, isUnderrun, isOverrun);
|
||||
amplitude = packet.amplitudePeak;
|
||||
currentLatency = packet.time.msecsTo(QTime::currentTime()) + (nativeFormat.durationForBytes(audio->getStreamLatency() * nativeFormat.bytesPerFrame()) / 1000);
|
||||
emit haveLevels(getAmplitude(), static_cast<quint16>(packet.amplitudeRMS * 255.0), setup.latency, currentLatency, isUnderrun, isOverrun);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
int getLatency();
|
||||
|
||||
|
||||
using audioHandler::getNextAudioChunk;
|
||||
void getNextAudioChunk(QByteArray& data);
|
||||
quint16 getAmplitude();
|
||||
|
||||
|
@ -62,7 +62,7 @@ signals:
|
|||
void sendLatency(quint16 newSize);
|
||||
void haveAudioData(const audioPacket& data);
|
||||
void haveLevels(quint16 amplitudePeak, quint16 amplitudeRMS, quint16 latency, quint16 current, bool under, bool over);
|
||||
void setupConverter(QAudioFormat in, QAudioFormat out, quint8 opus, quint8 resamp);
|
||||
void setupConverter(QAudioFormat in, codecType codecIn, QAudioFormat out, codecType codecOut, quint8 opus, quint8 resamp);
|
||||
void sendToConverter(audioPacket audio);
|
||||
|
||||
private:
|
||||
|
@ -101,8 +101,8 @@ private:
|
|||
qreal volume = 1.0;
|
||||
|
||||
audioSetup setup;
|
||||
QAudioFormat inFormat;
|
||||
QAudioFormat outFormat;
|
||||
QAudioFormat radioFormat;
|
||||
QAudioFormat nativeFormat;
|
||||
audioConverter* converter = Q_NULLPTR;
|
||||
QThread* converterThread = Q_NULLPTR;
|
||||
QByteArray arrayBuffer;
|
||||
|
|
|
@ -60,7 +60,11 @@ void selectRadio::setInUse(quint8 radio, quint8 busy, QString user, QString ip)
|
|||
|
||||
void selectRadio::on_table_cellClicked(int row, int col) {
|
||||
qInfo() << "Clicked on " << row << "," << col;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5,11,0))
|
||||
if (ui->table->item(row, col)->backgroundColor() != Qt::darkGreen) {
|
||||
#else
|
||||
if (ui->table->item(row, col)->background() != Qt::darkGreen) {
|
||||
#endif
|
||||
ui->table->selectRow(row);
|
||||
emit selectedRadio(row);
|
||||
this->setVisible(false);
|
||||
|
|
228
servermain.cpp
|
@ -8,13 +8,15 @@
|
|||
// This code is copyright 2017-2020 Elliott H. Liggett
|
||||
// All rights reserved
|
||||
|
||||
servermain::servermain(const QString settingsFile, const QString logFile)
|
||||
servermain::servermain(const QString settingsFile)
|
||||
{
|
||||
|
||||
qRegisterMetaType <udpPreferences>(); // Needs to be registered early.
|
||||
qRegisterMetaType <rigCapabilities>();
|
||||
qRegisterMetaType <duplexMode>();
|
||||
qRegisterMetaType <rptAccessTxRx>();
|
||||
qRegisterMetaType <rptrAccessData_t>();
|
||||
qRegisterMetaType <rptAccessTxRx>();
|
||||
qRegisterMetaType <rigInput>();
|
||||
qRegisterMetaType <meterKind>();
|
||||
qRegisterMetaType <spectrumMode>();
|
||||
|
@ -28,6 +30,8 @@ servermain::servermain(const QString settingsFile, const QString logFile)
|
|||
qRegisterMetaType<rigstate*>();
|
||||
qRegisterMetaType<QList<radio_cap_packet>>();
|
||||
qRegisterMetaType<networkStatus>();
|
||||
qRegisterMetaType<codecType>();
|
||||
qRegisterMetaType<errorType>();
|
||||
|
||||
setDefPrefs();
|
||||
|
||||
|
@ -35,6 +39,10 @@ servermain::servermain(const QString settingsFile, const QString logFile)
|
|||
|
||||
loadSettings(); // Look for saved preferences
|
||||
|
||||
audioDev = new audioDevices(prefs.audioSystem, QFontMetrics(QFont()));
|
||||
connect(audioDev, SIGNAL(updated()), this, SLOT(updateAudioDevices()));
|
||||
audioDev->enumerate();
|
||||
|
||||
setInitialTiming();
|
||||
|
||||
openRig();
|
||||
|
@ -62,6 +70,10 @@ servermain::~servermain()
|
|||
serverThread->wait();
|
||||
}
|
||||
|
||||
if (audioDev != Q_NULLPTR) {
|
||||
delete audioDev;
|
||||
}
|
||||
|
||||
delete settings;
|
||||
|
||||
#if defined(PORTAUDIO)
|
||||
|
@ -87,7 +99,7 @@ void servermain::openRig()
|
|||
{
|
||||
//qInfo(logSystem()) << "Got rig";
|
||||
QMetaObject::invokeMethod(radio->rig, [=]() {
|
||||
radio->rig->commSetup(radio->civAddr, radio->serialPort, radio->baudRate, QString("none"),prefs.tcpPort,radio->waterfallFormat);
|
||||
radio->rig->commSetup(radio->civAddr, radio->serialPort, radio->baudRate, QString("none"),0 ,radio->waterfallFormat);
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +122,7 @@ void servermain::makeRig()
|
|||
connect(radio->rigThread, SIGNAL(finished()), radio->rig, SLOT(deleteLater()));
|
||||
radio->rigThread->start();
|
||||
// Rig status and Errors:
|
||||
connect(radio->rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString)));
|
||||
connect(radio->rig, SIGNAL(havePortError(errorType)), this, SLOT(receivePortError(errorType)));
|
||||
connect(radio->rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus)));
|
||||
|
||||
// Rig comm setup:
|
||||
|
@ -319,11 +331,9 @@ void servermain::receiveFoundRigID(rigCapabilities rigCaps)
|
|||
return;
|
||||
}
|
||||
|
||||
void servermain::receiveSerialPortError(QString port, QString errorText)
|
||||
void servermain::receivePortError(errorType err)
|
||||
{
|
||||
qInfo(logSystem()) << "servermain: received serial port error for port: " << port << " with message: " << errorText;
|
||||
|
||||
// TODO: Dialog box, exit, etc
|
||||
qInfo(logSystem()) << "servermain: received error for device: " << err.device << " with message: " << err.message;
|
||||
}
|
||||
|
||||
|
||||
|
@ -430,6 +440,7 @@ void servermain::setDefPrefs()
|
|||
udpDefPrefs.username = QString("");
|
||||
udpDefPrefs.password = QString("");
|
||||
udpDefPrefs.clientName = QHostInfo::localHostName();
|
||||
|
||||
}
|
||||
|
||||
void servermain::loadSettings()
|
||||
|
@ -485,7 +496,7 @@ void servermain::loadSettings()
|
|||
|
||||
numRadios = settings->beginReadArray("Radios");
|
||||
int tempNum = numRadios;
|
||||
|
||||
|
||||
for (int i = 0; i < numRadios; i++) {
|
||||
settings->setArrayIndex(i);
|
||||
RIGCONFIG* tempPrefs = new RIGCONFIG();
|
||||
|
@ -500,23 +511,16 @@ void servermain::loadSettings()
|
|||
tempPrefs->rxAudioSetup.type = prefs.audioSystem;
|
||||
tempPrefs->txAudioSetup.type = prefs.audioSystem;
|
||||
|
||||
QString tempPort = "auto";
|
||||
if (tempPrefs->rigName=="<NONE>")
|
||||
{
|
||||
if (tempPrefs->serialPort == "auto") {
|
||||
foreach(const QSerialPortInfo & serialPortInfo, QSerialPortInfo::availablePorts())
|
||||
{
|
||||
qDebug(logSystem()) << "Serial Port found: " << serialPortInfo.portName() << "Manufacturer:" << serialPortInfo.manufacturer() << "Product ID" << serialPortInfo.description() << "S/N" << serialPortInfo.serialNumber();
|
||||
if ((serialPortInfo.portName() == tempPrefs->serialPort || tempPrefs->serialPort == "auto") && !serialPortInfo.serialNumber().isEmpty())
|
||||
{
|
||||
if (serialPortInfo.serialNumber().startsWith("IC-")) {
|
||||
tempPrefs->rigName = serialPortInfo.serialNumber();
|
||||
tempPort = serialPortInfo.portName();
|
||||
}
|
||||
if (serialPortInfo.serialNumber().startsWith("IC-") && tempPrefs->serialPort == "auto") {
|
||||
tempPrefs->rigName = serialPortInfo.serialNumber();
|
||||
tempPrefs->serialPort = serialPortInfo.portName();
|
||||
}
|
||||
}
|
||||
}
|
||||
tempPrefs->serialPort = tempPort;
|
||||
|
||||
QString guid = settings->value("GUID", "").toString();
|
||||
if (guid.isEmpty()) {
|
||||
guid = QUuid::createUuid().toString();
|
||||
|
@ -534,6 +538,7 @@ void servermain::loadSettings()
|
|||
|
||||
tempPrefs->rig = Q_NULLPTR;
|
||||
tempPrefs->rigThread = Q_NULLPTR;
|
||||
|
||||
serverConfig.rigs.append(tempPrefs);
|
||||
if (tempNum == 0) {
|
||||
settings->endGroup();
|
||||
|
@ -544,167 +549,6 @@ void servermain::loadSettings()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Now we have an array of rig objects, we need to match the configured audio devices with physical devices
|
||||
*/
|
||||
switch (prefs.audioSystem)
|
||||
{
|
||||
case rtAudio:
|
||||
{
|
||||
#if defined(Q_OS_LINUX)
|
||||
RtAudio* audio = new RtAudio(RtAudio::Api::LINUX_ALSA);
|
||||
// RtAudio* audio = new RtAudio(RtAudio::Api::LINUX_PULSE);
|
||||
#elif defined(Q_OS_WIN)
|
||||
RtAudio* audio = new RtAudio(RtAudio::Api::WINDOWS_WASAPI);
|
||||
#elif defined(Q_OS_MACX)
|
||||
RtAudio* audio = new RtAudio(RtAudio::Api::MACOSX_CORE);
|
||||
#endif
|
||||
|
||||
// Enumerate audio devices, need to do before settings are loaded.
|
||||
std::map<int, std::string> apiMap;
|
||||
apiMap[RtAudio::MACOSX_CORE] = "OS-X Core Audio";
|
||||
apiMap[RtAudio::WINDOWS_ASIO] = "Windows ASIO";
|
||||
apiMap[RtAudio::WINDOWS_DS] = "Windows DirectSound";
|
||||
apiMap[RtAudio::WINDOWS_WASAPI] = "Windows WASAPI";
|
||||
apiMap[RtAudio::UNIX_JACK] = "Jack Client";
|
||||
apiMap[RtAudio::LINUX_ALSA] = "Linux ALSA";
|
||||
apiMap[RtAudio::LINUX_PULSE] = "Linux PulseAudio";
|
||||
apiMap[RtAudio::LINUX_OSS] = "Linux OSS";
|
||||
apiMap[RtAudio::RTAUDIO_DUMMY] = "RtAudio Dummy";
|
||||
|
||||
std::vector< RtAudio::Api > apis;
|
||||
RtAudio::getCompiledApi(apis);
|
||||
|
||||
qInfo(logAudio()) << "RtAudio Version " << QString::fromStdString(RtAudio::getVersion());
|
||||
|
||||
qInfo(logAudio()) << "Compiled APIs:";
|
||||
for (unsigned int i = 0; i < apis.size(); i++) {
|
||||
qInfo(logAudio()) << " " << QString::fromStdString(apiMap[apis[i]]);
|
||||
}
|
||||
|
||||
RtAudio::DeviceInfo info;
|
||||
|
||||
qInfo(logAudio()) << "Current API: " << QString::fromStdString(apiMap[audio->getCurrentApi()]);
|
||||
|
||||
unsigned int devices = audio->getDeviceCount();
|
||||
qInfo(logAudio()) << "Found " << devices << " audio device(s) *=default";
|
||||
|
||||
for (unsigned int i = 1; i < devices; i++) {
|
||||
info = audio->getDeviceInfo(i);
|
||||
for (RIGCONFIG* rig : serverConfig.rigs)
|
||||
{
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "rxAudio device:" << rig->rxAudioSetup.name;
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "txAudio device:" << rig->txAudioSetup.name;
|
||||
if (info.outputChannels > 0)
|
||||
{
|
||||
qInfo(logAudio()) << (info.isDefaultOutput ? "*" : " ") << "(" << i << ") Output Device : " << QString::fromStdString(info.name);
|
||||
if (rig->txAudioSetup.name.toStdString() == info.name) {
|
||||
rig->txAudioSetup.portInt = i;
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "Selected txAudio device:" << QString(info.name.c_str());
|
||||
}
|
||||
}
|
||||
if (info.inputChannels > 0)
|
||||
{
|
||||
qInfo(logAudio()) << (info.isDefaultInput ? "*" : " ") << "(" << i << ") Input Device : " << QString::fromStdString(info.name);
|
||||
if (rig->rxAudioSetup.name.toStdString() == info.name) {
|
||||
rig->rxAudioSetup.portInt = i;
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "Selected rxAudio device:" << QString(info.name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case portAudio:
|
||||
{
|
||||
// Use PortAudio device enumeration
|
||||
|
||||
PaError err;
|
||||
|
||||
err = Pa_Initialize();
|
||||
|
||||
if (err != paNoError)
|
||||
{
|
||||
qInfo(logAudio()) << "ERROR: Cannot initialize Portaudio";
|
||||
}
|
||||
|
||||
qInfo(logAudio()) << "PortAudio version: " << Pa_GetVersionInfo()->versionText;
|
||||
|
||||
int numDevices;
|
||||
numDevices = Pa_GetDeviceCount();
|
||||
qInfo(logAudio()) << "Pa_CountDevices returned" << numDevices;
|
||||
|
||||
const PaDeviceInfo* info;
|
||||
for (int i = 0; i < numDevices; i++)
|
||||
{
|
||||
info = Pa_GetDeviceInfo(i);
|
||||
for (RIGCONFIG* rig : serverConfig.rigs)
|
||||
{
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "rxAudio device:" << rig->rxAudioSetup.name;
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "txAudio device:" << rig->txAudioSetup.name;
|
||||
if (info->maxInputChannels > 0) {
|
||||
qDebug(logAudio()) << (i == Pa_GetDefaultInputDevice() ? "*" : " ") << "(" << i << ") Input Device : " << info->name;
|
||||
|
||||
if (rig->rxAudioSetup.name == info->name) {
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "Selected rxAudio device:" << QString(info->name);
|
||||
rig->rxAudioSetup.portInt = i;
|
||||
}
|
||||
}
|
||||
if (info->maxOutputChannels > 0) {
|
||||
if (rig->txAudioSetup.name == info->name) {
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "Selected txAudio device:" << QString(info->name);
|
||||
rig->txAudioSetup.portInt = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case qtAudio:
|
||||
{
|
||||
const auto audioOutputs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
||||
const auto audioInputs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
|
||||
//qInfo(logAudio()) << "Looking for audio input devices";
|
||||
for (const QAudioDeviceInfo& deviceInfo : audioInputs) {
|
||||
qDebug(logSystem()) << "Found Audio input: " << deviceInfo.deviceName();
|
||||
for (RIGCONFIG* rig : serverConfig.rigs)
|
||||
{
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "rxAudio device:" << rig->rxAudioSetup.name;
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "txAudio device:" << rig->txAudioSetup.name;
|
||||
if (deviceInfo.deviceName() == rig->rxAudioSetup.name
|
||||
#ifdef Q_OS_WIN
|
||||
&& deviceInfo.realm() == "wasapi"
|
||||
#endif
|
||||
)
|
||||
{
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "Selected rxAudio device:" << deviceInfo.deviceName();
|
||||
rig->rxAudioSetup.port = deviceInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//qInfo(logAudio()) << "Looking for audio output devices";
|
||||
for (const QAudioDeviceInfo& deviceInfo : audioOutputs) {
|
||||
qDebug(logSystem()) << "Found Audio output: " << deviceInfo.deviceName();
|
||||
for (RIGCONFIG* rig : serverConfig.rigs)
|
||||
{
|
||||
if (deviceInfo.deviceName() == rig->txAudioSetup.name
|
||||
#ifdef Q_OS_WIN
|
||||
&& deviceInfo.realm() == "wasapi"
|
||||
#endif
|
||||
)
|
||||
{
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "Selected txAudio device:" << deviceInfo.deviceName();
|
||||
rig->txAudioSetup.port = deviceInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
settings->beginGroup("Server");
|
||||
serverConfig.enabled = settings->value("ServerEnabled", false).toBool();
|
||||
serverConfig.controlPort = settings->value("ServerControlPort", 50001).toInt();
|
||||
|
@ -738,6 +582,30 @@ void servermain::loadSettings()
|
|||
|
||||
}
|
||||
|
||||
void servermain::updateAudioDevices()
|
||||
{
|
||||
|
||||
for (RIGCONFIG* rig : serverConfig.rigs)
|
||||
{
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "configured rxAudio device:" << rig->rxAudioSetup.name;
|
||||
qDebug(logAudio()) << "Rig" << rig->rigName << "configured txAudio device:" << rig->txAudioSetup.name;
|
||||
|
||||
int inputNum = audioDev->findInput(rig->rigName, rig->rxAudioSetup.name);
|
||||
int outputNum = audioDev->findOutput(rig->rigName, rig->txAudioSetup.name);
|
||||
|
||||
if (prefs.audioSystem == qtAudio) {
|
||||
rig->rxAudioSetup.port = audioDev->getInputDeviceInfo(inputNum);
|
||||
rig->txAudioSetup.port = audioDev->getOutputDeviceInfo(outputNum);
|
||||
}
|
||||
else {
|
||||
rig->rxAudioSetup.portInt = audioDev->getInputDeviceInt(inputNum);
|
||||
rig->txAudioSetup.portInt = audioDev->getOutputDeviceInt(outputNum);
|
||||
}
|
||||
rig->rxAudioSetup.name = audioDev->getInputName(inputNum);
|
||||
rig->txAudioSetup.name = audioDev->getOutputName(outputNum);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void servermain::receivePTTstatus(bool pttOn)
|
||||
{
|
||||
|
|
14
servermain.h
|
@ -20,6 +20,7 @@
|
|||
#include "freqmemory.h"
|
||||
#include "rigidentities.h"
|
||||
#include "repeaterattributes.h"
|
||||
#include "audiodevices.h"
|
||||
|
||||
#include "udpserver.h"
|
||||
#include "rigctld.h"
|
||||
|
@ -46,7 +47,7 @@ class servermain : public QObject
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
servermain(const QString logFile, const QString settingsFile);
|
||||
servermain(const QString logFile);
|
||||
~servermain();
|
||||
|
||||
signals:
|
||||
|
@ -174,13 +175,14 @@ private slots:
|
|||
void receivePTTstatus(bool pttOn);
|
||||
|
||||
void receiveFoundRigID(rigCapabilities rigCaps);
|
||||
void receiveSerialPortError(QString port, QString errorText);
|
||||
void receivePortError(errorType err);
|
||||
void receiveBaudRate(quint32 baudrate);
|
||||
|
||||
void handlePttLimit();
|
||||
void receiveStatusUpdate(networkStatus status);
|
||||
void receiveStateInfo(rigstate* state);
|
||||
void connectToRig(RIGCONFIG* rig);
|
||||
void updateAudioDevices();
|
||||
|
||||
private:
|
||||
QSettings *settings=Q_NULLPTR;
|
||||
|
@ -282,6 +284,8 @@ private:
|
|||
|
||||
rigstate* rigState = Q_NULLPTR;
|
||||
|
||||
audioDevices* audioDev = Q_NULLPTR;
|
||||
|
||||
SERVERCONFIG serverConfig;
|
||||
};
|
||||
|
||||
|
@ -300,6 +304,12 @@ Q_DECLARE_METATYPE(QList<radio_cap_packet>)
|
|||
Q_DECLARE_METATYPE(enum meterKind)
|
||||
Q_DECLARE_METATYPE(enum spectrumMode)
|
||||
Q_DECLARE_METATYPE(rigstate*)
|
||||
Q_DECLARE_METATYPE(codecType)
|
||||
Q_DECLARE_METATYPE(errorType)
|
||||
Q_DECLARE_METATYPE(enum duplexMode)
|
||||
Q_DECLARE_METATYPE(enum rptAccessTxRx)
|
||||
Q_DECLARE_METATYPE(struct rptrTone_t)
|
||||
Q_DECLARE_METATYPE(struct rptrAccessData_t)
|
||||
|
||||
|
||||
#endif // WFMAIN_H
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef SIDEBANDCHOOSER_H
|
||||
#define SIDEBANDCHOOSER_H
|
||||
|
||||
#include "wfviewtypes.h"
|
||||
|
||||
class sidebandChooser
|
||||
{
|
||||
public:
|
||||
sidebandChooser();
|
||||
|
||||
static inline mode_kind getMode(freqt f, mode_kind currentMode = modeUSB) {
|
||||
|
||||
if((currentMode == modeLSB) || (currentMode == modeUSB) )
|
||||
{
|
||||
if(f.Hz < 5000000)
|
||||
{
|
||||
return modeLSB;
|
||||
}
|
||||
if( (f.Hz >= 5000000) && (f.Hz < 5600000) )
|
||||
{
|
||||
return modeUSB;
|
||||
}
|
||||
if( (f.Hz >= 5600000) && (f.Hz < 10000000) )
|
||||
{
|
||||
return modeLSB;
|
||||
}
|
||||
|
||||
return modeUSB;
|
||||
} else {
|
||||
return currentMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // SIDEBANDCHOOSER_H
|
|
@ -6,7 +6,8 @@ transceiverAdjustments::transceiverAdjustments(QWidget *parent) :
|
|||
ui(new Ui::transceiverAdjustments)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
#ifndef QT_DEBUG
|
||||
|
||||
// ---- These controls aren't finished yet:
|
||||
ui->transmitterControlsGroupBox->setVisible(false); // no controls available so far
|
||||
ui->bassRxLabel->setVisible(false);
|
||||
ui->bassRxSlider->setVisible(false);
|
||||
|
@ -20,11 +21,14 @@ transceiverAdjustments::transceiverAdjustments(QWidget *parent) :
|
|||
ui->NBRxChkBox->setVisible(false);
|
||||
ui->NBRxSlider->setVisible(false);
|
||||
ui->bandwidthGroupBox->setVisible(false);
|
||||
ui->otherGrpBox->setVisible(false);
|
||||
// ----
|
||||
|
||||
// Resize to fit new visible contents:
|
||||
this->window()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
this->window()->resize(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
#endif
|
||||
|
||||
this->setWindowTitle("TransceiverAdjustments");
|
||||
}
|
||||
|
||||
transceiverAdjustments::~transceiverAdjustments()
|
||||
|
@ -37,6 +41,15 @@ transceiverAdjustments::~transceiverAdjustments()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void transceiverAdjustments::setMaxPassband(quint16 maxHzAllowed)
|
||||
{
|
||||
if( (maxHzAllowed <= 10E3) && (maxHzAllowed != 0) )
|
||||
{
|
||||
maxHz = maxHzAllowed;
|
||||
updatePassband(lastKnownPassband);
|
||||
}
|
||||
}
|
||||
|
||||
void transceiverAdjustments::on_IFShiftSlider_valueChanged(int value)
|
||||
{
|
||||
if(rigCaps.hasIFShift)
|
||||
|
@ -103,3 +116,43 @@ void transceiverAdjustments::updateTPBFOuter(unsigned char level)
|
|||
ui->TPBFOuterSlider->setValue(level);
|
||||
ui->TPBFOuterSlider->blockSignals(false);
|
||||
}
|
||||
|
||||
void transceiverAdjustments::updatePassband(quint16 passbandHz)
|
||||
{
|
||||
lastKnownPassband = passbandHz;
|
||||
float l = 2.0*passbandHz/maxHz;
|
||||
#ifdef Q_OS_LINUX
|
||||
int val = exp10f(l);
|
||||
#else
|
||||
int val = pow(10, l);
|
||||
#endif
|
||||
|
||||
//qDebug() << "Updating slider passband to " << passbandHz << "Hz using 1-100 value:" << val << "with l=" << l << "and max=" << maxHz;
|
||||
ui->passbandWidthSlider->blockSignals(true);
|
||||
ui->passbandWidthSlider->setValue(val);
|
||||
ui->passbandWidthSlider->blockSignals(false);
|
||||
}
|
||||
|
||||
void transceiverAdjustments::on_resetPBTbtn_clicked()
|
||||
{
|
||||
ui->TPBFInnerSlider->setValue(128);
|
||||
ui->TPBFOuterSlider->setValue(128);
|
||||
ui->IFShiftSlider->blockSignals(true);
|
||||
ui->IFShiftSlider->setValue(128);
|
||||
ui->IFShiftSlider->blockSignals(false);
|
||||
}
|
||||
|
||||
void transceiverAdjustments::on_passbandWidthSlider_valueChanged(int value)
|
||||
{
|
||||
// value is 1-100
|
||||
//float maxHz = 10E3;
|
||||
float l = log10f(value);
|
||||
float p = l*maxHz/2.0;
|
||||
quint16 pbHz = (quint16)p;
|
||||
if(pbHz != 0)
|
||||
{
|
||||
//qDebug() << "Setting passband, maxHZ" << maxHz << ", value: " << value << ", l:" << l << ", p:" << p << ", pbHz: " << pbHz;
|
||||
lastKnownPassband = pbHz;
|
||||
emit setPassband(pbHz);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "rigidentities.h"
|
||||
|
||||
|
||||
|
@ -20,17 +22,20 @@ class transceiverAdjustments : public QWidget
|
|||
public:
|
||||
explicit transceiverAdjustments(QWidget *parent = 0);
|
||||
~transceiverAdjustments();
|
||||
void setMaxPassband(quint16 maxHzAllowed);
|
||||
|
||||
signals:
|
||||
void setIFShift(unsigned char level);
|
||||
void setTPBFInner(unsigned char level);
|
||||
void setTPBFOuter(unsigned char level);
|
||||
void setPassband(quint16 passbandHz);
|
||||
|
||||
public slots:
|
||||
void setRig(rigCapabilities rig);
|
||||
void updateIFShift(unsigned char level);
|
||||
void updateTPBFInner(unsigned char level);
|
||||
void updateTPBFOuter(unsigned char level);
|
||||
void updatePassband(quint16 passbandHz);
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -40,11 +45,17 @@ private slots:
|
|||
|
||||
void on_TPBFOuterSlider_valueChanged(int value);
|
||||
|
||||
void on_resetPBTbtn_clicked();
|
||||
|
||||
void on_passbandWidthSlider_valueChanged(int value);
|
||||
|
||||
private:
|
||||
Ui::transceiverAdjustments *ui;
|
||||
rigCapabilities rigCaps;
|
||||
bool haveRigCaps = false;
|
||||
int previousIFShift = 128;
|
||||
float maxHz = 10E3;
|
||||
quint16 lastKnownPassband = 3500;
|
||||
};
|
||||
|
||||
#endif // TRANSCEIVERADJUSTMENTS_H
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>832</width>
|
||||
<height>337</height>
|
||||
<width>961</width>
|
||||
<height>370</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -166,9 +166,219 @@
|
|||
<item>
|
||||
<widget class="QGroupBox" name="receiverControlsGroupBox">
|
||||
<property name="title">
|
||||
<string>Receiver</string>
|
||||
<string>Receiver Passband Controls</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="TPBFOuterLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PBF Outer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="TPBFOuterSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>230</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="TPBFInnerLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PBF Inner</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="TPBFInnerSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>230</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="IFShiftLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>IF Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="IFShiftSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>230</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Filter Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="passbandWidthSlider">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QPushButton" name="resetPBTbtn">
|
||||
<property name="text">
|
||||
<string>Reset PBT</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="otherGrpBox">
|
||||
<property name="title">
|
||||
<string>Other</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="bassRxVertLayout">
|
||||
<item>
|
||||
|
@ -229,111 +439,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="IFShiftVertLayout">
|
||||
<item>
|
||||
<widget class="QSlider" name="IFShiftSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>230</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="IFShiftLabel">
|
||||
<property name="text">
|
||||
<string>IF Shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="PBFInnerVertLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="TPBFInnerSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>230</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="TPBFInnerLabel">
|
||||
<property name="text">
|
||||
<string>PBF Inner</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="TPBFOuterVertLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="TPBFOuterSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>230</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="TPBFOuterLabel">
|
||||
<property name="text">
|
||||
<string>PBF Outer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="NRRxVertLayout">
|
||||
<item>
|
||||
|
@ -463,6 +568,26 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
|
|
@ -127,7 +127,7 @@ void udpAudio::receiveAudioData(audioPacket audio) {
|
|||
QByteArray partial = audio.data.mid(len, 1364);
|
||||
audio_packet p;
|
||||
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
|
||||
p.len = sizeof(p) + partial.length();
|
||||
p.len = (quint32)sizeof(p) + partial.length();
|
||||
p.sentid = myId;
|
||||
p.rcvdid = remoteId;
|
||||
if (partial.length() == 0xa0) {
|
||||
|
|
13
udpbase.cpp
|
@ -199,7 +199,7 @@ void udpBase::dataReceived(QByteArray r)
|
|||
{
|
||||
if (in->seq < rxSeqBuf.firstKey() || in->seq - rxSeqBuf.lastKey() > MAX_MISSING)
|
||||
{
|
||||
qInfo(logUdp()) << this->metaObject()->className() << "Large seq number gap detected, previous highest: " <<
|
||||
qDebug(logUdp()) << this->metaObject()->className() << "Large seq number gap detected, previous highest: " <<
|
||||
QString("0x%1").arg(rxSeqBuf.lastKey(), 0, 16) << " current: " << QString("0x%1").arg(in->seq, 0, 16);
|
||||
//seqPrefix++;
|
||||
// Looks like it has rolled over so clear buffer and start again.
|
||||
|
@ -218,7 +218,7 @@ void udpBase::dataReceived(QByteArray r)
|
|||
// Add incoming packet to the received buffer and if it is in the missing buffer, remove it.
|
||||
|
||||
if (in->seq > rxSeqBuf.lastKey() + 1) {
|
||||
qInfo(logUdp()) << this->metaObject()->className() << "1 or more missing packets detected, previous: " <<
|
||||
qDebug(logUdp()) << this->metaObject()->className() << "1 or more missing packets detected, previous: " <<
|
||||
QString("0x%1").arg(rxSeqBuf.lastKey(), 0, 16) << " current: " << QString("0x%1").arg(in->seq, 0, 16);
|
||||
// We are likely missing packets then!
|
||||
missingMutex.lock();
|
||||
|
@ -253,7 +253,7 @@ void udpBase::dataReceived(QByteArray r)
|
|||
auto s = rxMissing.find(in->seq);
|
||||
if (s != rxMissing.end())
|
||||
{
|
||||
qInfo(logUdp()) << this->metaObject()->className() << ": Missing SEQ has been received! " << QString("0x%1").arg(in->seq, 0, 16);
|
||||
qDebug(logUdp()) << this->metaObject()->className() << ": Missing SEQ has been received! " << QString("0x%1").arg(in->seq, 0, 16);
|
||||
|
||||
s = rxMissing.erase(s);
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ void udpBase::sendRetransmitRequest()
|
|||
{
|
||||
qInfo(logUdp()) << this->metaObject()->className() << ": sending request for multiple missing packets : " << missingSeqs.toHex(':');
|
||||
missingMutex.lock();
|
||||
p.len = sizeof(p) + missingSeqs.size();
|
||||
p.len = (quint32)sizeof(p) + missingSeqs.size();
|
||||
missingSeqs.insert(0, p.packet, sizeof(p));
|
||||
missingMutex.unlock();
|
||||
|
||||
|
@ -429,11 +429,12 @@ void udpBase::sendTrackedPacket(QByteArray d)
|
|||
|
||||
udpMutex.lock();
|
||||
udp->writeDatagram(d, radioIP, port);
|
||||
if (congestion > 10) { // Poor quality connection?
|
||||
|
||||
/*if (congestion > 10) { // Poor quality connection?
|
||||
udp->writeDatagram(d, radioIP, port);
|
||||
if (congestion > 20) // Even worse so send again.
|
||||
udp->writeDatagram(d, radioIP, port);
|
||||
}
|
||||
} */
|
||||
if (idleTimer != Q_NULLPTR && idleTimer->isActive()) {
|
||||
idleTimer->start(IDLE_PERIOD); // Reset idle counter if it's running
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ struct udpPreferences {
|
|||
QString password;
|
||||
QString clientName;
|
||||
quint8 waterfallFormat;
|
||||
bool halfDuplex;
|
||||
};
|
||||
|
||||
struct networkAudioLevels {
|
||||
|
|
|
@ -93,7 +93,7 @@ void udpCivData::send(QByteArray d)
|
|||
//qInfo(logUdp()) << "Sending: (" << d.length() << ") " << d;
|
||||
data_packet p;
|
||||
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
|
||||
p.len = sizeof(p) + d.length();
|
||||
p.len = (quint32)sizeof(p) + d.length();
|
||||
p.sentid = myId;
|
||||
p.rcvdid = remoteId;
|
||||
p.reply = (char)0xc1;
|
||||
|
|
|
@ -325,12 +325,12 @@ void udpHandler::dataReceived()
|
|||
if (in->type != 0x01) {
|
||||
if (in->error == 0xffffffff && !streamOpened)
|
||||
{
|
||||
emit haveNetworkError(radioIP.toString(), "Connection failed, wait a few minutes or reboot the radio.");
|
||||
emit haveNetworkError(errorType(true, radioIP.toString(), "Connection failed\ntry rebooting the radio."));
|
||||
qInfo(logUdp()) << this->metaObject()->className() << ": Connection failed, wait a few minutes or reboot the radio.";
|
||||
}
|
||||
else if (in->error == 0x00000000 && in->disc == 0x01)
|
||||
{
|
||||
emit haveNetworkError(radioIP.toString(), "Got radio disconnected.");
|
||||
emit haveNetworkError(errorType(radioIP.toString(), "Got radio disconnected."));
|
||||
qInfo(logUdp()) << this->metaObject()->className() << ": Got radio disconnected.";
|
||||
if (streamOpened) {
|
||||
// Close stream connections but keep connection open to the radio.
|
||||
|
@ -395,7 +395,7 @@ void udpHandler::dataReceived()
|
|||
{
|
||||
if (rxSetup.codec >= 0x40 || txSetup.codec >= 0x40)
|
||||
{
|
||||
emit haveNetworkError(QString("UDP"), QString("Opus codec not supported, forcing LPCM16"));
|
||||
emit haveNetworkError(errorType(QString("UDP"), QString("Opus codec not supported, forcing LPCM16")));
|
||||
if (rxSetup.codec >= 0x40)
|
||||
rxSetup.codec = 0x04;
|
||||
if (txSetup.codec >= 0x40)
|
||||
|
@ -406,7 +406,7 @@ void udpHandler::dataReceived()
|
|||
|
||||
if (in->error == 0xfeffffff)
|
||||
{
|
||||
status.message = "Invalid Username/Password";
|
||||
emit haveNetworkError(errorType(true, radioIP.toString(), "Invalid Username/Password"));
|
||||
qInfo(logUdp()) << this->metaObject()->className() << ": Invalid Username/Password";
|
||||
}
|
||||
else if (!isAuthenticated)
|
||||
|
@ -508,20 +508,13 @@ void udpHandler::dataReceived()
|
|||
const char* tmpRad = r.constData();
|
||||
memcpy(&rad, tmpRad+f, RADIO_CAP_SIZE);
|
||||
radios.append(rad);
|
||||
qInfo(logUdp()) << this->metaObject()->className() << QString("Received radio capabilities, Name: %1, Audio: %2, CIV: %3, MAC: %4:%5:%6:%7:%8:%9 CAPF: %10")
|
||||
.arg(rad.name).arg(rad.audio).arg((unsigned char)rad.civ, 2, 16, QChar('0'))
|
||||
.arg(rad.macaddress[0], 2, 16, QChar('0')).arg(rad.macaddress[1], 2, 16, QChar('0'))
|
||||
.arg(rad.macaddress[2], 2, 16, QChar('0')).arg(rad.macaddress[3], 2, 16, QChar('0'))
|
||||
.arg(rad.macaddress[4], 2, 16, QChar('0')).arg(rad.macaddress[5], 2, 16, QChar('0')).arg(rad.capf, 4, 16, QChar('0'));
|
||||
}
|
||||
for(const radio_cap_packet &radio : radios)
|
||||
{
|
||||
qInfo(logUdp()) << this->metaObject()->className() << "Received radio capabilities, Name:" <<
|
||||
radio.name << " Audio:" <<
|
||||
radio.audio << "CIV:" << QString("0x%1").arg((unsigned char)radio.civ,0, 16) <<
|
||||
"MAC:" << radio.macaddress[0] <<
|
||||
":" << radio.macaddress[1] <<
|
||||
":" << radio.macaddress[2] <<
|
||||
":" << radio.macaddress[3] <<
|
||||
":" << radio.macaddress[4] <<
|
||||
":" << radio.macaddress[5] <<
|
||||
"CAPF" << radio.capf;
|
||||
}
|
||||
|
||||
emit requestRadioSelection(radios);
|
||||
|
||||
break;
|
||||
|
@ -690,6 +683,7 @@ void udpHandler::sendToken(uint8_t magic)
|
|||
p.requestreply = 0x01;
|
||||
p.innerseq = qToBigEndian(authSeq++);
|
||||
p.tokrequest = tokRequest;
|
||||
p.resetcap = qToBigEndian((quint16)0x0798);
|
||||
p.token = token;
|
||||
|
||||
sendTrackedPacket(QByteArray::fromRawData((const char *)p.packet, sizeof(p)));
|
||||
|
|
|
@ -62,7 +62,7 @@ public slots:
|
|||
signals:
|
||||
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
|
||||
void haveAudioData(audioPacket data); // emit this when we have data, connect to rigcommander
|
||||
void haveNetworkError(QString, QString);
|
||||
void haveNetworkError(errorType);
|
||||
void haveChangeLatency(quint16 value);
|
||||
void haveSetVolume(unsigned char value);
|
||||
void haveNetworkStatus(networkStatus);
|
||||
|
|
|
@ -382,31 +382,32 @@ void udpServer::controlReceived()
|
|||
qCritical(logAudio()) << "Unsupported Transmit Audio Handler selected!";
|
||||
}
|
||||
|
||||
//radio->txaudio = new audioHandler();
|
||||
radio->txAudioThread = new QThread(this);
|
||||
radio->txAudioThread->setObjectName("txAudio()");
|
||||
|
||||
if (radio->txaudio != Q_NULLPTR) {
|
||||
radio->txAudioThread = new QThread(this);
|
||||
radio->txAudioThread->setObjectName("txAudio()");
|
||||
|
||||
|
||||
radio->txaudio->moveToThread(radio->txAudioThread);
|
||||
radio->txaudio->moveToThread(radio->txAudioThread);
|
||||
|
||||
radio->txAudioThread->start(QThread::TimeCriticalPriority);
|
||||
radio->txAudioThread->start(QThread::TimeCriticalPriority);
|
||||
|
||||
connect(this, SIGNAL(setupTxAudio(audioSetup)), radio->txaudio, SLOT(init(audioSetup)));
|
||||
connect(radio->txAudioThread, SIGNAL(finished()), radio->txaudio, SLOT(deleteLater()));
|
||||
connect(this, SIGNAL(setupTxAudio(audioSetup)), radio->txaudio, SLOT(init(audioSetup)));
|
||||
connect(radio->txAudioThread, SIGNAL(finished()), radio->txaudio, SLOT(deleteLater()));
|
||||
|
||||
// Not sure how we make this work in QT5.9?
|
||||
// Not sure how we make this work in QT5.9?
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(radio->txaudio, [=]() {
|
||||
radio->txaudio->init(radio->txAudioSetup);
|
||||
}, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(radio->txaudio, [=]() {
|
||||
radio->txaudio->init(radio->txAudioSetup);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
emit setupTxAudio(radio->txAudioSetup);
|
||||
#warning "QT 5.9 is not fully supported multiple rigs will NOT work!"
|
||||
emit setupTxAudio(radio->txAudioSetup);
|
||||
#warning "QT 5.9 is not fully supported multiple rigs will NOT work!"
|
||||
#endif
|
||||
hasTxAudio = datagram.senderAddress();
|
||||
|
||||
connect(this, SIGNAL(haveAudioData(audioPacket)), radio->txaudio, SLOT(incomingAudio(audioPacket)));
|
||||
hasTxAudio = datagram.senderAddress();
|
||||
|
||||
connect(this, SIGNAL(haveAudioData(audioPacket)), radio->txaudio, SLOT(incomingAudio(audioPacket)));
|
||||
}
|
||||
}
|
||||
if ((!memcmp(radio->guid, current->guid, GUIDLEN) || config->rigs.size() == 1) && radio->rxaudio == Q_NULLPTR && !config->lan)
|
||||
{
|
||||
|
@ -431,27 +432,30 @@ void udpServer::controlReceived()
|
|||
qCritical(logAudio()) << "Unsupported Receive Audio Handler selected!";
|
||||
}
|
||||
|
||||
if (radio->rxaudio != Q_NULLPTR)
|
||||
{
|
||||
|
||||
radio->rxAudioThread = new QThread(this);
|
||||
radio->rxAudioThread->setObjectName("rxAudio()");
|
||||
radio->rxAudioThread = new QThread(this);
|
||||
radio->rxAudioThread->setObjectName("rxAudio()");
|
||||
|
||||
radio->rxaudio->moveToThread(radio->rxAudioThread);
|
||||
radio->rxaudio->moveToThread(radio->rxAudioThread);
|
||||
|
||||
radio->rxAudioThread->start(QThread::TimeCriticalPriority);
|
||||
radio->rxAudioThread->start(QThread::TimeCriticalPriority);
|
||||
|
||||
connect(radio->rxAudioThread, SIGNAL(finished()), radio->rxaudio, SLOT(deleteLater()));
|
||||
connect(radio->rxaudio, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket)));
|
||||
connect(radio->rxAudioThread, SIGNAL(finished()), radio->rxaudio, SLOT(deleteLater()));
|
||||
connect(radio->rxaudio, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket)));
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
|
||||
QMetaObject::invokeMethod(radio->rxaudio, [=]() {
|
||||
radio->rxaudio->init(radio->rxAudioSetup);
|
||||
}, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(radio->rxaudio, [=]() {
|
||||
radio->rxaudio->init(radio->rxAudioSetup);
|
||||
}, Qt::QueuedConnection);
|
||||
#else
|
||||
//#warning "QT 5.9 is not fully supported multiple rigs will NOT work!"
|
||||
connect(this, SIGNAL(setupRxAudio(audioSetup)), radio->rxaudio, SLOT(init(audioSetup)));
|
||||
setupRxAudio(radio->rxAudioSetup);
|
||||
//#warning "QT 5.9 is not fully supported multiple rigs will NOT work!"
|
||||
connect(this, SIGNAL(setupRxAudio(audioSetup)), radio->rxaudio, SLOT(init(audioSetup)));
|
||||
setupRxAudio(radio->rxAudioSetup);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -806,7 +810,7 @@ void udpServer::commonReceived(QList<CLIENT*>* l, CLIENT* current, QByteArray r)
|
|||
{
|
||||
control_packet_t in = (control_packet_t)r.constData();
|
||||
if (in->type == 0x03) {
|
||||
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Received 'are you there'";
|
||||
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Received 'Are you there'";
|
||||
current->remoteId = in->sentid;
|
||||
sendControl(current, 0x04, in->seq);
|
||||
} // This is This is "Are you ready" in response to "I am here".
|
||||
|
@ -1283,7 +1287,7 @@ void udpServer::sendCapabilities(CLIENT* c)
|
|||
s.data.append(QByteArray::fromRawData((const char*)r.packet, sizeof(r)));
|
||||
}
|
||||
|
||||
p.len = sizeof(p)+s.data.length();
|
||||
p.len = (quint32)sizeof(p)+s.data.length();
|
||||
p.payloadsize = qToBigEndian((quint16)(sizeof(p) + s.data.length() - 0x10));
|
||||
|
||||
s.data.insert(0,QByteArray::fromRawData((const char*)p.packet, sizeof(p)));
|
||||
|
@ -1688,7 +1692,7 @@ void udpServer::receiveAudioData(const audioPacket& d)
|
|||
if (client != Q_NULLPTR && client->connected && (!memcmp(client->guid, guid, GUIDLEN) || config->rigs.size()== 1)) {
|
||||
audio_packet p;
|
||||
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
|
||||
p.len = sizeof(p) + partial.length();
|
||||
p.len = (quint32)sizeof(p) + partial.length();
|
||||
p.sentid = client->myId;
|
||||
p.rcvdid = client->remoteId;
|
||||
p.ident = 0x0080; // audio is always this?
|
||||
|
@ -1823,7 +1827,7 @@ void udpServer::sendRetransmitRequest(CLIENT* c)
|
|||
{
|
||||
qInfo(logUdp()) << this->metaObject()->className() << ": sending request for multiple missing packets : " << missingSeqs.toHex();
|
||||
|
||||
p.len = sizeof(p) + missingSeqs.size();
|
||||
p.len = (quint32)sizeof(p) + missingSeqs.size();
|
||||
missingSeqs.insert(0, p.packet, sizeof(p));
|
||||
|
||||
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
#ifndef usbController_H
|
||||
#define usbController_H
|
||||
|
||||
#include <iostream>
|
||||
#include <QThread>
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QRect>
|
||||
#include <QGraphicsTextItem>
|
||||
#include <QSpinBox>
|
||||
#include <QColor>
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QIODevice>
|
||||
#include <QtEndian>
|
||||
#include <QUuid>
|
||||
#include <QLabel>
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
#include <QImageWriter>
|
||||
#include <QBuffer>
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
#include <memory>
|
||||
|
||||
|
||||
#if defined(USB_CONTROLLER) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
||||
#include <QGamepad>
|
||||
#endif
|
||||
|
||||
#if defined(USB_CONTROLLER)
|
||||
#ifndef Q_OS_WIN
|
||||
#include "hidapi/hidapi.h"
|
||||
#else
|
||||
#include "hidapi.h"
|
||||
#endif
|
||||
|
||||
#ifdef HID_API_VERSION_MAJOR
|
||||
#ifndef HID_API_MAKE_VERSION
|
||||
#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
|
||||
#endif
|
||||
#ifndef HID_API_VERSION
|
||||
#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
#include <hidapi/hidapi_darwin.h>
|
||||
#endif
|
||||
|
||||
#if defined(USING_HIDAPI_LIBUSB) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
#include <hidapi_libusb.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Include these so we have the various enums
|
||||
#include "rigidentities.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define HIDDATALENGTH 64
|
||||
#define MAX_STR 255
|
||||
|
||||
struct USBTYPE {
|
||||
USBTYPE() {}
|
||||
USBTYPE(usbDeviceType model,quint32 manufacturerId, quint32 productId , quint32 usage, quint32 usagePage, int buttons, int cols, int knobs, int leds, int maxPayload, int iconSize) :
|
||||
model(model), manufacturerId(manufacturerId), productId(productId), usage(usage), usagePage(usagePage), buttons(buttons), cols(cols), knobs(knobs), leds(leds), maxPayload(maxPayload), iconSize(iconSize) {}
|
||||
|
||||
usbDeviceType model = usbNone;
|
||||
quint32 manufacturerId=0;
|
||||
quint32 productId=0;
|
||||
quint32 usage=0;
|
||||
quint32 usagePage=0;
|
||||
int buttons=0; // How many buttons
|
||||
int cols=0; // How many columns of buttons
|
||||
int knobs=0; // How many knobs
|
||||
int leds=0; // how many leds
|
||||
int maxPayload=0; // Max allowed payload
|
||||
int iconSize=0;
|
||||
};
|
||||
|
||||
|
||||
struct KNOBVALUE {
|
||||
int value=0;
|
||||
int previous=0;
|
||||
quint8 send=0;
|
||||
qint64 lastChanged=0;
|
||||
QString name="";
|
||||
};
|
||||
|
||||
struct USBDEVICE {
|
||||
USBDEVICE() {}
|
||||
USBDEVICE(USBTYPE type) : type(type) {}
|
||||
USBTYPE type;
|
||||
bool detected = false;
|
||||
bool remove = false;
|
||||
bool connected = false;
|
||||
bool uiCreated = false;
|
||||
bool disabled = false;
|
||||
quint8 speed=2;
|
||||
quint8 timeout=30;
|
||||
quint8 brightness=2;
|
||||
quint8 orientation=0;
|
||||
QColor color=Qt::darkGray;
|
||||
cmds lcd=cmdNone;
|
||||
|
||||
hid_device* handle = NULL;
|
||||
QString product = "";
|
||||
QString manufacturer = "";
|
||||
QString serial = "<none>";
|
||||
QString deviceId = "";
|
||||
QString path = "";
|
||||
int sensitivity = 1;
|
||||
unsigned char jogpos=0;
|
||||
unsigned char shutpos=0;
|
||||
unsigned char shutMult = 0;
|
||||
int jogCounter = 0;
|
||||
quint32 buttons = 0;
|
||||
quint32 knobs = 0;
|
||||
QList<KNOBVALUE> knobValues;
|
||||
|
||||
QTime lastusbController = QTime::currentTime();
|
||||
QByteArray lastData = QByteArray(8,0x0);
|
||||
unsigned char lastDialPos=0;
|
||||
QUuid uuid;
|
||||
QLabel *message;
|
||||
int pages=1;
|
||||
int currentPage=0;
|
||||
QGraphicsScene* scene = Q_NULLPTR;
|
||||
QSpinBox* pageSpin = Q_NULLPTR;
|
||||
QImage image;
|
||||
quint8 ledStatus=0x07;
|
||||
};
|
||||
|
||||
struct COMMAND {
|
||||
COMMAND() {}
|
||||
COMMAND(int index, QString text, usbCommandType cmdType, int command, int value) :
|
||||
index(index), text(text), cmdType(cmdType), command(command), value(value) {}
|
||||
COMMAND(int index, QString text, usbCommandType cmdType, int command, unsigned char suffix) :
|
||||
index(index), text(text), cmdType(cmdType), command(command), suffix(suffix) {}
|
||||
COMMAND(int index, QString text, usbCommandType cmdType, int command, int getCommand, unsigned char suffix) :
|
||||
index(index), text(text), cmdType(cmdType), command(command), getCommand(getCommand), suffix(suffix) {}
|
||||
COMMAND(int index, QString text, usbCommandType cmdType, int command, availableBands band) :
|
||||
index(index), text(text), cmdType(cmdType), command(command), band(band) {}
|
||||
COMMAND(int index, QString text, usbCommandType cmdType, int command, mode_kind mode) :
|
||||
index(index), text(text), cmdType(cmdType), command(command), mode(mode) {}
|
||||
|
||||
int index=0;
|
||||
QString text;
|
||||
usbCommandType cmdType = commandButton;
|
||||
int command=0;
|
||||
int getCommand=0;
|
||||
unsigned char suffix=0x0;
|
||||
int value=0;
|
||||
availableBands band=bandGen;
|
||||
mode_kind mode=modeLSB;
|
||||
};
|
||||
|
||||
struct BUTTON {
|
||||
BUTTON() {}
|
||||
|
||||
BUTTON(usbDeviceType dev, int num, QRect pos, const QColor textColour, COMMAND* on, COMMAND* off, bool graphics=false, int led=0) :
|
||||
dev(dev), num(num), name(""), pos(pos), textColour(textColour), onCommand(on), offCommand(off), on(onCommand->text), off(offCommand->text), graphics(graphics), led(led){}
|
||||
BUTTON(usbDeviceType dev, QString name, QRect pos, const QColor textColour, COMMAND* on, COMMAND* off) :
|
||||
dev(dev), num(-1), name(name), pos(pos), textColour(textColour), onCommand(on), offCommand(off), on(onCommand->text), off(offCommand->text) {}
|
||||
|
||||
usbDeviceType dev;
|
||||
USBDEVICE* parent = Q_NULLPTR;
|
||||
int page=1;
|
||||
int num;
|
||||
QString name;
|
||||
QRect pos;
|
||||
QColor textColour;
|
||||
const COMMAND* onCommand = Q_NULLPTR;
|
||||
const COMMAND* offCommand = Q_NULLPTR;
|
||||
QGraphicsRectItem* bgRect = Q_NULLPTR;
|
||||
QGraphicsTextItem* text = Q_NULLPTR;
|
||||
QString on;
|
||||
QString off;
|
||||
QString path;
|
||||
QColor backgroundOn = Qt::lightGray;
|
||||
QColor backgroundOff = Qt::blue;
|
||||
QString iconName = "";
|
||||
QImage* icon = Q_NULLPTR;
|
||||
bool toggle = false;
|
||||
bool isOn = false;
|
||||
bool graphics = false;
|
||||
int led = 0;
|
||||
};
|
||||
|
||||
|
||||
struct KNOB {
|
||||
KNOB() {}
|
||||
|
||||
KNOB(usbDeviceType dev, int num, QRect pos, const QColor textColour, COMMAND* command) :
|
||||
dev(dev), num(num), name(""), pos(pos), textColour(textColour), command(command), cmd(command->text) {}
|
||||
|
||||
usbDeviceType dev;
|
||||
USBDEVICE* parent = Q_NULLPTR;
|
||||
int page=1;
|
||||
int num;
|
||||
QString name;
|
||||
QRect pos;
|
||||
QColor textColour;
|
||||
const COMMAND* command = Q_NULLPTR;
|
||||
QGraphicsTextItem* text = Q_NULLPTR;
|
||||
QString cmd;
|
||||
QString path;
|
||||
};
|
||||
|
||||
|
||||
typedef QMap<QString,USBDEVICE> usbDevMap;
|
||||
|
||||
|
||||
#if defined(USB_CONTROLLER)
|
||||
class usbController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
usbController();
|
||||
~usbController();
|
||||
bool hotPlugEvent(const QByteArray & eventType, void * message, long * result);
|
||||
|
||||
public slots:
|
||||
void init(QMutex* mut,usbDevMap* prefs ,QVector<BUTTON>* buts,QVector<KNOB>* knobs);
|
||||
void run();
|
||||
void runTimer();
|
||||
void receivePTTStatus(bool on);
|
||||
void receiveLevel(cmds cmd, unsigned char level);
|
||||
void programPages(USBDEVICE* dev, int pages);
|
||||
void programDisable(USBDEVICE* dev, bool disabled);
|
||||
|
||||
void sendRequest(USBDEVICE *dev, usbFeatureType feature, int val=0, QString text="", QImage* img=Q_NULLPTR, QColor* color=Q_NULLPTR);
|
||||
void sendToLCD(QImage *img);
|
||||
void backupController(USBDEVICE* dev, QString file);
|
||||
void restoreController(USBDEVICE* dev, QString file);
|
||||
|
||||
signals:
|
||||
void jogPlus();
|
||||
void jogMinus();
|
||||
void sendJog(int counter);
|
||||
void doShuttle(bool plus, quint8 level);
|
||||
void setBand(int band);
|
||||
void button(const COMMAND* cmd);
|
||||
void initUI(usbDevMap* devs, QVector<BUTTON>* but, QVector<KNOB>* kb, QVector<COMMAND>* cmd, QMutex* mut);
|
||||
void newDevice(USBDEVICE* dev);
|
||||
void removeDevice(USBDEVICE* dev);
|
||||
void setConnected(USBDEVICE* dev);
|
||||
void changePage(USBDEVICE* dev, int page);
|
||||
|
||||
private:
|
||||
void loadButtons();
|
||||
void loadKnobs();
|
||||
void loadCommands();
|
||||
|
||||
|
||||
int hidStatus = 1;
|
||||
bool isOpen=false;
|
||||
int devicesConnected=0;
|
||||
QVector<BUTTON>* buttonList;
|
||||
QVector<KNOB>* knobList;
|
||||
|
||||
QVector<BUTTON> defaultButtons;
|
||||
QVector<KNOB> defaultKnobs;
|
||||
QVector<USBTYPE> knownDevices;
|
||||
QVector<COMMAND> commands;
|
||||
usbDevMap* devices;
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
||||
QGamepad* gamepad=Q_NULLPTR;
|
||||
#endif
|
||||
void buttonState(QString but, bool val);
|
||||
void buttonState(QString but, double val);
|
||||
QColor currentColour;
|
||||
|
||||
QMutex* mutex=Q_NULLPTR;
|
||||
COMMAND sendCommand;
|
||||
|
||||
QTimer* dataTimer = Q_NULLPTR;
|
||||
protected:
|
||||
};
|
||||
|
||||
|
||||
class usbControllerDev : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
3597
wfmain.cpp
367
wfmain.h
|
@ -13,13 +13,17 @@
|
|||
#include <QTimer>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QThread>
|
||||
#include <QMetaType>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QColorDialog>
|
||||
#include <QColor>
|
||||
#include <QMap>
|
||||
|
||||
#include "logcategories.h"
|
||||
#include "wfviewtypes.h"
|
||||
#include "prefs.h"
|
||||
#include "commhandler.h"
|
||||
#include "rigcommander.h"
|
||||
#include "rigstate.h"
|
||||
|
@ -32,6 +36,7 @@
|
|||
#include "repeatersetup.h"
|
||||
#include "satellitesetup.h"
|
||||
#include "transceiveradjustments.h"
|
||||
#include "cwsender.h"
|
||||
#include "udpserver.h"
|
||||
#include "qledlabel.h"
|
||||
#include "rigctld.h"
|
||||
|
@ -39,9 +44,14 @@
|
|||
#include "selectradio.h"
|
||||
#include "colorprefs.h"
|
||||
#include "loggingwindow.h"
|
||||
#include "cluster.h"
|
||||
#include "audiodevices.h"
|
||||
#include "sidebandchooser.h"
|
||||
|
||||
#include <qcustomplot.h>
|
||||
#include <qserialportinfo.h>
|
||||
#include "usbcontroller.h"
|
||||
#include "controllersetup.h"
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
|
@ -53,6 +63,18 @@
|
|||
#include "rtaudio/RtAudio.h"
|
||||
#endif
|
||||
|
||||
#ifdef USB_CONTROLLER
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#include <dbt.h>
|
||||
#define USB_HOTPLUG
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#include <QSocketNotifier>
|
||||
#include <libudev.h>
|
||||
#define USB_HOTPLUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define numColorPresetsTotal (5)
|
||||
|
||||
namespace Ui {
|
||||
|
@ -69,22 +91,40 @@ public:
|
|||
static void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||
void handleLogText(QString text);
|
||||
|
||||
#ifdef USB_HOTPLUG
|
||||
#if defined(Q_OS_WIN)
|
||||
protected:
|
||||
virtual bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result);
|
||||
#elif defined(Q_OS_LINUX)
|
||||
private slots:
|
||||
void uDevEvent();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
signals:
|
||||
// Signal levels received to other parts of wfview
|
||||
void sendLevel(cmds cmd, unsigned char level);
|
||||
void usbHotplug();
|
||||
// Basic to rig:
|
||||
void setCIVAddr(unsigned char newRigCIVAddr);
|
||||
void setRigID(unsigned char rigID);
|
||||
void setRTSforPTT(bool enabled);
|
||||
|
||||
// Power
|
||||
|
||||
void sendPowerOn();
|
||||
void sendPowerOff();
|
||||
|
||||
// Frequency, mode, band:
|
||||
void getFrequency();
|
||||
void getFrequency(unsigned char);
|
||||
void setFrequency(unsigned char vfo, freqt freq);
|
||||
void getMode();
|
||||
void setMode(unsigned char modeIndex, unsigned char modeFilter);
|
||||
void setMode(mode_info);
|
||||
void selectVFO(vfo_t vfo);
|
||||
void sendVFOSwap();
|
||||
void sendVFOEqualAB();
|
||||
void sendVFOEqualMS();
|
||||
void setDataMode(bool dataOn, unsigned char filter);
|
||||
void getDataMode();
|
||||
void getModInput(bool dataOn);
|
||||
|
@ -98,10 +138,20 @@ signals:
|
|||
|
||||
// Repeater:
|
||||
void getDuplexMode();
|
||||
void setQuickSplit(bool qsOn);
|
||||
void getTone();
|
||||
void getTSQL();
|
||||
void getDTCS();
|
||||
void getRptAccessMode();
|
||||
void setRepeaterAccessMode(rptrAccessData_t rd);
|
||||
void setTone(rptrTone_t t);
|
||||
void setTSQL(rptrTone_t t);
|
||||
void getToneEnabled();
|
||||
void getTSQLEnabled();
|
||||
void setToneEnabled(bool enabled);
|
||||
void setTSQLEnabled(bool enabled);
|
||||
void setRptDuplexOffset(freqt f);
|
||||
void getRptDuplexOffset();
|
||||
|
||||
// Level get:
|
||||
void getLevels(); // get all levels
|
||||
|
@ -115,6 +165,25 @@ signals:
|
|||
void getMicGain();
|
||||
void getSpectrumRefLevel();
|
||||
void getModInputLevel(rigInput input);
|
||||
void getMeters(meterKind meter);
|
||||
void getPassband();
|
||||
void getVoxGain();
|
||||
void getAntiVoxGain();
|
||||
void getMonitorGain();
|
||||
void getNBLevel();
|
||||
void getNRLevel();
|
||||
void getCompLevel();
|
||||
void getCwPitch();
|
||||
|
||||
void getVox();
|
||||
void getMonitor();
|
||||
void getCompressor();
|
||||
void getNB();
|
||||
void getNR();
|
||||
|
||||
void getDashRatio();
|
||||
void getPskTone();
|
||||
void getRttyMark();
|
||||
|
||||
// Level set:
|
||||
void setRfGain(unsigned char level);
|
||||
|
@ -123,16 +192,25 @@ signals:
|
|||
void setIFShift(unsigned char level);
|
||||
void setTPBFInner(unsigned char level);
|
||||
void setTPBFOuter(unsigned char level);
|
||||
|
||||
|
||||
void setIFShiftWindow(unsigned char level);
|
||||
void setTPBFInnerWindow(unsigned char level);
|
||||
void setTPBFOuterWindow(unsigned char level);
|
||||
void setMicGain(unsigned char);
|
||||
void setCompLevel(unsigned char);
|
||||
void setTxPower(unsigned char);
|
||||
void setMonitorLevel(unsigned char);
|
||||
void setMonitorGain(unsigned char);
|
||||
void setVoxGain(unsigned char);
|
||||
void setAntiVoxGain(unsigned char);
|
||||
void setNBLevel(unsigned char level);
|
||||
void setNRLevel(unsigned char level);
|
||||
|
||||
void setVox(bool en);
|
||||
void setMonitor(bool en);
|
||||
void setCompressor(bool en);
|
||||
void setNB(bool en);
|
||||
void setNR(bool en);
|
||||
|
||||
void setSpectrumRefLevel(int);
|
||||
|
||||
void setModLevel(rigInput input, unsigned char level);
|
||||
|
@ -142,12 +220,11 @@ signals:
|
|||
void setUSBGain(unsigned char level);
|
||||
void setLANGain(unsigned char level);
|
||||
|
||||
void getMeters(meterKind meter);
|
||||
|
||||
void setPassband(quint16 pass);
|
||||
|
||||
// PTT, ATU, ATT, Antenna, Preamp:
|
||||
void getPTT();
|
||||
void setPTT(bool pttOn);
|
||||
void setPTT(bool pttOn);
|
||||
void getAttenuator();
|
||||
void getPreamp();
|
||||
void getAntenna();
|
||||
|
@ -158,6 +235,16 @@ signals:
|
|||
void setATU(bool atuEnabled);
|
||||
void getATUStatus();
|
||||
|
||||
// CW Keying:
|
||||
void sendCW(QString message);
|
||||
void stopCW();
|
||||
void getKeySpeed();
|
||||
void setKeySpeed(unsigned char wpm);
|
||||
void setCwPitch(unsigned char pitch);
|
||||
void setDashRatio(unsigned char ratio);
|
||||
void setCWBreakMode(unsigned char breakMode);
|
||||
void getCWBreakMode();
|
||||
|
||||
// Time and date:
|
||||
void setTime(timekind t);
|
||||
void setDate(datekind d);
|
||||
|
@ -185,10 +272,24 @@ signals:
|
|||
void sendChangeLatency(quint16 latency);
|
||||
void initServer();
|
||||
void sendRigCaps(rigCapabilities caps);
|
||||
void openShuttle();
|
||||
void requestRigState();
|
||||
void stateUpdated();
|
||||
void initUsbController(QMutex* mutex,usbDevMap* devs ,QVector<BUTTON>* buts,QVector<KNOB>* knobs);
|
||||
void setClusterUdpPort(int port);
|
||||
void setClusterEnableUdp(bool udp);
|
||||
void setClusterEnableTcp(bool tcp);
|
||||
void setClusterServerName(QString name);
|
||||
void setClusterTcpPort(int port);
|
||||
void setClusterUserName(QString name);
|
||||
void setClusterPassword(QString pass);
|
||||
void setClusterTimeout(int timeout);
|
||||
void setClusterSkimmerSpots(bool enable);
|
||||
void setFrequencyRange(double low, double high);
|
||||
void sendControllerRequest(USBDEVICE* dev, usbFeatureType request, int val=0, QString text="", QImage* img=Q_NULLPTR, QColor* color=Q_NULLPTR);
|
||||
|
||||
private slots:
|
||||
void setAudioDevicesUI();
|
||||
void updateSizes(int tabIndex);
|
||||
void shortcutF1();
|
||||
void shortcutF2();
|
||||
|
@ -213,6 +314,8 @@ private slots:
|
|||
void shortcutSlash();
|
||||
void shortcutMinus();
|
||||
void shortcutPlus();
|
||||
void shortcutStepMinus();
|
||||
void shortcutStepPlus();
|
||||
void shortcutShiftMinus();
|
||||
void shortcutShiftPlus();
|
||||
void shortcutControlMinus();
|
||||
|
@ -226,12 +329,15 @@ private slots:
|
|||
|
||||
void handlePttLimit(); // hit at 3 min transmit length
|
||||
|
||||
void doShuttle(bool up, unsigned char level);
|
||||
|
||||
void receiveCommReady();
|
||||
void receiveFreq(freqt);
|
||||
void receiveMode(unsigned char mode, unsigned char filter);
|
||||
void receiveSpectrumData(QByteArray spectrum, double startFreq, double endFreq);
|
||||
void receiveSpectrumMode(spectrumMode spectMode);
|
||||
void receiveSpectrumSpan(freqt freqspan, bool isSub);
|
||||
void handleScopeOutOfRange(bool outOfRange);
|
||||
void receivePTTstatus(bool pttOn);
|
||||
void receiveDataModeStatus(bool dataOn);
|
||||
void receiveBandStackReg(freqt f, char mode, char filter, bool dataOn); // freq, mode, (filter,) datamode
|
||||
|
@ -239,8 +345,18 @@ private slots:
|
|||
void receiveRITValue(int ritValHz);
|
||||
void receiveModInput(rigInput input, bool dataOn);
|
||||
//void receiveDuplexMode(duplexMode dm);
|
||||
|
||||
|
||||
void receivePassband(quint16 pass);
|
||||
void receiveMonitorGain(unsigned char pass);
|
||||
void receiveNBLevel(unsigned char pass);
|
||||
void receiveNRLevel(unsigned char pass);
|
||||
void receiveCwPitch(unsigned char pitch);
|
||||
void receiveTPBFInner(unsigned char level);
|
||||
void receiveTPBFOuter(unsigned char level);
|
||||
void receiveVox(bool en);
|
||||
void receiveMonitor(bool en);
|
||||
void receiveComp(bool en);
|
||||
void receiveNB(bool en);
|
||||
void receiveNR(bool en);
|
||||
|
||||
// Levels:
|
||||
void receiveRfGain(unsigned char level);
|
||||
|
@ -256,7 +372,6 @@ private slots:
|
|||
void receiveTxPower(unsigned char power);
|
||||
void receiveMicGain(unsigned char gain);
|
||||
void receiveCompLevel(unsigned char compLevel);
|
||||
void receiveMonitorGain(unsigned char monitorGain);
|
||||
void receiveVoxGain(unsigned char voxGain);
|
||||
void receiveAntiVoxGain(unsigned char antiVoxGain);
|
||||
void receiveSpectrumRefLevel(int level);
|
||||
|
@ -278,10 +393,12 @@ private slots:
|
|||
void receiveAntennaSel(unsigned char ant, bool rx);
|
||||
void receiveRigID(rigCapabilities rigCaps);
|
||||
void receiveFoundRigID(rigCapabilities rigCaps);
|
||||
void receiveSerialPortError(QString port, QString errorText);
|
||||
void receivePortError(errorType err);
|
||||
void receiveStatusUpdate(networkStatus status);
|
||||
void receiveNetworkAudioLevels(networkAudioLevels l);
|
||||
void handlePlotClick(QMouseEvent *);
|
||||
void handlePlotMouseRelease(QMouseEvent *);
|
||||
void handlePlotMouseMove(QMouseEvent *);
|
||||
void handlePlotDoubleClick(QMouseEvent *);
|
||||
void handleWFClick(QMouseEvent *);
|
||||
void handleWFDoubleClick(QMouseEvent *);
|
||||
|
@ -292,10 +409,20 @@ private slots:
|
|||
void receiveBaudRate(quint32 baudrate);
|
||||
void radioSelection(QList<radio_cap_packet> radios);
|
||||
|
||||
|
||||
// Added for RC28/Shuttle support
|
||||
void pttToggle(bool);
|
||||
void stepUp();
|
||||
void stepDown();
|
||||
void changeFrequency(int value);
|
||||
void setBand(int band);
|
||||
|
||||
void setRadioTimeDateSend();
|
||||
void logCheck();
|
||||
void setDebugLogging(bool debugModeOn);
|
||||
|
||||
void buttonControl(const COMMAND* cmd);
|
||||
|
||||
|
||||
// void on_getFreqBtn_clicked();
|
||||
|
||||
|
@ -328,6 +455,11 @@ private slots:
|
|||
void on_fCEbtn_clicked();
|
||||
|
||||
void on_fEnterBtn_clicked();
|
||||
void on_usbControllerBtn_clicked();
|
||||
|
||||
void on_usbControllersResetBtn_clicked();
|
||||
|
||||
void on_enableUsbChk_clicked(bool checked);
|
||||
|
||||
void on_scopeBWCombo_currentIndexChanged(int index);
|
||||
|
||||
|
@ -397,6 +529,8 @@ private slots:
|
|||
|
||||
void on_passwordTxt_textChanged(QString text);
|
||||
|
||||
void on_audioDuplexCombo_currentIndexChanged(int value);
|
||||
|
||||
void on_audioOutputCombo_currentIndexChanged(int value);
|
||||
|
||||
void on_audioInputCombo_currentIndexChanged(int value);
|
||||
|
@ -413,11 +547,11 @@ private slots:
|
|||
|
||||
void on_audioTXCodecCombo_currentIndexChanged(int value);
|
||||
|
||||
void on_audioSampleRateCombo_currentIndexChanged(QString text);
|
||||
void on_audioSampleRateCombo_currentIndexChanged(int value);
|
||||
|
||||
void on_vspCombo_currentIndexChanged(int value);
|
||||
|
||||
void on_scopeEnableWFBtn_clicked(bool checked);
|
||||
void on_scopeEnableWFBtn_stateChanged(int state);
|
||||
|
||||
void on_sqlSlider_valueChanged(int value);
|
||||
|
||||
|
@ -451,7 +585,7 @@ private slots:
|
|||
|
||||
void on_tuningStepCombo_currentIndexChanged(int index);
|
||||
|
||||
void on_serialDeviceListCombo_activated(const QString &arg1);
|
||||
void on_serialDeviceListCombo_textActivated(const QString &arg1);
|
||||
|
||||
void on_rptSetupBtn_clicked();
|
||||
|
||||
|
@ -497,8 +631,6 @@ private slots:
|
|||
|
||||
void on_wfLengthSlider_valueChanged(int value);
|
||||
|
||||
void on_pollingBtn_clicked();
|
||||
|
||||
void on_wfAntiAliasChk_clicked(bool checked);
|
||||
|
||||
void on_wfInterpolateChk_clicked(bool checked);
|
||||
|
@ -609,6 +741,14 @@ private slots:
|
|||
|
||||
void on_colorEditTuningLine_editingFinished();
|
||||
|
||||
void on_colorSetBtnPassband_clicked();
|
||||
|
||||
void on_colorEditPassband_editingFinished();
|
||||
|
||||
void on_colorSetBtnPBT_clicked();
|
||||
|
||||
void on_colorEditPBT_editingFinished();
|
||||
|
||||
void on_colorSetBtnMeterLevel_clicked();
|
||||
|
||||
void on_colorEditMeterLevel_editingFinished();
|
||||
|
@ -625,6 +765,10 @@ private slots:
|
|||
|
||||
void on_colorEditMeterText_editingFinished();
|
||||
|
||||
void on_colorSetBtnClusterSpots_clicked();
|
||||
|
||||
void on_colorEditClusterSpots_editingFinished();
|
||||
|
||||
void on_colorRenamePresetBtn_clicked();
|
||||
|
||||
void on_colorRevertPresetBtn_clicked();
|
||||
|
@ -645,6 +789,33 @@ private slots:
|
|||
|
||||
void on_customEdgeBtn_clicked();
|
||||
|
||||
void on_clusterUdpEnable_clicked(bool enable);
|
||||
void on_clusterTcpEnable_clicked(bool enable);
|
||||
void on_clusterUdpPortLineEdit_editingFinished();
|
||||
void on_clusterServerNameCombo_currentTextChanged(QString text);
|
||||
void on_clusterServerNameCombo_currentIndexChanged(int index);
|
||||
void on_clusterTcpPortLineEdit_editingFinished();
|
||||
void on_clusterUsernameLineEdit_editingFinished();
|
||||
void on_clusterPasswordLineEdit_editingFinished();
|
||||
void on_clusterTimeoutLineEdit_editingFinished();
|
||||
void on_clusterPopOutBtn_clicked();
|
||||
void on_clusterSkimmerSpotsEnable_clicked(bool enable);
|
||||
|
||||
void on_clickDragTuningEnableChk_clicked(bool checked);
|
||||
|
||||
void receiveClusterOutput(QString text);
|
||||
void receiveSpots(QList<spotData> spots);
|
||||
|
||||
void on_autoPollBtn_clicked(bool checked);
|
||||
|
||||
void on_manualPollBtn_clicked(bool checked);
|
||||
|
||||
void on_pollTimeMsSpin_valueChanged(int arg1);
|
||||
|
||||
void on_autoSSBchk_clicked(bool checked);
|
||||
|
||||
void on_cwButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::wfmain *ui;
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
@ -665,6 +836,8 @@ private:
|
|||
QCustomPlot *plot; // line plot
|
||||
QCustomPlot *wf; // waterfall image
|
||||
QCPItemLine * freqIndicatorLine;
|
||||
QCPItemRect* passbandIndicator;
|
||||
QCPItemRect* pbtIndicator;
|
||||
void setAppTheme(bool isCustom);
|
||||
void prepareWf();
|
||||
void prepareWf(unsigned int wfLength);
|
||||
|
@ -719,6 +892,17 @@ private:
|
|||
QShortcut *keyF;
|
||||
QShortcut *keyM;
|
||||
|
||||
QShortcut *keyH;
|
||||
QShortcut *keyK; // alternate +
|
||||
QShortcut *keyJ; // alternate -
|
||||
QShortcut *keyL;
|
||||
|
||||
QShortcut *keyShiftK;
|
||||
QShortcut *keyShiftJ;
|
||||
|
||||
QShortcut *keyControlK;
|
||||
QShortcut *keyControlJ;
|
||||
|
||||
QShortcut *keyDebug;
|
||||
|
||||
|
||||
|
@ -730,7 +914,8 @@ private:
|
|||
QTimer * delayedCommand;
|
||||
QTimer * pttTimer;
|
||||
uint16_t loopTickCounter;
|
||||
uint16_t slowCmdNum;
|
||||
uint16_t slowCmdNum=0;
|
||||
uint16_t rapidCmdNum=0;
|
||||
|
||||
void setupPlots();
|
||||
void makeRig();
|
||||
|
@ -742,8 +927,8 @@ private:
|
|||
void setupMainUI();
|
||||
void setUIToPrefs();
|
||||
void setSerialDevicesUI();
|
||||
void setAudioDevicesUI();
|
||||
void setServerToPrefs();
|
||||
void setupUsbControllerDevice();
|
||||
void setInitialTiming();
|
||||
void getSettingsFilePath(QString settingsFile);
|
||||
|
||||
|
@ -761,9 +946,6 @@ private:
|
|||
quint16 wfLength;
|
||||
bool spectrumDrawLock;
|
||||
|
||||
enum underlay_t { underlayNone, underlayPeakHold, underlayPeakBuffer, underlayAverageBuffer };
|
||||
|
||||
|
||||
QByteArray spectrumPeaks;
|
||||
QVector <double> spectrumPlasmaLine;
|
||||
QVector <QByteArray> spectrumPlasma;
|
||||
|
@ -779,6 +961,10 @@ private:
|
|||
double wfCeiling = 160;
|
||||
double oldPlotFloor = -1;
|
||||
double oldPlotCeiling = 999;
|
||||
double passbandWidth = 0.0;
|
||||
|
||||
double mousePressFreq = 0.0;
|
||||
double mouseReleaseFreq = 0.0;
|
||||
|
||||
QVector <QByteArray> wfimage;
|
||||
unsigned int wfLengthMax;
|
||||
|
@ -791,51 +977,43 @@ private:
|
|||
double oldLowerFreq;
|
||||
double oldUpperFreq;
|
||||
freqt freq;
|
||||
freqt freqb;
|
||||
float tsKnobMHz;
|
||||
|
||||
unsigned char setModeVal=0;
|
||||
unsigned char setFilterVal=0;
|
||||
|
||||
enum cmds {cmdNone, cmdGetRigID, cmdGetRigCIV, cmdGetFreq, cmdSetFreq, cmdGetMode, cmdSetMode,
|
||||
cmdGetDataMode, cmdSetModeFilter, cmdSetDataModeOn, cmdSetDataModeOff, cmdGetRitEnabled, cmdGetRitValue,
|
||||
cmdSpecOn, cmdSpecOff, cmdDispEnable, cmdDispDisable, cmdGetRxGain, cmdSetRxRfGain, cmdGetAfGain, cmdSetAfGain,
|
||||
cmdGetSql, cmdSetSql, cmdGetIFShift, cmdSetIFShift, cmdGetTPBFInner, cmdSetTPBFInner,
|
||||
cmdGetTPBFOuter, cmdSetTPBFOuter, cmdGetATUStatus,
|
||||
cmdSetATU, cmdStartATU, cmdGetSpectrumMode,
|
||||
cmdGetSpectrumSpan, cmdScopeCenterMode, cmdScopeFixedMode, cmdGetPTT, cmdSetPTT,
|
||||
cmdGetTxPower, cmdSetTxPower, cmdGetMicGain, cmdSetMicGain, cmdSetModLevel,
|
||||
cmdGetSpectrumRefLevel, cmdGetDuplexMode, cmdGetModInput, cmdGetModDataInput,
|
||||
cmdGetCurrentModLevel, cmdStartRegularPolling, cmdStopRegularPolling, cmdQueNormalSpeed,
|
||||
cmdGetVdMeter, cmdGetIdMeter, cmdGetSMeter, cmdGetCenterMeter, cmdGetPowerMeter,
|
||||
cmdGetSWRMeter, cmdGetALCMeter, cmdGetCompMeter, cmdGetTxRxMeter,
|
||||
cmdGetTone, cmdGetTSQL, cmdGetDTCS, cmdGetRptAccessMode, cmdGetPreamp, cmdGetAttenuator, cmdGetAntenna,
|
||||
cmdSetTime, cmdSetDate, cmdSetUTCOffset};
|
||||
|
||||
struct commandtype {
|
||||
cmds cmd;
|
||||
std::shared_ptr<void> data;
|
||||
};
|
||||
|
||||
std::deque <commandtype> delayedCmdQue; // rapid que for commands to the radio
|
||||
std::deque <commandtype> delayedCmdQue; // rapid commands from user interaction
|
||||
std::deque <cmds> periodicCmdQueue; // rapid que for metering
|
||||
std::deque <cmds> slowPollCmdQueue; // slow, regular checking for UI sync
|
||||
std::deque <cmds> rapidPollCmdQueue; // rapid regular polling for non-meter actions
|
||||
void doCmd(cmds cmd);
|
||||
void doCmd(commandtype cmddata);
|
||||
|
||||
bool rapidPollCmdQueueEnabled = false;
|
||||
|
||||
void issueCmd(cmds cmd, freqt f);
|
||||
void issueCmd(cmds cmd, mode_info m);
|
||||
void issueCmd(cmds cmd, vfo_t v);
|
||||
void issueCmd(cmds cmd, rptrTone_t t);
|
||||
void issueCmd(cmds cmd, rptrAccessData_t rd);
|
||||
void issueCmd(cmds cmd, timekind t);
|
||||
void issueCmd(cmds cmd, datekind d);
|
||||
void issueCmd(cmds cmd, int i);
|
||||
void issueCmd(cmds cmd, unsigned char c);
|
||||
void issueCmd(cmds cmd, char c);
|
||||
void issueCmd(cmds cmd, bool b);
|
||||
void issueCmd(cmds cmd, quint16 c);
|
||||
void issueCmd(cmds cmd, qint16 c);
|
||||
void issueCmd(cmds cmd, QString s);
|
||||
|
||||
// These commands pop_front and remove similar commands:
|
||||
void issueCmdUniquePriority(cmds cmd, bool b);
|
||||
void issueCmdUniquePriority(cmds cmd, unsigned char c);
|
||||
void issueCmdUniquePriority(cmds cmd, char c);
|
||||
void issueCmdUniquePriority(cmds cmd, freqt f);
|
||||
void issueCmdUniquePriority(cmds cmd, quint16 c);
|
||||
void issueCmdUniquePriority(cmds cmd, qint16 c);
|
||||
|
||||
void removeSimilarCommand(cmds cmd);
|
||||
|
||||
|
@ -860,40 +1038,7 @@ private:
|
|||
|
||||
colorPrefsType colorPreset[numColorPresetsTotal];
|
||||
|
||||
struct preferences {
|
||||
bool useFullScreen;
|
||||
bool useSystemTheme;
|
||||
bool drawPeaks;
|
||||
underlay_t underlayMode = underlayNone;
|
||||
int underlayBufferSize = 64;
|
||||
bool wfAntiAlias;
|
||||
bool wfInterpolate;
|
||||
QString stylesheetPath;
|
||||
unsigned char radioCIVAddr;
|
||||
bool CIVisRadioModel;
|
||||
bool forceRTSasPTT;
|
||||
QString serialPortRadio;
|
||||
quint32 serialPortBaud;
|
||||
bool enablePTT;
|
||||
bool niceTS;
|
||||
bool enableLAN;
|
||||
bool enableRigCtlD;
|
||||
quint16 rigCtlPort;
|
||||
int currentColorPresetNumber = 0;
|
||||
QString virtualSerialPort;
|
||||
unsigned char localAFgain;
|
||||
unsigned int wflength;
|
||||
int wftheme;
|
||||
int plotFloor;
|
||||
int plotCeiling;
|
||||
bool confirmExit;
|
||||
bool confirmPowerOff;
|
||||
meterKind meter2Type;
|
||||
quint16 tcpPort;
|
||||
quint8 waterfallFormat;
|
||||
audioType audioSystem;
|
||||
} prefs;
|
||||
|
||||
preferences prefs;
|
||||
preferences defPrefs;
|
||||
udpPreferences udpPrefs;
|
||||
udpPreferences udpDefPrefs;
|
||||
|
@ -955,20 +1100,31 @@ private:
|
|||
|
||||
void changeModLabelAndSlider(rigInput source);
|
||||
|
||||
// Fast command queue:
|
||||
void initPeriodicCommands();
|
||||
// Fast command queue for S-Meter:
|
||||
void insertPeriodicCommand(cmds cmd, unsigned char priority);
|
||||
void insertPeriodicCommandUnique(cmds cmd);
|
||||
void removePeriodicCommand(cmds cmd);
|
||||
// Fast command queue for other functions:
|
||||
void insertPeriodicRapidCmd(cmds cmd);
|
||||
void insertPeriodicRapidCmdUnique(cmds cmd);
|
||||
void removePeriodicRapidCmd(cmds cmd);
|
||||
|
||||
|
||||
void insertSlowPeriodicCommand(cmds cmd, unsigned char priority);
|
||||
void removeSlowPeriodicCommand(cmds cmd);
|
||||
void calculateTimingParameters();
|
||||
void changePollTiming(int timing_ms, bool setUI=false);
|
||||
|
||||
void changeMode(mode_kind mode);
|
||||
void changeMode(mode_kind mode, bool dataOn);
|
||||
|
||||
void connectionHandler(bool connect);
|
||||
|
||||
cmds meterKindToMeterCommand(meterKind m);
|
||||
|
||||
void updateUsbButtons();
|
||||
|
||||
int oldFreqDialVal;
|
||||
|
||||
rigCapabilities rigCaps;
|
||||
|
@ -978,7 +1134,8 @@ private:
|
|||
mode_info currentModeInfo;
|
||||
|
||||
bool haveRigCaps;
|
||||
bool amTransmitting;
|
||||
bool amTransmitting = false;
|
||||
bool splitModeEnabled = false;
|
||||
bool usingDataMode = false;
|
||||
|
||||
unsigned char micGain=0;
|
||||
|
@ -988,10 +1145,13 @@ private:
|
|||
unsigned char usbGain=0;
|
||||
unsigned char lanGain=0;
|
||||
|
||||
// Widgets and Special Windows:
|
||||
calibrationWindow *cal;
|
||||
repeaterSetup *rpt;
|
||||
satelliteSetup *sat;
|
||||
transceiverAdjustments *trxadj;
|
||||
cwSender *cw;
|
||||
controllerSetup* usbWindow = Q_NULLPTR;
|
||||
aboutbox *abtBox;
|
||||
selectRadio *selRad;
|
||||
loggingWindow *logWindow;
|
||||
|
@ -1024,9 +1184,45 @@ private:
|
|||
|
||||
rigstate* rigState = Q_NULLPTR;
|
||||
|
||||
passbandActions passbandAction = passbandStatic;
|
||||
double TPBFInner = 0.0;
|
||||
double TPBFOuter = 0.0;
|
||||
double passbandCenterFrequency = 0.0;
|
||||
double pbtDefault = 0.0;
|
||||
quint16 cwPitch = 600;
|
||||
|
||||
availableBands lastRequestedBand=bandGen;
|
||||
|
||||
SERVERCONFIG serverConfig;
|
||||
void serverAddUserLine(const QString& user, const QString& pass, const int& type);
|
||||
|
||||
#if defined (USB_CONTROLLER)
|
||||
usbController *usbControllerDev = Q_NULLPTR;
|
||||
QThread *usbControllerThread = Q_NULLPTR;
|
||||
QString typeName;
|
||||
QVector<BUTTON> usbButtons;
|
||||
QVector<KNOB> usbKnobs;
|
||||
usbDevMap usbDevices;
|
||||
QMutex usbMutex;
|
||||
qint64 lastUsbNotify=0;
|
||||
|
||||
#if defined (Q_OS_LINUX)
|
||||
struct udev* uDev = nullptr;
|
||||
struct udev_monitor* uDevMonitor = nullptr;
|
||||
QSocketNotifier* uDevNotifier = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
dxClusterClient* cluster = Q_NULLPTR;
|
||||
QThread* clusterThread = Q_NULLPTR;
|
||||
QMap<QString, spotData*> clusterSpots;
|
||||
QTimer clusterTimer;
|
||||
QCPItemText* text=Q_NULLPTR;
|
||||
QList<clusterSettings> clusters;
|
||||
QMutex clusterMutex;
|
||||
QColor clusterColor;
|
||||
audioDevices* audioDev = Q_NULLPTR;
|
||||
QImage lcdImage;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(struct rigCapabilities)
|
||||
|
@ -1040,11 +1236,28 @@ Q_DECLARE_METATYPE(struct timekind)
|
|||
Q_DECLARE_METATYPE(struct datekind)
|
||||
Q_DECLARE_METATYPE(struct networkStatus)
|
||||
Q_DECLARE_METATYPE(struct networkAudioLevels)
|
||||
Q_DECLARE_METATYPE(struct spotData)
|
||||
Q_DECLARE_METATYPE(enum rigInput)
|
||||
Q_DECLARE_METATYPE(enum meterKind)
|
||||
Q_DECLARE_METATYPE(enum spectrumMode)
|
||||
Q_DECLARE_METATYPE(enum mode_kind)
|
||||
Q_DECLARE_METATYPE(enum vfo_t)
|
||||
Q_DECLARE_METATYPE(QList<radio_cap_packet>)
|
||||
Q_DECLARE_METATYPE(QList<spotData>)
|
||||
Q_DECLARE_METATYPE(rigstate*)
|
||||
Q_DECLARE_METATYPE(QVector <BUTTON>*)
|
||||
Q_DECLARE_METATYPE(QVector <KNOB>*)
|
||||
Q_DECLARE_METATYPE(QVector <COMMAND>*)
|
||||
Q_DECLARE_METATYPE(const COMMAND*)
|
||||
Q_DECLARE_METATYPE(const USBDEVICE*)
|
||||
Q_DECLARE_METATYPE(codecType)
|
||||
Q_DECLARE_METATYPE(errorType)
|
||||
Q_DECLARE_METATYPE(enum duplexMode)
|
||||
Q_DECLARE_METATYPE(enum rptAccessTxRx)
|
||||
Q_DECLARE_METATYPE(struct rptrTone_t)
|
||||
Q_DECLARE_METATYPE(struct rptrAccessData_t)
|
||||
Q_DECLARE_METATYPE(enum usbFeatureType)
|
||||
Q_DECLARE_METATYPE(enum cmds)
|
||||
|
||||
//void (*wfmain::logthistext)(QString text) = NULL;
|
||||
|
||||
|
|
64
wfserver.pro
|
@ -13,27 +13,49 @@ TEMPLATE = app
|
|||
|
||||
CONFIG += console
|
||||
|
||||
DEFINES += WFVIEW_VERSION=\\\"1.50\\\"
|
||||
DEFINES += WFVIEW_VERSION=\\\"1.65\\\"
|
||||
|
||||
DEFINES += BUILD_WFSERVER
|
||||
|
||||
|
||||
CONFIG(debug, release|debug) {
|
||||
# For Debug builds only:
|
||||
QMAKE_CXXFLAGS += -faligned-new
|
||||
win32:DESTDIR = wfview-release
|
||||
win32:LIBS += -L../portaudio/msvc/Win32/Debug/ -lportaudio_x86 -ole32
|
||||
# For Debug builds only:
|
||||
linux:QMAKE_CXXFLAGS += -faligned-new
|
||||
win32 {
|
||||
contains(QMAKE_TARGET.arch, x86_64) {
|
||||
QMAKE_POST_LINK +=$$quote(cmd /c copy /y ..\portaudio\msvc\x64\Debug\portaudio_x64.dll wfview-debug $$escape_expand(\\n\\t))
|
||||
LIBS += -L../portaudio/msvc/X64/Debug/ -lportaudio_x64
|
||||
LIBS += -L../opus/win32/VS2015/x64/Debug/ -lopus -lole32
|
||||
} else {
|
||||
QMAKE_POST_LINK +=$$quote(cmd /c copy /y ..\portaudio\msvc\win32\Debug\portaudio_x86.dll wfview-debug\$$escape_expand(\\n\\t))
|
||||
LIBS += -L../portaudio/msvc/Win32/Debug/ -lportaudio_x86
|
||||
LIBS += -L../opus/win32/VS2015/Win32/Debug/ -lopus -lole32
|
||||
}
|
||||
DESTDIR = wfview-release
|
||||
}
|
||||
} else {
|
||||
# For Release builds only:
|
||||
linux:QMAKE_CXXFLAGS += -s
|
||||
QMAKE_CXXFLAGS += -fvisibility=hidden
|
||||
QMAKE_CXXFLAGS += -fvisibility-inlines-hidden
|
||||
QMAKE_CXXFLAGS += -faligned-new
|
||||
linux:QMAKE_LFLAGS += -O2 -s
|
||||
win32:DESTDIR = wfview-debug
|
||||
win32:LIBS += -L../portaudio/msvc/Win32/Release/ -lportaudio_x86 -lole32
|
||||
# For Release builds only:
|
||||
linux:QMAKE_CXXFLAGS += -s
|
||||
linux:QMAKE_CXXFLAGS += -fvisibility=hidden
|
||||
linux:QMAKE_CXXFLAGS += -fvisibility-inlines-hidden
|
||||
linux:QMAKE_CXXFLAGS += -faligned-new
|
||||
linux:QMAKE_LFLAGS += -O2 -s
|
||||
|
||||
win32 {
|
||||
contains(QMAKE_TARGET.arch, x86_64) {
|
||||
QMAKE_POST_LINK +=$$quote(cmd /c copy /y ..\portaudio\msvc\x64\Release\portaudio_x64.dll wfview-release $$escape_expand(\\n\\t))
|
||||
LIBS += -L../portaudio/msvc/X64/Release/ -lportaudio_x64
|
||||
LIBS += -L../opus/win32/VS2015/x64/Release/ -lopus -lole32
|
||||
} else {
|
||||
QMAKE_POST_LINK +=$$quote(cmd /c copy /y ..\portaudio\msvc\win32\Release\portaudio_x86.dll wfview-release $$escape_expand(\\n\\t))
|
||||
LIBS += -L../portaudio/msvc/Win32/Release/ -lportaudio_x86
|
||||
LIBS += -L../opus/win32/VS2015/Win32/Release/ -lopus -lole32
|
||||
}
|
||||
DESTDIR = wfview-debug
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# RTAudio defines
|
||||
win32:DEFINES += __WINDOWS_WASAPI__
|
||||
#win32:DEFINES += __WINDOWS_DS__ # Requires DirectSound libraries
|
||||
|
@ -103,15 +125,6 @@ RESOURCES += qdarkstyle/style.qrc \
|
|||
unix:target.path = $$PREFIX/bin
|
||||
INSTALLS += target
|
||||
|
||||
# Do not do this, it will hang on start:
|
||||
# CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT
|
||||
|
||||
CONFIG(debug, release|debug) {
|
||||
win32:LIBS += -L../opus/win32/VS2015/Win32/Debug/ -lopus
|
||||
} else {
|
||||
win32:LIBS += -L../opus/win32/VS2015/Win32/Release/ -lopus
|
||||
}
|
||||
|
||||
linux:LIBS += -L./ -lopus
|
||||
macx:LIBS += -framework CoreAudio -framework CoreFoundation -lpthread -lopus
|
||||
|
||||
|
@ -142,7 +155,8 @@ SOURCES += main.cpp\
|
|||
resampler/resample.c \
|
||||
rigctld.cpp \
|
||||
tcpserver.cpp \
|
||||
keyboard.cpp
|
||||
keyboard.cpp \
|
||||
audiodevices.cpp
|
||||
|
||||
HEADERS += servermain.h \
|
||||
commhandler.h \
|
||||
|
@ -169,4 +183,6 @@ HEADERS += servermain.h \
|
|||
ulaw.h \
|
||||
tcpserver.h \
|
||||
audiotaper.h \
|
||||
keyboard.h
|
||||
keyboard.h \
|
||||
wfviewtypes.h \
|
||||
audiodevices.h
|
||||
|
|
450
wfserver.vcxproj
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
|
@ -9,6 +13,10 @@
|
|||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{00E054F8-A1D4-3ECA-A8D6-DFC8A68AFD56}</ProjectGuid>
|
||||
|
@ -16,7 +24,8 @@
|
|||
<Keyword>QtVS_v304</Keyword>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild></PropertyGroup>
|
||||
<QtMsBuild Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
|
@ -27,6 +36,15 @@
|
|||
<IntermediateDirectory>release\</IntermediateDirectory>
|
||||
<PrimaryOutput>wfserver</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<OutputDirectory>wfview-release\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<IntermediateDirectory>release\</IntermediateDirectory>
|
||||
<PrimaryOutput>wfserver</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<OutputDirectory>wfview-debug\</OutputDirectory>
|
||||
|
@ -36,16 +54,78 @@
|
|||
<IntermediateDirectory>debug\</IntermediateDirectory>
|
||||
<PrimaryOutput>wfserver</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /><Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')"><Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." /></Target>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<OutputDirectory>wfview-debug\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<IntermediateDirectory>debug\</IntermediateDirectory>
|
||||
<PrimaryOutput>wfserver</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
|
||||
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
|
||||
</Target>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" /><ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')"><Import Project="$(QtMsBuild)\qt_defaults.props" /></ImportGroup><PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"><OutDir>wfview-debug\</OutDir><IntDir>debug\</IntDir><TargetName>wfserver</TargetName><IgnoreImportLibrary>true</IgnoreImportLibrary></PropertyGroup><PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"><OutDir>wfview-release\</OutDir><IntDir>release\</IntDir><TargetName>wfserver</TargetName><IgnoreImportLibrary>true</IgnoreImportLibrary><LinkIncremental>false</LinkIncremental></PropertyGroup><PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"><QtInstall>msvc2019</QtInstall><QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules></PropertyGroup><PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"><QtInstall>msvc2019</QtInstall><QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules></PropertyGroup><ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')"><Import Project="$(QtMsBuild)\qt.props" /></ImportGroup>
|
||||
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
|
||||
<Import Project="$(QtMsBuild)\qt_defaults.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>wfview-debug\</OutDir>
|
||||
<IntDir>debug\</IntDir>
|
||||
<TargetName>wfserver</TargetName>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TargetName>wfserver</TargetName>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>wfview-release\</OutDir>
|
||||
<IntDir>release\</IntDir>
|
||||
<TargetName>wfserver</TargetName>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetName>wfserver</TargetName>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>wfview-release\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<QtInstall>msvc2019</QtInstall>
|
||||
<QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="QtSettings">
|
||||
<QtInstall>msvc2016_64_v640</QtInstall>
|
||||
<QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<QtInstall>msvc2019</QtInstall>
|
||||
<QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="QtSettings">
|
||||
<QtInstall>msvc2016_64_v640</QtInstall>
|
||||
<QtModules>core;network;gui;multimedia;widgets;serialport;printsupport</QtModules>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
|
||||
<Import Project="$(QtMsBuild)\qt.props" />
|
||||
</ImportGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.;..\rtaudio;..\portaudio\include;..\opus\include;..\eigen;..\r8brain-free-src;resampler;release;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -57,14 +137,16 @@
|
|||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<ObjectFileName>release\</ObjectFileName>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.2e";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX="/usr/local";GITSHORT="44f6ec2";HOST="wfview.org";UNAME="build";NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.55";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX="/usr/local";GITSHORT="44f6ec2";HOST="wfview.org";UNAME="build";NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessToFile>false</PreprocessToFile>
|
||||
<ProgramDataBaseFileName></ProgramDataBaseFileName>
|
||||
<ProgramDataBaseFileName>
|
||||
</ProgramDataBaseFileName>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation></ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>..\portaudio\msvc\Win32\Release\portaudio_x86.lib;..\opus\win32\VS2015\Win32\Release\opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\portaudio\msvc\Win32\Release;..\opus\win32\VS2015\Win32\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
@ -85,9 +167,81 @@
|
|||
<WarningLevel>0</WarningLevel>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2e\";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"44f6ec2\";HOST=\"wfview.org\";UNAME=\"build\";NDEBUG;QT_NO_DEBUG;QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.55\";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"44f6ec2\";HOST=\"wfview.org\";UNAME=\"build\";NDEBUG;QT_NO_DEBUG;QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc><CompilerFlavor>msvc</CompilerFlavor><Include>./$(Configuration)/moc_predefs.h</Include><ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription><DynamicSource>output</DynamicSource><QtMocDir>$(Configuration)</QtMocDir><QtMocFileName>moc_%(Filename).cpp</QtMocFileName></QtMoc><QtRcc><Compression>default</Compression><ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription><QtRccDir>$(Configuration)</QtRccDir><QtRccFileName>qrc_%(Filename).cpp</QtRccFileName></QtRcc></ItemDefinitionGroup>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<Compression>default</Compression>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.;..\rtaudio;..\portaudio\include;..\opus\include;..\eigen;..\r8brain-free-src;resampler;release;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AssemblerListingLocation>release\</AssemblerListingLocation>
|
||||
<BrowseInformation>false</BrowseInformation>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<ObjectFileName>release\</ObjectFileName>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.55";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX="/usr/local";GITSHORT="44f6ec2";HOST="wfview.org";UNAME="build";NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessToFile>false</PreprocessToFile>
|
||||
<ProgramDataBaseFileName>
|
||||
</ProgramDataBaseFileName>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>..\portaudio\msvc\x64\Release\portaudio_x64.lib;..\opus\win32\VS2015\x64\Release\opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\portaudio\msvc\x64\Release;..\opus\win32\VS2015\x64\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
|
||||
<DataExecutionPrevention>true</DataExecutionPrevention>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<OutputFile>$(OutDir)\wfserver.exe</OutputFile>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Link>
|
||||
<Midl>
|
||||
<DefaultCharType>Unsigned</DefaultCharType>
|
||||
<EnableErrorChecks>None</EnableErrorChecks>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.55\";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"44f6ec2\";HOST=\"wfview.org\";UNAME=\"build\";NDEBUG;QT_NO_DEBUG;QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<Compression>default</Compression>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.;..\rtaudio;..\portaudio\include;..\opus\include;..\eigen;..\r8brain-free-src;resampler;debug;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -99,13 +253,14 @@
|
|||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<ObjectFileName>debug\</ObjectFileName>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.2e";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX="/usr/local";GITSHORT="44f6ec2";HOST="wfview.org";UNAME="build";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.55";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX="/usr/local";GITSHORT="44f6ec2";HOST="wfview.org";UNAME="build";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessToFile>false</PreprocessToFile>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation></ClCompile>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>..\portaudio\msvc\Win32\Debug\portaudio_x86.lib;..\opus\win32\VS2015\Win32\Debug\opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\portaudio\msvc\Win32\Debug;..\opus\win32\VS2015\Win32\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
@ -124,12 +279,81 @@
|
|||
<WarningLevel>0</WarningLevel>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.2e\";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"44f6ec2\";HOST=\"wfview.org\";UNAME=\"build\";QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.55\";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"44f6ec2\";HOST=\"wfview.org\";UNAME=\"build\";QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc><CompilerFlavor>msvc</CompilerFlavor><Include>./$(Configuration)/moc_predefs.h</Include><ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription><DynamicSource>output</DynamicSource><QtMocDir>$(Configuration)</QtMocDir><QtMocFileName>moc_%(Filename).cpp</QtMocFileName></QtMoc><QtRcc><Compression>default</Compression><ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription><QtRccDir>$(Configuration)</QtRccDir><QtRccFileName>qrc_%(Filename).cpp</QtRccFileName></QtRcc></ItemDefinitionGroup>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<Compression>default</Compression>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.;..\rtaudio;..\portaudio\include;..\opus\include;..\eigen;..\r8brain-free-src;resampler;debug;/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AssemblerListingLocation>debug\</AssemblerListingLocation>
|
||||
<BrowseInformation>false</BrowseInformation>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<ObjectFileName>debug\</ObjectFileName>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION="1.55";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX="/usr/local";GITSHORT="44f6ec2";HOST="wfview.org";UNAME="build";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessToFile>false</PreprocessToFile>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>..\portaudio\msvc\Win32\Debug\portaudio_x86.lib;..\opus\win32\VS2015\Win32\Debug\opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\portaudio\msvc\Win32\Debug;..\opus\win32\VS2015\Win32\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
|
||||
<DataExecutionPrevention>true</DataExecutionPrevention>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<OutputFile>$(OutDir)\wfserver.exe</OutputFile>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
</Link>
|
||||
<Midl>
|
||||
<DefaultCharType>Unsigned</DefaultCharType>
|
||||
<EnableErrorChecks>None</EnableErrorChecks>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</Midl>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WFVIEW_VERSION=\"1.55\";BUILD_WFSERVER;__WINDOWS_WASAPI__;QT_DEPRECATED_WARNINGS;QCUSTOMPLOT_COMPILE_LIBRARY;USE_SSE;USE_SSE2;OUTSIDE_SPEEX;RANDOM_PREFIX=wf;EIGEN_MPL2_ONLY;EIGEN_DONT_VECTORIZE;EIGEN_VECTORIZE_SSE3;PREFIX=\"/usr/local\";GITSHORT=\"44f6ec2\";HOST=\"wfview.org\";UNAME=\"build\";QT_MULTIMEDIA_LIB;QT_PRINTSUPPORT_LIB;QT_WIDGETS_LIB;QT_GUI_LIB;QT_SERIALPORT_LIB;QT_NETWORK_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<QtMoc>
|
||||
<CompilerFlavor>msvc</CompilerFlavor>
|
||||
<Include>./$(Configuration)/moc_predefs.h</Include>
|
||||
<ExecutionDescription>Moc'ing %(Identity)...</ExecutionDescription>
|
||||
<DynamicSource>output</DynamicSource>
|
||||
<QtMocDir>$(Configuration)</QtMocDir>
|
||||
<QtMocFileName>moc_%(Filename).cpp</QtMocFileName>
|
||||
</QtMoc>
|
||||
<QtRcc>
|
||||
<Compression>default</Compression>
|
||||
<ExecutionDescription>Rcc'ing %(Identity)...</ExecutionDescription>
|
||||
<QtRccDir>$(Configuration)</QtRccDir>
|
||||
<QtRccFileName>qrc_%(Filename).cpp</QtRccFileName>
|
||||
</QtRcc>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\rtaudio\RTAudio.cpp" />
|
||||
<ClCompile Include="audioconverter.cpp" />
|
||||
<ClCompile Include="audiodevices.cpp" />
|
||||
<ClCompile Include="audiohandler.cpp" />
|
||||
<ClCompile Include="commhandler.cpp" />
|
||||
<ClCompile Include="freqmemory.cpp" />
|
||||
|
@ -153,219 +377,76 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\rtaudio\RTAUdio.h" />
|
||||
<QtMoc Include="audiodevices.h" />
|
||||
<ClInclude Include="resampler\arch.h" />
|
||||
<QtMoc Include="audioconverter.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="audiohandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="audiotaper.h" />
|
||||
<QtMoc Include="commhandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="freqmemory.h" />
|
||||
<QtMoc Include="keyboard.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="logcategories.h" />
|
||||
<ClInclude Include="packettypes.h" />
|
||||
<QtMoc Include="pahandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="pttyhandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="repeaterattributes.h" />
|
||||
<ClInclude Include="resampler\resample_sse.h" />
|
||||
<QtMoc Include="rigcommander.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="rigctld.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="rigidentities.h" />
|
||||
<QtMoc Include="rthandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="servermain.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="resampler\speex_resampler.h" />
|
||||
<QtMoc Include="tcpserver.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="udpaudio.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="udpbase.h" />
|
||||
<QtMoc Include="udpcivdata.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="udphandler.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<QtMoc Include="udpserver.h">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</QtMoc>
|
||||
<ClInclude Include="ulaw.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
<FileType>Document</FileType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -faligned-new -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -faligned-new -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Generate moc_predefs.h</Message>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Generate moc_predefs.h</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">debug\moc_predefs.h;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">debug\moc_predefs.h;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="release\moc_predefs.h.cbt">
|
||||
<FileType>Document</FileType>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -fvisibility=hidden -fvisibility-inlines-hidden -faligned-new -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -fvisibility=hidden -fvisibility-inlines-hidden -faligned-new -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Generate moc_predefs.h</Message>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Generate moc_predefs.h</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">release\moc_predefs.h;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">release\moc_predefs.h;%(Outputs)</Outputs>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</CustomBuild>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="qdarkstyle\rc\Hmovetoolbar.png" />
|
||||
|
@ -398,30 +479,20 @@
|
|||
<None Include="qdarkstyle\rc\radio_unchecked_disabled.png" />
|
||||
<None Include="qdarkstyle\rc\radio_unchecked_focus.png" />
|
||||
<QtRcc Include="resources\resources.qrc">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">resources</InitFuncName><InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">resources</InitFuncName></QtRcc>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">resources</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">resources</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">resources</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">resources</InitFuncName>
|
||||
</QtRcc>
|
||||
<None Include="qdarkstyle\rc\right_arrow.png" />
|
||||
<None Include="qdarkstyle\rc\right_arrow_disabled.png" />
|
||||
<None Include="qdarkstyle\rc\sizegrip.png" />
|
||||
<QtRcc Include="qdarkstyle\style.qrc">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">style</InitFuncName><InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">style</InitFuncName></QtRcc>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">style</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">style</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">style</InitFuncName>
|
||||
<InitFuncName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">style</InitFuncName>
|
||||
</QtRcc>
|
||||
<None Include="qdarkstyle\style.qss" />
|
||||
<None Include="qdarkstyle\rc\stylesheet-branch-end.png" />
|
||||
<None Include="qdarkstyle\rc\stylesheet-branch-more.png" />
|
||||
|
@ -435,6 +506,9 @@
|
|||
<ItemGroup>
|
||||
<ResourceCompile Include=".\wfserver_resource.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /><ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')"><Import Project="$(QtMsBuild)\qt.targets" /></ImportGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
|
@ -103,6 +103,9 @@
|
|||
<ClCompile Include="udpserver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audiodevices.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\rtaudio\RTAUdio.h">
|
||||
|
@ -188,46 +191,12 @@
|
|||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
<Filter>Generated Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="release\moc_predefs.h.cbt">
|
||||
<Filter>Generated Files</Filter>
|
||||
</CustomBuild>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="qdarkstyle\rc\Hmovetoolbar.png">
|
||||
|
@ -361,6 +330,11 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="C:\Users\Phil\source\repos\wfview\wfserver_resource.rc" />
|
||||
<ResourceCompile Include=".\wfserver_resource.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="audiodevices.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,10 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<QtLastBackgroundBuild>2022-04-13T11:33:50.3607712Z</QtLastBackgroundBuild>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="QtSettings">
|
||||
<QtLastBackgroundBuild>2023-02-14T19:04:12.9338871Z</QtLastBackgroundBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<QtLastBackgroundBuild>2022-04-13T11:33:53.0745117Z</QtLastBackgroundBuild>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="QtSettings">
|
||||
<QtLastBackgroundBuild>2023-02-14T19:04:11.6802165Z</QtLastBackgroundBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="QtSettings">
|
||||
<QtLastBackgroundBuild>2023-02-14T19:04:14.0213664Z</QtLastBackgroundBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="QtSettings">
|
||||
<QtLastBackgroundBuild>2023-02-14T19:04:13.5068223Z</QtLastBackgroundBuild>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<<<<<<< HEAD
|
||||
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(PATH)</LocalDebuggerEnvironment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
=======
|
||||
>>>>>>> settings
|
||||
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(PATH)</LocalDebuggerEnvironment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(PATH)</LocalDebuggerEnvironment>
|
||||
</PropertyGroup>
|
||||
<<<<<<< HEAD
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(PATH)</LocalDebuggerEnvironment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<QtLastBackgroundBuild>2021-11-18T12:40:24.8966742Z</QtLastBackgroundBuild>
|
||||
=======
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<QtLastBackgroundBuild>2021-11-22T18:24:33.3752914Z</QtLastBackgroundBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<QtLastBackgroundBuild>2021-11-22T18:24:41.6960953Z</QtLastBackgroundBuild>
|
||||
>>>>>>> settings
|
||||
</PropertyGroup>
|
||||
</Project>
|
Po Szerokość: | Wysokość: | Rozmiar: 116 KiB |