--- /dev/null
+LIBRARY DttSP
+EXPORTS
+ audio_callback @1
+ setup_sdr @2
+ destroy_sdr @3
--- /dev/null
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DttSP", "DttSP.vcproj", "{E8E40DF8-8A3B-422D-B7A1-44BB036F4994}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {E8E40DF8-8A3B-422D-B7A1-44BB036F4994}.Debug.ActiveCfg = Debug|Win32
+ {E8E40DF8-8A3B-422D-B7A1-44BB036F4994}.Debug.Build.0 = Debug|Win32
+ {E8E40DF8-8A3B-422D-B7A1-44BB036F4994}.Release.ActiveCfg = Release|Win32
+ {E8E40DF8-8A3B-422D-B7A1-44BB036F4994}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="DttSP"
+ ProjectGUID="{E8E40DF8-8A3B-422D-B7A1-44BB036F4994}"
+ RootNamespace="DttSP"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../temp/Debug/DttSP"
+ IntermediateDirectory="../../temp/Debug/DttSP"
+ ConfigurationType="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D_WIN32_WINNT>=0x0400"
+ Optimization="0"
+ AdditionalIncludeDirectories="./;../FFTW/fftw;"../pthread""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DttSP_EXPORTS;__CLEANUP_C"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"
+ CompileAs="1"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="../../bin/Debug/DttSP.dll"
+ LinkIncremental="2"
+ ModuleDefinitionFile="./DttSP.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/DttSP.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/DttSP.lib"
+ TargetMachine="0"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreLinkEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../temp/Release/DttSP"
+ IntermediateDirectory="../../temp/Release/DttSP"
+ ConfigurationType="2"
+ CharacterSet="0">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D_WIN32_WINNT>=0x0400"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ ImproveFloatingPointConsistency="TRUE"
+ FavorSizeOrSpeed="1"
+ OptimizeForProcessor="0"
+ OptimizeForWindowsApplication="TRUE"
+ AdditionalIncludeDirectories="".";"..\FFTW\fftw";"..\pthread""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;DttSP_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)/"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="0"
+ CompileAs="1"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="../../bin/Release/DttSP.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile="./DttSP.def"
+ GenerateDebugInformation="FALSE"
+ GenerateMapFile="FALSE"
+ MapFileName="$(OutDir)/$(ProjectName).map"
+ MapExports="FALSE"
+ SubSystem="2"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(IntDir)/DttSP.lib"
+ TargetMachine="0"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreLinkEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath=".\am_demod.c">
+ </File>
+ <File
+ RelativePath=".\banal.c">
+ </File>
+ <File
+ RelativePath=".\bufvec.c">
+ </File>
+ <File
+ RelativePath=".\chan.c">
+ </File>
+ <File
+ RelativePath=".\chap.c">
+ </File>
+ <File
+ RelativePath=".\correctIQ.c">
+ </File>
+ <File
+ RelativePath=".\crc16.c">
+ </File>
+ <File
+ RelativePath=".\cxops.c">
+ </File>
+ <File
+ RelativePath=".\digitalagc.c">
+ </File>
+ <File
+ RelativePath=".\fastrig.c">
+ </File>
+ <File
+ RelativePath=".\filter.c">
+ </File>
+ <File
+ RelativePath=".\fm_demod.c">
+ </File>
+ <File
+ RelativePath=".\lmadf.c">
+ </File>
+ <File
+ RelativePath=".\main.c">
+ </File>
+ <File
+ RelativePath=".\meter.c">
+ </File>
+ <File
+ RelativePath=".\noiseblanker.c">
+ </File>
+ <File
+ RelativePath=".\oscillator.c">
+ </File>
+ <File
+ RelativePath=".\ovsv.c">
+ </File>
+ <File
+ RelativePath=".\power_spectrum.c">
+ </File>
+ <File
+ RelativePath=".\ringb.c">
+ </File>
+ <File
+ RelativePath=".\sdr.c">
+ </File>
+ <File
+ RelativePath=".\sdrexport.c">
+ </File>
+ <File
+ RelativePath=".\speechproc.c">
+ </File>
+ <File
+ RelativePath=".\splitfields.c">
+ </File>
+ <File
+ RelativePath=".\spottone.c">
+ </File>
+ <File
+ RelativePath=".\thunk.c">
+ </File>
+ <File
+ RelativePath=".\update.c">
+ </File>
+ <File
+ RelativePath=".\window.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath=".\am_demod.h">
+ </File>
+ <File
+ RelativePath=".\banal.h">
+ </File>
+ <File
+ RelativePath=".\bufvec.h">
+ </File>
+ <File
+ RelativePath=".\chan.h">
+ </File>
+ <File
+ RelativePath=".\chap.h">
+ </File>
+ <File
+ RelativePath=".\common.h">
+ </File>
+ <File
+ RelativePath=".\complex.h">
+ </File>
+ <File
+ RelativePath=".\correctIQ.h">
+ </File>
+ <File
+ RelativePath=".\crc16.h">
+ </File>
+ <File
+ RelativePath=".\cxops.h">
+ </File>
+ <File
+ RelativePath=".\datatypes.h">
+ </File>
+ <File
+ RelativePath=".\digitalagc.h">
+ </File>
+ <File
+ RelativePath=".\fastrig.h">
+ </File>
+ <File
+ RelativePath="..\Fftw\fftw\fftw.h">
+ </File>
+ <File
+ RelativePath=".\filter.h">
+ </File>
+ <File
+ RelativePath=".\firdes.h">
+ </File>
+ <File
+ RelativePath=".\fm_demod.h">
+ </File>
+ <File
+ RelativePath=".\fromsys.h">
+ </File>
+ <File
+ RelativePath=".\lmadf.h">
+ </File>
+ <File
+ RelativePath=".\meter.h">
+ </File>
+ <File
+ RelativePath=".\noiseblanker.h">
+ </File>
+ <File
+ RelativePath=".\oscillator.h">
+ </File>
+ <File
+ RelativePath=".\ovsv.h">
+ </File>
+ <File
+ RelativePath=".\power_spectrum.h">
+ </File>
+ <File
+ RelativePath=".\ringb.h">
+ </File>
+ <File
+ RelativePath=".\sdrexport.h">
+ </File>
+ <File
+ RelativePath=".\speechproc.h">
+ </File>
+ <File
+ RelativePath=".\splitfields.h">
+ </File>
+ <File
+ RelativePath=".\spottone.h">
+ </File>
+ <File
+ RelativePath=".\statistics.h">
+ </File>
+ <File
+ RelativePath=".\thunk.h">
+ </File>
+ <File
+ RelativePath=".\update.h">
+ </File>
+ <File
+ RelativePath=".\valueswin.h">
+ </File>
+ <File
+ RelativePath=".\window.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="DttSP"
+ ProjectGUID="{E8E40DF8-8A3B-422D-B7A1-44BB036F4994}"
+ RootNamespace="DttSP"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../temp/Debug"
+ IntermediateDirectory="../../temp/Debug"
+ ConfigurationType="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="./;"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DttSP_EXPORTS"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(IntDir)/FFTW2.lib"
+ OutputFile="../../bin/Debug/DttSP.dll"
+ LinkIncremental="1"
+ ModuleDefinitionFile="./DttSP.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/DttSP.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/DttSP.lib"
+ TargetMachine="0"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreLinkEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../temp/Release"
+ IntermediateDirectory="../../temp/Release"
+ ConfigurationType="2"
+ CharacterSet="0">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ ImproveFloatingPointConsistency="TRUE"
+ FavorSizeOrSpeed="1"
+ OptimizeForProcessor="0"
+ OptimizeForWindowsApplication="TRUE"
+ AdditionalIncludeDirectories="".";"..\FFTW\fftw";."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;DttSP_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ AssemblerListingLocation="$(IntDir)/"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(IntDir)/FFTW2.lib"
+ OutputFile="../../bin/Release/DttSP.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile="./DttSP.def"
+ GenerateDebugInformation="FALSE"
+ GenerateMapFile="FALSE"
+ MapFileName="$(OutDir)/$(ProjectName).map"
+ MapExports="FALSE"
+ SubSystem="2"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(IntDir)/DttSP.lib"
+ TargetMachine="0"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreBuildEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCPreLinkEventTool"
+ ExcludedFromBuild="TRUE"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath=".\am_demod.c">
+ </File>
+ <File
+ RelativePath=".\banal.c">
+ </File>
+ <File
+ RelativePath=".\bufvec.c">
+ </File>
+ <File
+ RelativePath=".\chan.c">
+ </File>
+ <File
+ RelativePath=".\chap.c">
+ </File>
+ <File
+ RelativePath=".\correctIQ.c">
+ </File>
+ <File
+ RelativePath=".\crc16.c">
+ </File>
+ <File
+ RelativePath=".\cxops.c">
+ </File>
+ <File
+ RelativePath=".\digitalagc.c">
+ </File>
+ <File
+ RelativePath=".\DttSP.cpp">
+ </File>
+ <File
+ RelativePath=".\fastrig.c">
+ </File>
+ <File
+ RelativePath=".\filter.c">
+ </File>
+ <File
+ RelativePath=".\fm_demod.c">
+ </File>
+ <File
+ RelativePath=".\lmadf.c">
+ </File>
+ <File
+ RelativePath=".\main.c">
+ </File>
+ <File
+ RelativePath=".\noiseblanker.c">
+ </File>
+ <File
+ RelativePath=".\oscillator.c">
+ </File>
+ <File
+ RelativePath=".\ovsv.c">
+ </File>
+ <File
+ RelativePath=".\power_spectrum.c">
+ </File>
+ <File
+ RelativePath=".\ringb.c">
+ </File>
+ <File
+ RelativePath=".\sdr.c">
+ </File>
+ <File
+ RelativePath=".\sdrexport.c">
+ </File>
+ <File
+ RelativePath=".\speechproc.c">
+ </File>
+ <File
+ RelativePath=".\splitfields.c">
+ </File>
+ <File
+ RelativePath=".\spottone.c">
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\thunk.c">
+ </File>
+ <File
+ RelativePath=".\update.c">
+ </File>
+ <File
+ RelativePath=".\window.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath=".\am_demod.h">
+ </File>
+ <File
+ RelativePath=".\banal.h">
+ </File>
+ <File
+ RelativePath=".\bufvec.h">
+ </File>
+ <File
+ RelativePath=".\chan.h">
+ </File>
+ <File
+ RelativePath=".\chap.h">
+ </File>
+ <File
+ RelativePath=".\common.h">
+ </File>
+ <File
+ RelativePath=".\complex.h">
+ </File>
+ <File
+ RelativePath=".\correctIQ.h">
+ </File>
+ <File
+ RelativePath=".\crc16.h">
+ </File>
+ <File
+ RelativePath=".\cxops.h">
+ </File>
+ <File
+ RelativePath=".\datatypes.h">
+ </File>
+ <File
+ RelativePath=".\digitalagc.h">
+ </File>
+ <File
+ RelativePath=".\DttSP.h">
+ </File>
+ <File
+ RelativePath=".\fastrig.h">
+ </File>
+ <File
+ RelativePath=".\fftw.h">
+ </File>
+ <File
+ RelativePath=".\filter.h">
+ </File>
+ <File
+ RelativePath=".\firdes.h">
+ </File>
+ <File
+ RelativePath=".\fm_demod.h">
+ </File>
+ <File
+ RelativePath=".\fromsys.h">
+ </File>
+ <File
+ RelativePath=".\lmadf.h">
+ </File>
+ <File
+ RelativePath=".\noiseblanker.h">
+ </File>
+ <File
+ RelativePath=".\oscillator.h">
+ </File>
+ <File
+ RelativePath=".\ovsv.h">
+ </File>
+ <File
+ RelativePath=".\power_spectrum.h">
+ </File>
+ <File
+ RelativePath=".\ringb.h">
+ </File>
+ <File
+ RelativePath=".\sdrexport.h">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Moc'ing sdrexport.h..."
+ CommandLine="$(QTDIR)\bin\moc.exe .\sdrexport.h -o tmp\moc\moc_sdrexport.cpp
+"
+ AdditionalDependencies="$(QTDIR)\bin\moc.exe"
+ Outputs="tmp\moc\moc_sdrexport.cpp"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Moc'ing sdrexport.h..."
+ CommandLine="$(QTDIR)\bin\moc.exe .\sdrexport.h -o tmp\moc\moc_sdrexport.cpp
+"
+ AdditionalDependencies="$(QTDIR)\bin\moc.exe"
+ Outputs="tmp\moc\moc_sdrexport.cpp"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\speechproc.h">
+ </File>
+ <File
+ RelativePath=".\splitfields.h">
+ </File>
+ <File
+ RelativePath=".\spottone.h">
+ </File>
+ <File
+ RelativePath=".\statistics.h">
+ </File>
+ <File
+ RelativePath=".\stdafx.h">
+ </File>
+ <File
+ RelativePath=".\thunk.h">
+ </File>
+ <File
+ RelativePath=".\update.h">
+ </File>
+ <File
+ RelativePath=".\valueswin.h">
+ </File>
+ <File
+ RelativePath=".\window.h">
+ </File>
+ <File
+ RelativePath=".\wvlt.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- /dev/null
+extern int write(int, void*,unsigned int);
--- /dev/null
+/* keyb.c */
+/*
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <ringb.h>
+
+#define SAMP_RATE (48000)
+#define HUGE_PHASE (1256637061.43593)
+
+#define RING_SIZE (01 << 020)
+
+static pthread_t input, play;
+static sem_t ready, reader, writer;
+
+ringb_t *lring, *rring;
+int size;
+
+static BOOLEAN playing = FALSE;
+static double wpm = 18.0, freq = 750.0, gain = -6.0, ramp = 5.0;
+
+COMPLEX *zout = 0;
+
+// basic mapping, chars -> morse strings
+char *morse_table[128];
+
+// CW tone segments
+#define ME_EOF (-1)
+#define ME_ZERO (0)
+#define ME_RAMP (1)
+#define ME_STDY (2)
+
+struct {
+ double wpm, rise, fall, curr, incr, rate;
+ int type, size;
+} morsel;
+
+int ditspacesize, dahspacesize,
+ ditstdysize, dahstdysize,
+ charspacesize, wordspacesize,
+ risesize, fallsize;
+double riseincr, fallincr;
+
+#define MAX_ESC (512)
+#define ESC_L '<'
+#define ESC_R '>'
+
+void inlinecmd(char *, int);
+
+void send_sound(COMPLEX *, int);
+
+//------------------------------------------------------------
+
+// try to map char -> morse string
+char *
+get_morse(int c) { return morse_table[c & 0x7F]; }
+
+// translate text input to timed, sub-morse-element
+// audio segment specs; parcel the segments out
+// one at a time to the sound player
+void
+reader_thread(void) {
+ BOOLEAN b = TRUE; // we're coming from silence
+ int c, e;
+ char *m;
+
+ // keep reading 1 char at a time
+ while ((c = getchar()) != EOF) {
+
+ // inline command?
+ if (c == ESC_L) {
+ int i = 0;
+ char buf[MAX_ESC];
+ while ((c = getchar()) != EOF) {
+ if (c == ESC_R) break;
+ buf[i] = c;
+ if (++i >= (MAX_ESC - 1)) break;
+ }
+ if (c == EOF) goto finish;
+ buf[i] = 0;
+ inlinecmd(buf, i);
+ continue;
+ }
+
+ // is char mapped to morse?
+ if (m = get_morse(c)) {
+
+ // yup
+ // for each element in morse string
+ // (dit/dah, doesn't matter)
+ while (e = *m++) {
+ // first segment is ramp up...
+ sem_wait(&reader);
+ morsel.type = ME_RAMP, morsel.size = risesize;
+ morsel.curr = 0.0, morsel.incr = riseincr;
+ sem_post(&writer);
+
+ // ...then steady state...
+ // (choose dit/dah here)
+ sem_wait(&reader);
+ morsel.type = ME_STDY;
+ morsel.size = e == '.' ? ditstdysize : dahstdysize;
+ sem_post(&writer);
+
+ // ...then ramp down...
+ sem_wait(&reader);
+ morsel.type = ME_RAMP, morsel.size = fallsize;
+ morsel.curr = 1.0, morsel.incr = fallincr;
+ sem_post(&writer);
+
+ // ...finally, post-element pause
+ sem_wait(&reader);
+ morsel.type = ME_ZERO;
+ morsel.size = ditspacesize;
+ sem_post(&writer);
+ }
+
+ // post-character pause
+ sem_wait(&reader);
+ morsel.type = ME_ZERO;
+ // (we already emitted a dit-sized space)
+ morsel.size = charspacesize - ditspacesize;
+ sem_post(&writer);
+
+ // wherever we go next, it won't have been from silence
+ b = FALSE;
+
+ } else {
+ // anything else treated as interword space,
+ // which has only one segment (silence)
+ sem_wait(&reader);
+ morsel.type = ME_ZERO;
+ // was previous output also interword space?
+ if (b)
+ // yes, use full duration
+ morsel.size = wordspacesize;
+ else
+ // no, part of duration already played
+ morsel.size = wordspacesize - charspacesize;
+ b = TRUE;
+ sem_post(&writer);
+ }
+ }
+
+ finish:
+ // indicate EOF on input
+ sem_wait(&reader);
+ morsel.type = ME_EOF;
+ sem_post(&writer);
+ pthread_exit(0);
+}
+
+void
+sound_thread_keyb(void) {
+ int i, k = 0;
+ double ofreq, scale, phase = 0.0;
+ COMPLEX z, delta_z;
+
+ // keep looking for sub-element segments, one at a time
+ for (;;) {
+
+ // pause for next sub-element segment
+ sem_post(&reader);
+ sem_wait(&writer);
+
+ // no more data?
+ if (morsel.type == ME_EOF) break;
+
+ // requires playing some tone?
+ if (morsel.type != ME_ZERO) {
+ // yes, reset params and
+ // set up CORDIC tone generation
+ ofreq = freq * 2.0 * M_PI / SAMP_RATE;
+ scale = pow(10.0, gain / 20.0);
+ if (phase > HUGE_PHASE) phase -= HUGE_PHASE;
+ z = Cmplx(cos(phase), sin(phase));
+ delta_z = Cmplx(cos(ofreq), sin(ofreq));
+ }
+
+ // play out this segment
+ for (i = 0; i < morsel.size; i++) {
+
+ // make silence
+ if (morsel.type == ME_ZERO) zout[k] = cxzero;
+
+ // make tone
+ else {
+ z = Cmul(z, delta_z);
+ phase += ofreq;
+ // is this a ramping segment?
+ if (morsel.type == ME_RAMP) {
+ morsel.curr += morsel.incr;
+ zout[k] = Cscl(z, scale * sin(morsel.curr * M_PI / 2.0));
+ } else
+ zout[k] = Cscl(z, scale);
+ }
+
+ // have we played enough to fill a jack buffer?
+ if (++k >= size) {
+ // yes, send to output
+ send_sound(zout, k);
+ // wait until some audio has been drained
+ sem_wait(&ready);
+ k = 0;
+ if (morsel.type != ME_ZERO) {
+ // reset CORDIC
+ if (phase > HUGE_PHASE) phase -= HUGE_PHASE;
+ z = Cmplx(cos(phase), sin(phase));
+ delta_z = Cmplx(cos(ofreq), sin(ofreq));
+ }
+ }
+ }
+ }
+
+ // anything left unsent?
+ if (k > 0) send_sound(zout, k);
+
+ pthread_exit(0);
+}
+
+//------------------------------------------------------------------------
+void
+send_sound(COMPLEX *buff, int len) {
+ if (ringb_write_space(lring) < len * sizeof(float)) {
+ //write(2, "overrun\n", 8);
+ ringb_restart(lring, size * sizeof(float));
+ ringb_restart(rring, size * sizeof(float));
+ } else {
+ int i;
+ for (i = 0; i < len; i++) {
+ float l = (float)buff[i].re, r = (float)buff[i].im;
+ ringb_write(lring, (char *) &l, sizeof(float));
+ ringb_write(rring, (char *) &r, sizeof(float));
+ }
+ }
+}
+#ifndef _WINDOWS
+PRIVATE void
+jack_xrun(void *arg) {
+ char *str = "xrun!\n";
+ write(2, str, strlen(str));
+}
+
+PRIVATE void
+jack_shutdown(void *arg) {}
+
+PRIVATE void
+jack_callback(jack_nframes_t nframes, void *arg) {
+ char *lp, *rp;
+ int nwant = nframes * sizeof(float),
+ nhave = ringb_read_space(lring);
+
+ lp = jack_port_get_buffer(lport, nframes);
+ rp = jack_port_get_buffer(rport, nframes);
+ if (nhave >= nwant) {
+ ringb_read(lring, lp, nwant);
+ ringb_read(rring, rp, nwant);
+ sem_post(&ready);
+ } else {
+ memset(lp, 0, nwant);
+ memset(rp, 0, nwant);
+ }
+}
+#endif
+void
+resetparam(void) {
+ morsel.wpm = wpm;
+ morsel.rise = morsel.fall = ramp;
+ morsel.rate = SAMP_RATE;
+
+ ditspacesize = (int)(SAMP_RATE * 1.2 / morsel.wpm + 0.5);
+ dahspacesize = (int)(3 * ditspacesize);
+ charspacesize = dahspacesize;
+ wordspacesize = 7 * ditspacesize;
+
+ risesize = (int)(SAMP_RATE * morsel.rise / 1e3 + 0.5);
+ if (risesize > 1)
+ riseincr = 1.0 / (risesize - 1);
+ else
+ riseincr = 1.0;
+
+ fallsize = (int)(SAMP_RATE * morsel.fall / 1e3 + 0.5);
+ if (fallsize > 1)
+ fallincr = -1.0 / (fallsize - 1);
+ else
+ fallincr = -1.0;
+
+ ditstdysize = ditspacesize - risesize - fallsize;
+ dahstdysize = dahspacesize - risesize - fallsize;
+}
+
+#ifndef _WINDOWS
+int
+main(int argc, char **argv) {
+ int i;
+
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1]) {
+ case 'f':
+ freq = atof(argv[++i]);
+ break;
+ case 'w':
+ wpm = atof(argv[++i]);
+ break;
+ case 'r':
+ ramp = atof(argv[++i]);
+ break;
+ default:
+ fprintf(stderr, "keyd [-w wpm] [-f freq] [-r ramp_ms] [infile]\n");
+ exit(1);
+ }
+ else break;
+
+ if (i < argc) {
+ if (!freopen(argv[i], "r", stdin))
+ perror(argv[i]), exit(1);
+ i++;
+ }
+
+ //------------------------------------------------------------
+
+ resetparam();
+
+ //------------------------------------------------------------
+
+ if (!(client = jack_client_new("keyb")))
+ fprintf(stderr, "can't make client -- jack not running?\n"), exit(1);
+ jack_set_process_callback(client, (void *) jack_callback, 0);
+ jack_on_shutdown(client, (void *) jack_shutdown, 0);
+ jack_set_xrun_callback(client, (void *) jack_xrun, 0);
+ size = jack_get_buffer_size(client);
+
+ lport = jack_port_register(client,
+ "ol",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ rport = jack_port_register(client,
+ "or",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ lring = ringb_create(RING_SIZE);
+ rring = ringb_create(RING_SIZE);
+ ringb_clear(lring, size * sizeof(float));
+ ringb_clear(rring, size * sizeof(float));
+
+ //------------------------------------------------------------
+
+ zout = newvec_COMPLEX(size, "keyb sample buffer");
+
+ //------------------------------------------------------------
+
+ sem_init(&ready, 0, 0);
+ sem_init(&reader, 0, 0);
+ sem_init(&writer, 0, 0);
+ pthread_create(&input, 0, (void *) reader_thread, 0);
+ pthread_create(&play, 0, (void *) sound_thread, 0);
+
+ //------------------------------------------------------------
+
+ jack_activate(client);
+ {
+ const char **ports;
+ if (!(ports = jack_get_ports(client, 0, 0, JackPortIsPhysical | JackPortIsInput))) {
+ fprintf(stderr, "can't find any physical playback ports\n");
+ exit(1);
+ }
+ if (jack_connect(client, jack_port_name(lport), ports[0])) {
+ fprintf(stderr, "can't connect left output\n");
+ exit(1);
+ }
+ if (jack_connect(client, jack_port_name(rport), ports[1])) {
+ fprintf(stderr, "can't connect right output\n");
+ exit(1);
+ }
+ free(ports);
+ }
+
+ pthread_join(input, 0);
+ pthread_join(play, 0);
+ jack_client_close(client);
+
+ //------------------------------------------------------------
+
+ delvec_COMPLEX(zout);
+
+ //------------------------------------------------------------
+
+ ringb_free(lring);
+ ringb_free(rring);
+ sem_destroy(&ready);
+ sem_destroy(&reader);
+ sem_destroy(&writer);
+
+ //------------------------------------------------------------
+
+ exit(0);
+}
+#endif
+char *morse_table[128] = {
+ /* 000 NUL */ 0, /* 001 SOH */ 0, /* 002 STX */ 0, /* 003 ETX */ 0,
+ /* 004 EOT */ 0, /* 005 ENQ */ 0, /* 006 ACK */ 0, /* 007 BEL */ 0,
+ /* 008 BS */ 0, /* 009 HT */ 0, /* 010 LF */ 0, /* 011 VT */ 0,
+ /* 012 FF */ 0, /* 013 CR */ 0, /* 014 SO */ 0, /* 015 SI */ 0,
+ /* 016 DLE */ 0, /* 017 DC1 */ 0, /* 018 DC2 */ 0, /* 019 DC3 */ 0,
+ /* 020 DC4 */ 0, /* 021 NAK */ 0, /* 022 SYN */ 0, /* 023 ETB */ 0,
+ /* 024 CAN */ 0, /* 025 EM */ 0, /* 026 SUB */ 0, /* 027 ESC */ 0,
+ /* 028 FS */ 0, /* 029 GS */ 0, /* 030 RS */ 0, /* 031 US */ 0,
+ /* 032 SP */ 0,
+ /* 033 ! */ "...-.", // [SN]
+ /* 034 " */ 0,
+ /* 035 # */ 0,
+ /* 036 $ */ 0,
+ /* 037 % */ ".-...", // [AS]
+ /* 038 & */ 0,
+ /* 039 ' */ 0,
+ /* 040 ( */ "-.--.", // [KN]
+ /* 041 ) */ 0,
+ /* 042 * */ "...-.-", // [SK]
+ /* 043 + */ ".-.-.", // [AR]
+ /* 044 , */ "--..--",
+ /* 045 - */ "-....-",
+ /* 046 . */ ".-.-.-",
+ /* 047 / */ "-..-.",
+ /* 048 0 */ "-----",
+ /* 049 1 */ ".----",
+ /* 050 2 */ "..---",
+ /* 051 3 */ "...--",
+ /* 052 4 */ "....-",
+ /* 053 5 */ ".....",
+ /* 054 6 */ "-....",
+ /* 055 7 */ "--...",
+ /* 056 8 */ "---..",
+ /* 057 9 */ "----.",
+ /* 058 : */ 0,
+ /* 059 ; */ 0,
+ /* 060 < */ 0,
+ /* 061 = */ "-...-", // [BT]
+ /* 062 > */ 0,
+ /* 063 ? */ "..__..", // [IMI]
+ /* 064 @ */ ".--.-.",
+ /* 065 A */ ".-",
+ /* 066 B */ "-...",
+ /* 067 C */ "-.-.",
+ /* 068 D */ "-..",
+ /* 069 E */ ".",
+ /* 070 F */ "..-.",
+ /* 071 G */ "--.",
+ /* 072 H */ "....",
+ /* 073 I */ "..",
+ /* 074 J */ ".---",
+ /* 075 K */ "-.-",
+ /* 076 L */ ".-..",
+ /* 077 M */ "--",
+ /* 078 N */ "-.",
+ /* 079 O */ "---",
+ /* 080 P */ ".--.",
+ /* 081 Q */ "--.-",
+ /* 082 R */ ".-.",
+ /* 083 S */ "...",
+ /* 084 T */ "-",
+ /* 085 U */ "..-",
+ /* 086 V */ "...-",
+ /* 087 W */ ".--",
+ /* 088 X */ "-..-",
+ /* 089 Y */ "-.--",
+ /* 090 Z */ "--..",
+ /* 091 [ */ 0,
+ /* 092 \ */ 0,
+ /* 093 ] */ 0,
+ /* 094 ^ */ 0,
+ /* 095 _ */ 0,
+ /* 096 ` */ 0,
+ /* 097 a */ ".-",
+ /* 098 b */ "-...",
+ /* 099 c */ "-.-.",
+ /* 100 d */ "-..",
+ /* 101 e */ ".",
+ /* 102 f */ "..-.",
+ /* 103 g */ "--.",
+ /* 104 h */ "....",
+ /* 105 i */ "..",
+ /* 106 j */ ".---",
+ /* 107 k */ "-.-",
+ /* 108 l */ ".-..",
+ /* 109 m */ "--",
+ /* 110 n */ "-.",
+ /* 111 o */ "---",
+ /* 112 p */ ".--.",
+ /* 113 q */ "--.-",
+ /* 114 r */ ".-.",
+ /* 115 s */ "...",
+ /* 116 t */ "-",
+ /* 117 u */ "..-",
+ /* 118 v */ "...-",
+ /* 119 w */ ".--",
+ /* 120 x */ "-..-",
+ /* 121 y */ "-.--",
+ /* 122 z */ "--..",
+ /* 123 { */ 0,
+ /* 124 | */ 0,
+ /* 125 } */ 0,
+ /* 126 ~ */ 0,
+ /* 127 DEL */ 0
+};
+
+void
+inlinecmd(char *buf, int len) {
+ if (!buf || len < 1) return;
+ if (!strncmp(buf, "wpm", 3)) {
+ wpm = atof(buf + 3);
+ resetparam();
+ } else if (!strncmp(buf, "ramp", 4)) {
+ ramp = atof(buf + 4);
+ resetparam();
+ } else if (!strncmp(buf, "freq", 4))
+ freq = atof(buf + 4);
+ else if (!strncmp(buf, "gain", 4))
+ gain = atof(buf + 4);
+}
--- /dev/null
+/* keyd.c */
+/*
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+//#include <linux/rtc.h>
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <ringb.h>
+#include <chan.h>
+#include <oscillator.h>
+#include <cwtones.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <keyer.h>
+
+#define SAMP_RATE (48000)
+
+// # times key is sampled per sec
+// > 64 requires root on Linux
+//#define RTC_RATE (128)
+#define RTC_RATE (64)
+
+// # samples generated during 1 clock tick at RTC_RATE
+#define TONE_SIZE (SAMP_RATE / RTC_RATE)
+
+// ring buffer size; > 1 sec at this sr
+#define RING_SIZE (01 << 020)
+
+KeyerState ks;
+KeyerLogic kl;
+
+static pthread_t play, key, update;
+sem_t clock_fired, keyer_started, update_ok, poll_fired;
+
+int fdser, fdrtc;
+/*
+jack_client_t *client;
+jack_port_t *lport, *rport;
+jack_ringbuffer_t *lring, *rring;
+jack_nframes_t size; */
+ringb_t *lring, *rring;
+int size;
+
+CWToneGen gen;
+static BOOLEAN playing = FALSE, iambic = FALSE;
+static double wpm = 18.0, freq = 750.0, ramp = 5.0, gain = 1.0;
+
+//------------------------------------------------------------
+
+
+DttSP_EXP void
+CWtoneExchange(float *bufl,float*bufr,int nframes) {
+ size_t bytesize = nframes*4;
+ size_t numsamps;
+ if ((numsamps = ringb_read_space(lring)) < bytesize) {
+ memset(bufl,0,bytesize);
+ memset(bufr,0,bytesize);
+ } else {
+ ringb_read(lring,(char *)bufl,bytesize);
+ ringb_read(rring,(char *)bufr,bytesize);
+ }
+}
+
+//------------------------------------------------------------
+
+// generated tone -> output ringbuffer
+void
+send_tone(void) {
+ if (ringb_write_space(lring) < TONE_SIZE * sizeof(float)) {
+ //write(2, "overrun tone\n", 13);
+ ringb_restart(lring, TONE_SIZE * sizeof(float));
+ ringb_restart(rring, TONE_SIZE * sizeof(float));
+ } else {
+ int i;
+ for (i = 0; i < gen->size; i++) {
+ float l = (float)CXBreal(gen->buf, i),
+ r = (float)CXBimag(gen->buf, i);
+ ringb_write(lring, (char *) &l, sizeof(float));
+ ringb_write(rring, (char *) &r, sizeof(float));
+ }
+ }
+}
+
+// silence -> output ringbuffer
+void
+send_silence(void) {
+ if (ringb_write_space(lring) < TONE_SIZE * sizeof(float)) {
+ //write(2, "overrun zero\n", 13);
+ ringb_restart(lring, TONE_SIZE * sizeof(float));
+ ringb_restart(rring, TONE_SIZE * sizeof(float));
+ } else {
+ int i;
+ for (i = 0; i < gen->size; i++) {
+ float zero = 0.0;
+ ringb_write(lring, (char *) &zero, sizeof(float));
+ ringb_write(rring, (char *) &zero, sizeof(float));
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+// sound/silence generation
+// tone turned on/off asynchronously
+
+DttSP_EXP void
+sound_thread_keyd(void) {
+ for (;;) {
+ sem_wait(&clock_fired);
+
+ if (playing) {
+ // CWTone keeps playing for awhile after it's turned off,
+ // in order to allow for a decay envelope;
+ // returns FALSE when it's actually done.
+ playing = CWTone(gen);
+ send_tone();
+ } else {
+ send_silence();
+ // only let updates run when we've just generated silence
+// sem_post(&update_ok);
+ }
+ }
+
+ pthread_exit(0);
+}
+
+
+BOOLEAN
+read_key(double del, BOOLEAN dot, BOOLEAN dash) {
+ extern BOOLEAN read_straight_key(KeyerState ks, BOOLEAN keyed);
+ extern BOOLEAN read_iambic_key(KeyerState ks, BOOLEAN dot, BOOLEAN dash, KeyerLogic kl, double ticklen);
+
+ if (iambic)
+ return read_iambic_key(ks, dot, dash, kl, del);
+ else
+ return read_straight_key(ks, dot^dash);
+}
+
+/// Main keyer function, called by a thread in the C#
+DttSP_EXP void
+key_thread(double del, BOOLEAN dash, BOOLEAN dot) {
+ BOOLEAN keydown;
+
+ // called after next tick and passed the
+ // delay waitsince last one
+
+ // read key; tell keyer elapsed time since last call
+ keydown = read_key(del,dot,dash);
+
+
+ if (!playing && keydown)
+ CWToneOn(gen), playing = TRUE;
+ else if (playing && !keydown)
+ CWToneOff(gen);
+
+ sem_post(&clock_fired);
+}
+
+//------------------------------------------------------------------------
+
+// update keyer parameters via text input from stdin
+// <wpm xxx> -> set keyer speed to xxx
+// <gain xxx> -> set gain to xxx (dB)
+// <freq xxx> -> set freq to xxx
+// <ramp xxx> -> set attack/decay times to xxx ms
+
+
+#define MAX_ESC (512)
+#define ESC_L '<'
+#define ESC_R '>'
+
+void
+updater(void) {
+ for (;;) {
+ int c;
+
+ // get or wait for next input char
+ if ((c = getchar()) == EOF) goto finish;
+
+ // if we see the beginning of a command,
+ if (c == ESC_L) {
+ int i = 0;
+ char buf[MAX_ESC];
+
+ // gather up the remainder
+ while ((c = getchar()) != EOF) {
+ if (c == ESC_R) break;
+ buf[i] = c;
+ if (++i >= (MAX_ESC - 1)) break;
+ }
+ if (c == EOF) goto finish;
+ buf[i] = 0;
+
+ // wait until changes are safe
+ sem_wait(&update_ok);
+
+ if (!strncmp(buf, "wpm", 3))
+ ks->wpm = wpm = atof(buf + 3);
+ else if (!strncmp(buf, "ramp", 4)) {
+ ramp = atof(buf + 4);
+ setCWToneGenVals(gen, gain, freq, ramp, ramp);
+ } else if (!strncmp(buf, "freq", 4)) {
+ freq = atof(buf + 4);
+ setCWToneGenVals(gen, gain, freq, ramp, ramp);
+ } else if (!strncmp(buf, "gain", 4)) {
+ gain = atof(buf + 4);
+ setCWToneGenVals(gen, gain, freq, ramp, ramp);
+ } else if (!strncmp(buf, "quit", 4))
+ goto finish;
+
+ } // otherwise go around again
+ }
+
+ // we saw an EOF or quit; kill other threads and exit neatly
+
+ finish:
+ pthread_cancel(play);
+ pthread_cancel(key);
+ pthread_exit(0);
+}
+DttSP_EXP void
+updateKeyer(double nfreq, BOOLEAN niambic, double ngain, double nramp, double nwpm,
+ BOOLEAN revpdl, int weight, double SampleRate) {
+ ks->flag.iambic = niambic;
+ iambic = niambic;
+ ks->flag.revpdl = revpdl;
+ ks->weight = weight;
+ wpm = nwpm;
+ gain = ngain;
+ ramp = nramp;
+ freq = nfreq;
+ gen->osc.freq = 2.0 * M_PI * freq / SampleRate;
+}
+DttSP_EXP void
+NewKeyer(double freq, BOOLEAN niambic, double gain, double ramp, double wpm, double SampleRate) {
+
+ void *usemem;
+
+ //------------------------------------------------------------
+
+ gen = newCWToneGen(gain, freq, ramp, ramp, TONE_SIZE, SampleRate);
+
+ //------------------------------------------------------------
+
+ kl = newKeyerLogic();
+ ks = newKeyerState();
+ ks->flag.iambic = niambic;
+ ks->flag.revpdl = TRUE; // depends on port wiring
+ ks->flag.autospace.khar = ks->flag.autospace.word = FALSE;
+ ks->debounce = 1; // could be more if sampled faster
+ ks->mode = MODE_B;
+ ks->weight = 50;
+ ks->wpm = wpm;
+ iambic = niambic;
+ size = 2048;
+ usemem = safealloc(1,4096*sizeof(float)+sizeof(ringb_t),"Keyer RB Left");
+ lring = ringb_create(usemem, 4096*sizeof(float));
+ usemem = safealloc(1,4096*sizeof(float)+sizeof(ringb_t),"Keyer RB Right");
+ rring = ringb_create(usemem,4096*sizeof(float));
+ ringb_clear(lring, size * sizeof(float));
+ ringb_clear(rring, size * sizeof(float));
+ sem_init(&clock_fired, 0, 0);
+ sem_init(&poll_fired , 0, 0);
+ sem_init(&keyer_started,0,0);
+}
+
+DttSP_EXP void
+delKeyer() {
+ sem_destroy(&clock_fired);
+ sem_destroy(&poll_fired);
+ sem_destroy(&keyer_started);
+ delCWToneGen(gen);
+ delKeyerState(ks);
+ delKeyerLogic(kl);
+ safefree((char *)lring);
+ safefree((char *)rring);
+}
+DttSP_EXP void
+KeyerClockFireWait()
+{
+ sem_wait(&clock_fired);
+}
+DttSP_EXP void
+KeyerClockFireRelease()
+{
+ sem_post(&clock_fired);
+}
+DttSP_EXP void
+KeyerStartedWait()
+{
+ sem_wait(&keyer_started);
+}
+DttSP_EXP void
+KeyerStartedRelease()
+{
+ sem_post(&keyer_started);
+}
+DttSP_EXP void
+PollTimerWait()
+{
+ sem_wait(&poll_fired);
+}
+DttSP_EXP void
+PollTimerRelease()
+{
+ sem_post(&poll_fired);
+}
+
+//------------------------------------------------------------------------
--- /dev/null
+#include <keyer.h>
+
+//========================================================================
+
+/* Read a straight key connected to a serial port, do debouncing, then
+ return the key state */
+
+BOOLEAN
+read_straight_key(KeyerState ks, BOOLEAN keyed) {
+ int i, j;
+ static BOOLEAN keystate = 0;
+ static int debounce_buf_i = 0,
+ debounce_buf[DEBOUNCE_BUF_MAX_SIZE];
+ debounce_buf[debounce_buf_i] = keyed;
+ debounce_buf_i++;
+
+ //
+ //***************************************************
+ // back to business as usual
+ //***************************************************
+
+ /* If the debounce buffer is full, determine the state of the key */
+ if (debounce_buf_i >= ks->debounce) {
+ debounce_buf_i = 0;
+
+ j = 0;
+ for (i = 0; i < ks->debounce; i++)
+ if (debounce_buf[i])
+ j++;
+ keystate = (j > ks->debounce / 2) ? 1 : 0;
+ }
+
+ return keystate;
+}
+
+//------------------------------------------------------------------------
+
+/* Read an iambic key connected to a serial port, do debouncing, emulate a
+ straight key, then return the emulated key state */
+
+BOOLEAN
+read_iambic_key(KeyerState ks, BOOLEAN dash, BOOLEAN dot, KeyerLogic kl, double ticklen) {
+ int i, j;
+ static BOOLEAN dah_debounce_buf[DEBOUNCE_BUF_MAX_SIZE],
+ dit_debounce_buf[DEBOUNCE_BUF_MAX_SIZE];
+ static int dah = 0, debounce_buf_i = 0, dit = 0;
+
+ if (ks->flag.revpdl) {
+ dah_debounce_buf[debounce_buf_i] = dot;
+ dit_debounce_buf[debounce_buf_i] = dash;
+ } else {
+ dah_debounce_buf[debounce_buf_i] = dash;
+ dit_debounce_buf[debounce_buf_i] = dot;
+ }
+ debounce_buf_i++;
+
+ //
+ //***************************************************
+ // back to business as usual
+ //***************************************************
+
+ /* If the debounce buffer is full, determine the state of the keys */
+ if (debounce_buf_i >= ks->debounce) {
+ debounce_buf_i = 0;
+
+ j = 0;
+ for (i = 0; i < ks->debounce; i++)
+ if (dah_debounce_buf[i]) j++;
+ dah = (j > ks->debounce / 2) ? 1 : 0;
+
+ j = 0;
+ for (i = 0; i < ks->debounce; i++)
+ if (dit_debounce_buf[i]) j++;
+ dit = (j > ks->debounce / 2) ? 1 : 0;
+ }
+
+ return klogic(kl,
+ dit,
+ dah,
+ ks->wpm,
+ ks->mode,
+ ks->flag.mdlmdB,
+ ks->flag.memory.dit,
+ ks->flag.memory.dah,
+ ks->flag.autospace.khar,
+ ks->flag.autospace.word,
+ ks->weight,
+ ticklen);
+}
+
+//========================================================================
--- /dev/null
+/* local.h
+
+Some manifest constants for the particular implementation
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+/* #include <fromsys.h> */
+/* #include <datatypes.h> */
+/* #include <banal.h> */
+/* #include <fftw.h> */
+/* #include <sdrexport.h> */
+
+#ifndef _local_h
+#define _local_h
+
+#include <common.h>
+//\\.\pipe\pipename
+#define RCBASE ".DttSPrc"
+#define PARMPATH "\\\\.\\pipe\\SDRcommands"
+#define METERPATH "\\\\.\\pipe\\SDRmeter"
+#define SPECPATH "\\\\.\\pipe\\SDRspectrum"
+#define WISDOMPATH ".\\wisdom"
+
+
+extern struct _loc {
+ char name[MAXPATHLEN];
+ struct {
+ char rcfile[MAXPATHLEN],
+ parm[MAXPATHLEN],
+ meter[MAXPATHLEN],
+ spec[MAXPATHLEN],
+ wisdom[MAXPATHLEN];
+ } path;
+ struct {
+ REAL rate;
+ int size, nrx, spec, comp;
+ SDRMODE mode;
+ } def;
+ struct { int ring;} mult;
+} loc;
+
+
+#endif
--- /dev/null
+/* sdr.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+//========================================================================
+/* initialization and termination */
+
+void
+reset_meters(void) {
+ if (uni.meter.flag) { // reset metering completely
+ int i, k;
+ for (i = 0; i < RXMETERPTS; i++)
+ for (k = 0; k < MAXRX; k++)
+ uni.meter.rx.val[k][i] = uni.meter.rx.avg[k][i] = -200.0;
+ for (i = 0; i < TXMETERPTS; i++)
+ uni.meter.tx.val[i] = uni.meter.tx.avg[i] = -200.0;
+ }
+}
+
+void
+reset_spectrum(void) {
+ if (uni.spec.flag)
+ reinit_spectrum(&uni.spec);
+}
+
+void
+reset_counters(void) {
+ int k;
+ for (k = 0; k < uni.multirx.nrx; k++) rx[k].tick = 0;
+ tx.tick = 0;
+}
+
+//========================================================================
+
+/* global and general info,
+ not specifically attached to
+ tx, rx, or scheduling */
+
+PRIVATE void
+setup_all(void) {
+
+ uni.samplerate = loc.def.rate;
+ uni.buflen = loc.def.size;
+ uni.mode.sdr = loc.def.mode;
+ uni.mode.trx = RX;
+
+ uni.wisdom.path = loc.path.wisdom;
+ uni.wisdom.bits = FFTW_OUT_OF_PLACE | FFTW_ESTIMATE;
+ {
+ FILE *f = fopen(uni.wisdom.path, "r");
+ if (f) {
+#define WBUFLEN 2048
+#define WSTRLEN 64
+ char *line = (char *)malloc(WBUFLEN);
+ fgets(line, WBUFLEN, f);
+ if ((strlen(line) > WSTRLEN) &&
+ (fftw_import_wisdom_from_string(line) != FFTW_FAILURE))
+ uni.wisdom.bits = FFTW_OUT_OF_PLACE | FFTW_MEASURE | FFTW_USE_WISDOM;
+#undef WSTRLEN
+#undef WBUFLEN
+ fclose(f);
+ free(line);
+ }
+
+ }
+
+ if (uni.meter.flag) {
+ uni.meter.rx.type = SIGNAL_STRENGTH;
+ uni.meter.tx.type = SIGNAL_STRENGTH;
+ reset_meters();
+ }
+
+ uni.spec.rxk = 0;
+ uni.spec.buflen = uni.buflen;
+ uni.spec.scale = SPEC_PWR;
+ uni.spec.type = SPEC_POST_FILT;
+ uni.spec.size = loc.def.spec;
+ uni.spec.planbits = uni.wisdom.bits;
+ init_spectrum(&uni.spec);
+
+ // set which receiver is listening to commands
+ uni.multirx.lis = 0;
+ uni.multirx.nrx = loc.def.nrx;
+
+ // set mixing of input from aux ports
+ uni.mix.rx.flag = uni.mix.tx.flag = FALSE;
+ uni.mix.rx.gain = uni.mix.tx.gain = 1.0;
+
+ uni.tick = 0;
+}
+
+/* purely rx */
+
+PRIVATE void
+setup_rx(int k) {
+
+ /* conditioning */
+ rx[k].iqfix = newCorrectIQ(0.0, 1.0);
+ rx[k].filt.coef = newFIR_Bandpass_COMPLEX(-4800.0,
+ 4800.0,
+ uni.samplerate,
+ uni.buflen + 1);
+ rx[k].filt.ovsv = newFiltOvSv(FIRcoef(rx[k].filt.coef),
+ FIRsize(rx[k].filt.coef),
+ uni.wisdom.bits);
+ normalize_vec_COMPLEX(rx[k].filt.ovsv->zfvec,
+ rx[k].filt.ovsv->fftlen);
+
+ // hack for EQ
+ rx[k].filt.save = newvec_COMPLEX(rx[k].filt.ovsv->fftlen, "RX filter cache");
+ memcpy((char *) rx[k].filt.save,
+ (char *) rx[k].filt.ovsv->zfvec,
+ rx[k].filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ /* buffers */
+ /* note we overload the internal filter buffers
+ we just created */
+ rx[k].buf.i = newCXB(FiltOvSv_fetchsize(rx[k].filt.ovsv),
+ FiltOvSv_fetchpoint(rx[k].filt.ovsv),
+ "init rx.buf.i");
+ rx[k].buf.o = newCXB(FiltOvSv_storesize(rx[k].filt.ovsv),
+ FiltOvSv_storepoint(rx[k].filt.ovsv),
+ "init rx[k].buf.o");
+
+ /* conversion */
+ rx[k].osc.freq = -11025.0;
+ rx[k].osc.phase = 0.0;
+ rx[k].osc.gen = newOSC(uni.buflen,
+ ComplexTone,
+ rx[k].osc.freq,
+ rx[k].osc.phase,
+ uni.samplerate,
+ "SDR RX Oscillator");
+
+ rx[k].agc.gen = newDigitalAgc(agcMED, // Mode
+ 7, // Hang
+ 7, // Size
+ 48, // Ramp
+ 3, // Over
+ 3, // Rcov
+ CXBsize(rx[k].buf.o), // BufSize
+ 100.0, // MaxGain
+ 0.707, // Limit
+ 1.0, // CurGain
+ CXBbase(rx[k].buf.o));
+ rx[k].agc.flag = TRUE;
+
+ /* demods */
+ rx[k].am.gen = newAMD(48000.0, // REAL samprate
+ 0.0, // REAL f_initial
+ -500.0, // REAL f_lobound,
+ 500.0, // REAL f_hibound,
+ 400.0, // REAL f_bandwid,
+ CXBsize(rx[k].buf.o), // int size,
+ CXBbase(rx[k].buf.o), // COMPLEX *ivec,
+ CXBbase(rx[k].buf.o), // COMPLEX *ovec,
+ AMdet, // AM Mode AMdet == rectifier,
+ // SAMdet == synchronous detector
+ "AM detector blew"); // char *tag
+ rx[k].fm.gen = newFMD(48000, // REAL samprate
+ 0.0, // REAL f_initial
+ -6000.0, // REAL f_lobound
+ 6000.0, // REAL f_hibound
+ 10000.0, // REAL f_bandwid
+ CXBsize(rx[k].buf.o), // int size
+ CXBbase(rx[k].buf.o), // COMPLEX *ivec
+ CXBbase(rx[k].buf.o), // COMPLEX *ovec
+ "New FM Demod structure"); // char *error message;
+
+ /* noise reduction */
+ rx[k].anf.gen = new_lmsr(rx[k].buf.o, // CXB signal,
+ 64, // int delay,
+ 0.01, // REAL adaptation_rate,
+ 0.00001, // REAL leakage,
+ 45, // int adaptive_filter_size,
+ LMADF_INTERFERENCE);
+ rx[k].anf.flag = FALSE;
+ rx[k].anr.gen = new_lmsr(rx[k].buf.o, // CXB signal,
+ 64, // int delay,
+ 0.01, // REAL adaptation_rate,
+ 0.00001, // REAL leakage,
+ 45, // int adaptive_filter_size,
+ LMADF_NOISE);
+ rx[k].anr.flag = FALSE;
+
+ rx[k].nb.thresh = 3.3;
+ rx[k].nb.gen = new_noiseblanker(rx[k].buf.i, rx[k].nb.thresh);
+ rx[k].nb.flag = FALSE;
+
+ rx[k].nb_sdrom.thresh = 2.5;
+ rx[k].nb_sdrom.gen = new_noiseblanker(rx[k].buf.i, rx[k].nb_sdrom.thresh);
+ rx[k].nb_sdrom.flag = FALSE;
+
+ rx[k].spot.gen = newSpotToneGen(-12.0, // gain
+ 700.0, // freq
+ 5.0, // ms rise
+ 5.0, // ms fall
+ uni.buflen,
+ uni.samplerate);
+
+ rx[k].scl.pre.val = 1.0;
+ rx[k].scl.pre.flag = FALSE;
+ rx[k].scl.post.val = 1.0;
+ rx[k].scl.post.flag = FALSE;
+
+ memset((char *) &rx[k].squelch, 0, sizeof(rx[k].squelch));
+ rx[k].squelch.thresh = -30.0;
+ rx[k].squelch.power = 0.0;
+ rx[k].squelch.flag = rx[k].squelch.running = rx[k].squelch.set = FALSE;
+ rx[k].squelch.num = (int) (0.0395 * uni.samplerate + 0.5);
+
+ rx[k].mode = uni.mode.sdr;
+ rx[k].bin.flag = FALSE;
+
+ {
+ REAL pos = 0.5, // 0 <= pos <= 1, left->right
+ theta = (1.0 - pos) * M_PI / 2.0;
+ rx[k].azim = Cmplx(cos(theta), sin(theta));
+ }
+
+ rx[k].tick = 0;
+}
+
+/* purely tx */
+
+PRIVATE void
+setup_tx(void) {
+
+ /* conditioning */
+ tx.iqfix = newCorrectIQ(0.0, 1.0);
+ tx.filt.coef = newFIR_Bandpass_COMPLEX(300.0,
+ 3000.0,
+ uni.samplerate,
+ uni.buflen + 1);
+ tx.filt.ovsv = newFiltOvSv(FIRcoef(tx.filt.coef),
+ FIRsize(tx.filt.coef),
+ uni.wisdom.bits);
+ normalize_vec_COMPLEX(tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen);
+
+ // hack for EQ
+ tx.filt.save = newvec_COMPLEX(tx.filt.ovsv->fftlen, "TX filter cache");
+ memcpy((char *) tx.filt.save,
+ (char *) tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ /* buffers */
+ tx.buf.i = newCXB(FiltOvSv_fetchsize(tx.filt.ovsv),
+ FiltOvSv_fetchpoint(tx.filt.ovsv),
+ "init tx.buf.i");
+ tx.buf.o = newCXB(FiltOvSv_storesize(tx.filt.ovsv),
+ FiltOvSv_storepoint(tx.filt.ovsv),
+ "init tx.buf.o");
+
+ /* conversion */
+ tx.osc.freq = 0.0;
+ tx.osc.phase = 0.0;
+ tx.osc.gen = newOSC(uni.buflen,
+ ComplexTone,
+ tx.osc.freq,
+ tx.osc.phase,
+ uni.samplerate,
+ "SDR TX Oscillator");
+
+ tx.agc.gen = newDigitalAgc(agcFAST, // Mode
+ 3, // Hang
+ 3, // Size
+ 3, // Over
+ 3, // Rcov
+ 48, // Ramp
+ CXBsize(tx.buf.o), // BufSize
+ 1.0, // MaxGain
+ 0.900, // Limit
+ 1.0, // CurGain
+ CXBbase(tx.buf.o));
+ tx.agc.flag = TRUE;
+
+ tx.spr.gen = newSpeechProc(0.4, 10.0, CXBbase(tx.buf.i), CXBsize(tx.buf.i));
+ tx.spr.flag = FALSE;
+
+ tx.scl.dc = cxzero;
+ tx.scl.pre.val = 1.0;
+ tx.scl.pre.flag = FALSE;
+ tx.scl.post.val = 1.0;
+ tx.scl.post.flag = FALSE;
+
+ tx.mode = uni.mode.sdr;
+
+ tx.tick = 0;
+ /* not much else to do for TX */
+}
+
+/* how the outside world sees it */
+
+void
+setup_workspace(void) {
+ int k;
+
+ setup_all();
+
+ for (k = 0; k < uni.multirx.nrx; k++) {
+ setup_rx(k);
+ uni.multirx.act[k] = FALSE;
+ }
+ uni.multirx.act[0] = TRUE;
+ uni.multirx.nac = 1;
+
+ setup_tx();
+}
+
+void
+destroy_workspace(void) {
+ int k;
+
+ /* TX */
+ delSpeechProc(tx.spr.gen);
+ delDigitalAgc(tx.agc.gen);
+ delOSC(tx.osc.gen);
+ delvec_COMPLEX(tx.filt.save);
+ delFiltOvSv(tx.filt.ovsv);
+ delFIR_Bandpass_COMPLEX(tx.filt.coef);
+ delCorrectIQ(tx.iqfix);
+ delCXB(tx.buf.o);
+ delCXB(tx.buf.i);
+
+ /* RX */
+ for (k = 0; k < uni.multirx.nrx; k++) {
+ delSpotToneGen(rx[k].spot.gen);
+ delDigitalAgc(rx[k].agc.gen);
+ del_nb(rx[k].nb_sdrom.gen);
+ del_nb(rx[k].nb.gen);
+ del_lmsr(rx[k].anf.gen);
+ del_lmsr(rx[k].anr.gen);
+ delAMD(rx[k].am.gen);
+ delFMD(rx[k].fm.gen);
+ delOSC(rx[k].osc.gen);
+ delvec_COMPLEX(rx[k].filt.save);
+ delFiltOvSv(rx[k].filt.ovsv);
+ delFIR_Bandpass_COMPLEX(rx[k].filt.coef);
+ delCorrectIQ(rx[k].iqfix);
+ delCXB(rx[k].buf.o);
+ delCXB(rx[k].buf.i);
+ }
+
+ /* all */
+ finish_spectrum(&uni.spec);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// execution
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+// util
+
+PRIVATE REAL
+CXBnorm(CXB buff) {
+ int i;
+ double sum = 0.0;
+ for (i = 0; i < CXBhave(buff); i++)
+ sum += Csqrmag(CXBdata(buff, i));
+ return sqrt(sum);
+}
+
+//========================================================================
+/* all */
+
+// unfortunate duplication here, due to
+// multirx vs monotx
+
+PRIVATE void
+do_rx_meter(int k, CXB buf, int tap) {
+ COMPLEX *vec = CXBbase(buf);
+ int i, len = CXBhave(buf);
+
+ uni.meter.rx.val[k][tap] = 0;
+
+ switch (uni.meter.rx.type) {
+ case AVG_SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+ uni.meter.rx.val[k][tap] =
+ uni.meter.rx.avg[k][tap] =
+ 0.9 * uni.meter.rx.avg[k][tap] + log10(uni.meter.rx.val[k][tap] + 1e-20);
+ break;
+ case SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] += Csqrmag(vec[i]);
+ uni.meter.rx.avg[k][tap] =
+ uni.meter.rx.val[k][tap] =
+ 10.0 * log10(uni.meter.rx.val[k][tap] + 1e-20);
+ break;
+ case ADC_REAL:
+ for(i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] = max(fabs(vec[i].re), uni.meter.rx.val[k][tap]);
+ uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+ break;
+ case ADC_IMAG:
+ for(i = 0; i < len; i++)
+ uni.meter.rx.val[k][tap] = max(fabs(vec[i].im), uni.meter.rx.val[k][tap]);
+ uni.meter.rx.val[k][tap] = 20.0 * log10(uni.meter.rx.val[k][tap] + 1e-10);
+ break;
+ default:
+ break;
+ }
+}
+
+PRIVATE void
+do_tx_meter(CXB buf, int tap) {
+ COMPLEX *vec = CXBbase(buf);
+ int i, len = CXBhave(buf);
+
+ uni.meter.tx.val[tap] = 0;
+
+ switch (uni.meter.tx.type) {
+ case AVG_SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+ uni.meter.tx.val[tap] =
+ uni.meter.tx.avg[tap] =
+ 0.9 * uni.meter.tx.avg[tap] + log10(uni.meter.tx.val[tap] + 1e-20);
+ break;
+ case SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.tx.val[tap] += Csqrmag(vec[i]);
+ uni.meter.tx.avg[tap] =
+ uni.meter.tx.val[tap] =
+ 10.0 * log10(uni.meter.tx.val[tap] + 1e-20);
+ break;
+ case ADC_REAL:
+ for(i = 0; i < len; i++)
+ uni.meter.tx.val[tap] = max(fabs(vec[i].re), uni.meter.tx.val[tap]);
+ uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
+ break;
+ case ADC_IMAG:
+ for(i = 0; i < len; i++)
+ uni.meter.tx.val[tap] = max(fabs(vec[i].im), uni.meter.tx.val[tap]);
+ uni.meter.tx.val[tap] = 20.0 * log10(uni.meter.tx.val[tap] + 1e-10);
+ break;
+ default:
+ break;
+ }
+}
+
+PRIVATE void
+do_rx_spectrum(int k, CXB buf, int type) {
+ if (uni.spec.flag && k == uni.spec.rxk && type == uni.spec.type) {
+ memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+ (char *) CXBbase(buf),
+ CXBhave(buf));
+ uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
+ }
+}
+
+PRIVATE void
+do_tx_spectrum(CXB buf) {
+ memcpy((char *) &CXBdata(uni.spec.accum, uni.spec.fill),
+ (char *) CXBbase(buf),
+ CXBhave(buf));
+ uni.spec.fill = (uni.spec.fill + uni.spec.buflen) % uni.spec.size;
+}
+
+//========================================================================
+/* RX processing */
+
+PRIVATE BOOLEAN
+should_do_rx_squelch(int k) {
+ if (rx[k].squelch.flag) {
+ int i, n = CXBhave(rx[k].buf.o);
+ rx[k].squelch.power = 0.0;
+ for (i = 0; i < n; i++)
+ rx[k].squelch.power += Csqrmag(CXBdata(rx[k].buf.o, i));
+ return rx[k].squelch.thresh > 10.0 * log10(rx[k].squelch.power);
+ } else
+ return rx[k].squelch.set = FALSE;
+}
+
+// apply squelch
+// slew into silence first time
+
+PRIVATE void
+do_squelch(int k) {
+ rx[k].squelch.set = TRUE;
+ if (!rx[k].squelch.running) {
+ int i, m = rx[k].squelch.num, n = CXBhave(rx[k].buf.o) - m;
+ for (i = 0; i < m; i++)
+ CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i), 1.0 - (REAL) i / m);
+ memset((void *) (CXBbase(rx[k].buf.o) + m), 0, n * sizeof(COMPLEX));
+ rx[k].squelch.running = TRUE;
+ } else
+ memset((void *) CXBbase(rx[k].buf.o), 0, CXBhave(rx[k].buf.o) * sizeof(COMPLEX));
+}
+
+// lift squelch
+// slew out from silence to full scale
+
+PRIVATE void
+no_squelch(int k) {
+ if (rx[k].squelch.running) {
+ int i, m = rx[k].squelch.num;
+ for (i = 0; i < m; i++)
+ CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i), (REAL) i / m);
+ rx[k].squelch.running = FALSE;
+ }
+}
+
+/* pre-condition for (nearly) all RX modes */
+
+PRIVATE void
+do_rx_pre(int k) {
+ int i, n = min(CXBhave(rx[k].buf.i), uni.buflen);
+
+ if (rx[k].scl.pre.flag)
+ for (i = 0; i < n; i++)
+ CXBdata(rx[k].buf.i, i) = Cscl(CXBdata(rx[k].buf.i, i),
+ rx[k].scl.pre.val);
+
+ if (rx[k].nb.flag) noiseblanker(rx[k].nb.gen);
+ if (rx[k].nb_sdrom.flag) SDROMnoiseblanker(rx[k].nb_sdrom.gen);
+
+ // metering for uncorrected values here
+
+ do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_CONV);
+
+ correctIQ(rx[k].buf.i, rx[k].iqfix);
+
+ /* 2nd IF conversion happens here */
+
+ if (rx[k].osc.gen->Frequency != 0.0) {
+ ComplexOSC(rx[k].osc.gen);
+ for (i = 0; i < n; i++)
+ CXBdata(rx[k].buf.i, i) = Cmul(CXBdata(rx[k].buf.i, i),
+ OSCCdata(rx[k].osc.gen, i));
+ }
+
+ /* filtering, metering, spectrum, squelch, & AGC */
+
+ if (rx[k].mode == SPEC)
+
+ do_rx_spectrum(k, rx[k].buf.i, SPEC_SEMI_RAW);
+
+ else {
+
+ do_rx_meter(k, rx[k].buf.i, RXMETER_PRE_FILT);
+ do_rx_spectrum(k, rx[k].buf.i, SPEC_PRE_FILT);
+
+ if (rx[k].tick == 0)
+ reset_OvSv(rx[k].filt.ovsv);
+
+ filter_OvSv(rx[k].filt.ovsv);
+ CXBhave(rx[k].buf.o) = CXBhave(rx[k].buf.i);
+
+ do_rx_meter(k, rx[k].buf.o, RXMETER_POST_FILT);
+ do_rx_spectrum(k, rx[k].buf.o, SPEC_POST_FILT);
+
+ if (should_do_rx_squelch(k))
+ do_squelch(k);
+
+ else if (rx[k].agc.flag)
+ DigitalAgc(rx[k].agc.gen, rx[k].tick);
+
+ }
+}
+
+PRIVATE void
+do_rx_post(int k) {
+ int i, n = CXBhave(rx[k].buf.o);
+
+ if (!rx[k].squelch.set) {
+ no_squelch(k);
+ // spotting tone
+ if (rx[k].spot.flag) {
+ // remember whether it's turned itself off during this pass
+ rx[k].spot.flag = SpotTone(rx[k].spot.gen);
+ for (i = 0; i < n; i++)
+ CXBdata(rx[k].buf.o, i) = Cadd(CXBdata(rx[k].buf.o, i),
+ CXBdata(rx[k].spot.gen->buf, i));
+ }
+ }
+
+ // final scaling
+
+ if (rx[k].scl.post.flag)
+ for (i = 0; i < n; i++)
+ CXBdata(rx[k].buf.o, i) = Cscl(CXBdata(rx[k].buf.o, i),
+ rx[k].scl.post.val);
+
+ // not binaural?
+ // position in stereo field
+
+ if (!rx[k].bin.flag)
+ for (i = 0; i < n; i++)
+ CXBdata(rx[k].buf.o, i) = Cscl(rx[k].azim, CXBreal(rx[k].buf.o, i));
+}
+
+/* demod processing */
+
+PRIVATE void
+do_rx_SBCW(int k) {
+ if (rx[k].anr.flag) lmsr_adapt(rx[k].anr.gen);
+ if (rx[k].anf.flag) lmsr_adapt(rx[k].anf.gen);
+}
+
+PRIVATE void
+do_rx_AM(int k) { AMDemod(rx[k].am.gen); }
+
+PRIVATE void
+do_rx_FM(int k) { FMDemod(rx[k].fm.gen); }
+
+PRIVATE void
+do_rx_DRM(int k) {}
+
+PRIVATE void
+do_rx_SPEC(int k) {
+ memcpy(CXBbase(rx[k].buf.o),
+ CXBbase(rx[k].buf.i),
+ sizeof(COMPLEX) * CXBhave(rx[k].buf.i));
+ if (rx[k].agc.flag) DigitalAgc(rx[k].agc.gen, rx[k].tick);
+}
+
+PRIVATE void
+do_rx_NIL(int k) {
+ int i, n = min(CXBhave(rx[k].buf.i), uni.buflen);
+ for (i = 0; i < n; i++) CXBdata(rx[k].buf.o, i) = cxzero;
+}
+
+/* overall dispatch for RX processing */
+
+PRIVATE void
+do_rx(int k) {
+ do_rx_pre(k);
+ switch (rx[k].mode) {
+ case USB:
+ case LSB:
+ case CWU:
+ case CWL:
+ case DSB: do_rx_SBCW(k); break;
+ case AM:
+ case SAM: do_rx_AM(k); break;
+ case FMN: do_rx_FM(k); break;
+ case DRM: do_rx_DRM(k); break;
+ case SPEC:
+ default: do_rx_SPEC(k); break;
+ }
+ do_rx_post(k);
+}
+
+//==============================================================
+/* TX processing */
+
+/* pre-condition for (nearly) all TX modes */
+
+PRIVATE void
+do_tx_pre(void) {
+
+if (tx.scl.pre.flag) {
+int i, n = CXBhave(tx.buf.i);
+ for (i = 0; i < n; i++)
+ CXBdata(tx.buf.i, i) = Cmplx(CXBreal(tx.buf.i, i) * tx.scl.pre.val, 0.0);
+ }
+
+ correctIQ(tx.buf.i, tx.iqfix);
+
+ if (tx.spr.flag) SpeechProcessor(tx.spr.gen);
+
+ if (tx.tick == 0) reset_OvSv(tx.filt.ovsv);
+ filter_OvSv(tx.filt.ovsv);
+}
+
+PRIVATE void
+do_tx_post(void) {
+ CXBhave(tx.buf.o) = CXBhave(tx.buf.i);
+
+ if (tx.agc.flag) DigitalAgc(tx.agc.gen, tx.tick);
+
+ // meter modulated signal
+
+ do_tx_meter(tx.buf.o, TXMETER_POST_MOD);
+
+ if (tx.scl.post.flag) {
+ int i, n = CXBhave(tx.buf.o);
+ for (i = 0; i < n; i++)
+ CXBdata(tx.buf.o, i) = Cscl(CXBdata(tx.buf.o, i), tx.scl.post.val);
+ }
+
+ if (uni.spec.flag)
+ do_tx_spectrum(tx.buf.o);
+
+ if (tx.osc.gen->Frequency != 0.0) {
+ int i;
+ ComplexOSC(tx.osc.gen);
+ for (i = 0; i < CXBhave(tx.buf.o); i++)
+ CXBdata(tx.buf.o, i) = Cmul(CXBdata(tx.buf.o, i), OSCCdata(tx.osc.gen, i));
+ }
+}
+
+/* modulator processing */
+
+PRIVATE void
+do_tx_SBCW(void) {
+ int i, n = min(CXBhave(tx.buf.o), uni.buflen);
+
+ if ((tx.norm = CXBnorm(tx.buf.o)) > 0.0)
+ for (i = 0; i < n; i++) {
+ tx.scl.dc = Cadd(Cscl(tx.scl.dc, 0.99),
+ Cscl(CXBdata(tx.buf.o, i), -0.01));
+ CXBdata(tx.buf.o, i) = Cadd(CXBdata(tx.buf.o, i), tx.scl.dc);
+ }
+}
+
+PRIVATE void
+do_tx_AM(void) {
+ int i, n = min(CXBhave(tx.buf.o), uni.buflen);
+
+ if ((tx.norm = CXBnorm(tx.buf.o)) > 0.0)
+ for (i = 0; i < n; i++) {
+ tx.scl.dc = Cadd(Cscl(tx.scl.dc, 0.999),
+ Cscl(CXBdata(tx.buf.o, i), -0.001));
+ CXBreal(tx.buf.o, i) =
+ 0.49995 + 0.49995 * (CXBreal(tx.buf.o, i) - tx.scl.dc.re);
+ CXBimag(tx.buf.o, i) = 0.0;
+ }
+}
+
+PRIVATE void
+do_tx_FM(void) {
+ int i, n = min(CXBhave(tx.buf.o), uni.buflen);
+ if ((tx.norm = CXBnorm(tx.buf.o)) > 0.0)
+ for (i = 0; i < n; i++) {
+ tx.scl.dc = Cadd(Cscl(tx.scl.dc, 0.999),
+ Cscl(CXBdata(tx.buf.o, i), 0.001));
+ tx.osc.phase += (CXBreal(tx.buf.o, i) - tx.scl.dc.re) * CvtMod2Freq;
+ if (tx.osc.phase >= TWOPI) tx.osc.phase -= TWOPI;
+ if (tx.osc.phase < 0.0) tx.osc.phase += TWOPI;
+ CXBdata(tx.buf.o, i) =
+ Cscl(Cmplx(cos(tx.osc.phase), sin(tx.osc.phase)), 0.99999);
+ }
+}
+
+PRIVATE void
+do_tx_NIL(void) {
+ int i, n = min(CXBhave(tx.buf.i), uni.buflen);
+ for (i = 0; i < n; i++) CXBdata(tx.buf.o, i) = cxzero;
+}
+
+/* general TX processing dispatch */
+
+PRIVATE void
+do_tx(void) {
+ do_tx_pre();
+ switch (tx.mode) {
+ case USB:
+ case LSB:
+ case CWU:
+ case CWL:
+ case DSB: do_tx_SBCW(); break;
+ case AM:
+ case SAM: do_tx_AM(); break;
+ case FMN: do_tx_FM(); break;
+ case DRM:
+ case SPEC:
+ default: do_tx_NIL(); break;
+ }
+ do_tx_post();
+}
+
+//========================================================================
+/* overall buffer processing;
+ come here when there are buffers to work on */
+
+void
+process_samples(float *bufl, float *bufr,
+ float *auxl, float *auxr,
+ int n) {
+ int i, k;
+
+ switch (uni.mode.trx) {
+
+ case RX:
+
+ // make copies of the input for all receivers
+ for (k = 0; k < uni.multirx.nrx; k++)
+ if (uni.multirx.act[k]) {
+ for (i = 0; i < n; i++)
+ CXBimag(rx[k].buf.i, i) = bufl[i], CXBreal(rx[k].buf.i, i) = bufr[i];
+ CXBhave(rx[k].buf.i) = n;
+ }
+
+ // prepare buffers for mixing
+ memset((char *) bufl, 0, n * sizeof(float));
+ memset((char *) bufr, 0, n * sizeof(float));
+
+ // run all receivers
+ for (k = 0; k < uni.multirx.nrx; k++)
+ if (uni.multirx.act[k]) {
+ do_rx(k), rx[k].tick++;
+ // mix
+ for (i = 0; i < n; i++)
+ bufl[i] += (float)CXBimag(rx[k].buf.o, i),
+ bufr[i] += (float)CXBreal(rx[k].buf.o, i);
+ CXBhave(rx[k].buf.o) = n;
+ }
+
+ // late mixing of aux buffers
+ if (uni.mix.rx.flag)
+ for (i = 0; i < n; i++)
+ bufl[i] += (float)(auxl[i] * uni.mix.rx.gain),
+ bufr[i] += (float)(auxr[i] * uni.mix.rx.gain);
+
+ break;
+
+ case TX:
+
+ // early mixing of aux buffers
+ if (uni.mix.tx.flag)
+ for (i = 0; i < n; i++)
+ bufl[i] += (float)(auxl[i] * uni.mix.tx.gain),
+ bufr[i] += (float)(auxr[i] * uni.mix.tx.gain);
+
+ for (i = 0; i < n; i++)
+ CXBimag(tx.buf.i, i) = bufl[i], CXBreal(tx.buf.i, i) = bufr[i];
+ CXBhave(tx.buf.i) = n;
+
+ do_tx(), tx.tick++;
+
+ for (i = 0; i < n; i++)
+ bufl[i] = (float) CXBimag(tx.buf.o, i), bufr[i] = (float) CXBreal(tx.buf.o, i);
+ CXBhave(tx.buf.o) = n;
+
+ break;
+ }
+
+ uni.tick++;
+}
--- /dev/null
+/* sdrexport.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+struct _uni uni;
+struct _rx rx[MAXRX];
+struct _tx tx;
+struct _top top;
--- /dev/null
+/* main.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004-5 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+/////////////////////////////////////////////////////////////////////////
+
+// Windows SHTUFF
+
+PRIVATE CRITICAL_SECTION csobj;
+PRIVATE CRITICAL_SECTION cs_updobj;
+PRIVATE LPCRITICAL_SECTION cs;
+PRIVATE LPCRITICAL_SECTION cs_upd;
+PRIVATE BOOLEAN IC = FALSE;
+
+// elementary defaults
+struct _loc loc;
+
+/////////////////////////////////////////////////////////////////////////
+// most of what little we know here about the inner loop,
+// functionally speaking
+
+extern void reset_meters(void);
+extern void reset_spectrum(void);
+extern void reset_counters(void);
+extern void process_samples(float *, float *, float *, float *, int);
+extern void setup_workspace(void);
+extern void destroy_workspace(void);
+
+//========================================================================
+
+PRIVATE void
+spectrum_thread(void)
+{
+ DWORD NumBytesWritten;
+ while (top.running) {
+ sem_wait(&top.sync.pws.sem);
+ compute_spectrum(&uni.spec);
+ WriteFile(top.meas.spec.fd, (LPVOID) & uni.spec.label,
+ sizeof(int), &NumBytesWritten, NULL);
+ WriteFile(top.meas.spec.fd, (LPVOID) uni.spec.output,
+ sizeof(float) * uni.spec.size, &NumBytesWritten, NULL);
+ }
+ pthread_exit(0);
+}
+
+/*PRIVATE void
+scope_thread(void) {
+ DWORD NumBytesWritten;
+ while (top.running) {
+ sem_wait(&top.sync.scope.sem);
+ compute_spectrum(&uni.spec);
+ WriteFile(top.meas.scope.fd,(LPVOID)&uni.spec.label,
+ sizeof(int),&NumBytesWritten,NULL);
+ WriteFile(top.meas.scope.fd,(LPVOID)uni.spec.accum,
+ sizeof(float)*uni.spec.size,&NumBytesWritten,NULL);
+ }
+ pthread_exit(0);
+} */
+
+PRIVATE void
+meter_thread(void)
+{
+ DWORD NumBytesWritten;
+ while (top.running) {
+ sem_wait(&top.sync.mtr.sem);
+ WriteFile(top.meas.mtr.fd, (LPVOID) & uni.meter.label, sizeof(int),
+ &NumBytesWritten, NULL);
+ WriteFile(top.meas.mtr.fd, (LPVOID) & uni.meter.snap.rx,
+ sizeof(REAL) * MAXRX * RXMETERPTS, &NumBytesWritten, NULL);
+ WriteFile(top.meas.mtr.fd, (LPVOID) & uni.meter.snap.tx,
+ sizeof(REAL) * TXMETERPTS, &NumBytesWritten, NULL);
+ }
+ pthread_exit(0);
+}
+
+//========================================================================
+
+PRIVATE void
+monitor_thread(void)
+{
+ while (top.running) {
+ sem_wait(&top.sync.mon.sem);
+ /* If there is anything that needs monitoring, do it here */
+ fprintf(stderr,
+ "@@@ mon [%d]: cb = %d rbi = %d rbo = %d xr = %d\n",
+ uni.tick,
+ top.jack.blow.cb,
+ top.jack.blow.rb.i, top.jack.blow.rb.o, top.jack.blow.xr);
+ memset((char *) &top.jack.blow, 0, sizeof(top.jack.blow));
+ }
+ pthread_exit(0);
+
+}
+
+//========================================================================
+
+PRIVATE void
+process_updates_thread(void)
+{
+
+ while (top.running) {
+ DWORD NumBytesRead;
+ pthread_testcancel();
+ while (ReadFile(top.parm.fd, top.parm.buff, 256, &NumBytesRead, NULL)) {
+ fprintf(stderr, "Update Bytes:%lu Msg:%s\n", NumBytesRead,
+ top.parm.buff), fflush(stderr);
+ if (NumBytesRead != 0)
+ do_update(top.parm.buff, top.verbose ? stderr : 0);
+ }
+ }
+ pthread_exit(0);
+}
+
+//========================================================================
+
+
+PRIVATE void
+gethold(void)
+{
+ EnterCriticalSection(cs);
+ if (ringb_write_space(top.jack.ring.o.l)
+ < top.hold.size.bytes) {
+ // pathology
+ ringb_reset(top.jack.ring.o.l);
+ ringb_reset(top.jack.ring.o.r);
+ top.jack.blow.rb.o++;
+ }
+ ringb_write(top.jack.ring.o.l,
+ (char *) top.hold.buf.l, top.hold.size.bytes);
+ ringb_write(top.jack.ring.o.r,
+ (char *) top.hold.buf.r, top.hold.size.bytes);
+ if (ringb_read_space(top.jack.ring.i.l)
+ < top.hold.size.bytes) {
+ // pathology
+ ringb_reset(top.jack.ring.i.l);
+ ringb_reset(top.jack.ring.i.r);
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ ringb_reset(top.jack.auxr.i.l);
+ ringb_reset(top.jack.auxr.i.r);
+ memset((char *) top.hold.aux.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.aux.r, 0, top.hold.size.bytes);
+ top.jack.blow.rb.i++;
+ } else {
+ ringb_read(top.jack.ring.i.l,
+ (char *) top.hold.buf.l, top.hold.size.bytes);
+ ringb_read(top.jack.ring.i.r,
+ (char *) top.hold.buf.r, top.hold.size.bytes);
+ ringb_read(top.jack.auxr.i.l,
+ (char *) top.hold.aux.l, top.hold.size.bytes);
+ ringb_read(top.jack.auxr.i.r,
+ (char *) top.hold.aux.r, top.hold.size.bytes);
+ }
+ LeaveCriticalSection(cs);
+}
+
+PRIVATE BOOLEAN
+canhold(void)
+{
+ BOOLEAN answer;
+ EnterCriticalSection(cs);
+ answer = (ringb_read_space(top.jack.ring.i.l) >= top.hold.size.bytes);
+ LeaveCriticalSection(cs);
+ return answer;
+}
+
+
+//------------------------------------------------------------------------
+
+PRIVATE void
+run_mute(void)
+{
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ memset((char *) top.hold.aux.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.aux.r, 0, top.hold.size.bytes);
+ uni.tick++;
+}
+
+PRIVATE void
+run_pass(void)
+{
+ uni.tick++;
+}
+
+PRIVATE void
+run_play(void)
+{
+ process_samples(top.hold.buf.l, top.hold.buf.r,
+ top.hold.aux.l, top.hold.aux.r, top.hold.size.frames);
+}
+
+// NB do not set RUN_SWCH directly via setRunState;
+// use setSWCH instead
+
+PRIVATE void
+run_swch(void)
+{
+ if (top.swch.bfct.have == 0) {
+ // first time
+ // apply ramp down
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) 1.0 - (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ memset((char *) (top.hold.buf.l + m), 0, n);
+ memset((char *) (top.hold.buf.r + m), 0, n);
+ top.swch.bfct.have++;
+ } else if (top.swch.bfct.have < top.swch.bfct.want) {
+ // in medias res
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ top.swch.bfct.have++;
+ } else {
+ // last time
+ // apply ramp up
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ uni.mode.trx = top.swch.trx.next;
+ switch (uni.mode.trx) {
+ int i;
+ case TX:
+ tx.agc.gen->over = tx.tick + 3;
+ break;
+ case RX:
+ for (i = 0; i < uni.multirx.nrx; i++)
+ rx[i].agc.gen->over = rx[i].tick + 3;
+ break;
+ }
+
+ top.state = top.swch.run.last;
+ top.swch.bfct.want = top.swch.bfct.have = 0;
+
+ ringb_reset(top.jack.ring.o.l);
+ ringb_reset(top.jack.ring.o.r);
+ ringb_clear(top.jack.ring.o.l, top.hold.size.bytes);
+ ringb_clear(top.jack.ring.o.r, top.hold.size.bytes);
+
+ reset_meters();
+ reset_spectrum();
+ reset_counters();
+ }
+
+ process_samples(top.hold.buf.l, top.hold.buf.r,
+ top.hold.aux.l, top.hold.aux.r, top.hold.size.frames);
+}
+
+//========================================================================
+
+
+
+DttSP_EXP void
+audio_callback(float *input_l, float *input_r, float *output_l,
+ float *output_r, int nframes)
+{
+ size_t nbytes = sizeof(float) * nframes;
+
+
+ EnterCriticalSection(cs);
+
+
+ if (ringb_read_space(top.jack.ring.o.l) >= nbytes) {
+ ringb_read(top.jack.ring.o.l, (char *) output_l, nbytes);
+ ringb_read(top.jack.ring.o.r, (char *) output_r, nbytes);
+ } else { // rb pathology
+ memset((char *) output_l, 0, nbytes);
+ memset((char *) output_r, 0, nbytes);
+ ringb_restart(top.jack.ring.o.l, nbytes);
+ ringb_restart(top.jack.ring.o.r, nbytes);
+ top.jack.blow.rb.o++;
+ }
+
+ // input: copy from port to ring
+ if (ringb_write_space(top.jack.ring.i.l) >= nbytes) {
+ ringb_write(top.jack.ring.i.l, (char *) input_l, nbytes);
+ ringb_write(top.jack.ring.i.r, (char *) input_r, nbytes);
+ ringb_write(top.jack.auxr.i.l, (char *) input_l, nbytes);
+ ringb_write(top.jack.auxr.i.r, (char *) input_r, nbytes);
+ } else { // rb pathology
+ ringb_restart(top.jack.ring.i.l, nbytes);
+ ringb_restart(top.jack.ring.i.r, nbytes);
+ ringb_restart(top.jack.auxr.i.l, nbytes);
+ ringb_restart(top.jack.auxr.i.r, nbytes);
+ top.jack.blow.rb.i++;
+ }
+ LeaveCriticalSection(cs);
+ // if enough accumulated in ring, fire dsp
+ if (ringb_read_space(top.jack.ring.i.l) >= top.hold.size.bytes)
+ sem_post(&top.sync.buf.sem);
+
+ // check for blowups
+ if ((top.jack.blow.cb > 0) ||
+ (top.jack.blow.rb.i > 0) || (top.jack.blow.rb.o > 0))
+ sem_post(&top.sync.mon.sem);
+}
+
+//========================================================================
+
+DttSP_EXP void
+process_samples_thread(void)
+{
+ while (top.running) {
+ sem_wait(&top.sync.buf.sem);
+ do {
+ gethold();
+ sem_wait(&top.sync.upd.sem);
+ switch (top.state) {
+ case RUN_MUTE:
+ run_mute();
+ break;
+ case RUN_PASS:
+ run_pass();
+ break;
+ case RUN_PLAY:
+ run_play();
+ break;
+ case RUN_SWCH:
+ run_swch();
+ break;
+ }
+ sem_post(&top.sync.upd.sem);
+ } while (canhold());
+ }
+}
+
+
+void
+closeup(void)
+{
+ top.running = FALSE;
+ Sleep(50);
+ safefree((char *) top.jack.ring.o.r);
+ safefree((char *) top.jack.ring.o.l);
+ safefree((char *) top.jack.ring.i.r);
+ safefree((char *) top.jack.ring.i.l);
+ safefree((char *) top.jack.auxr.i.l);
+ safefree((char *) top.jack.auxr.i.r);
+ safefree((char *) top.jack.auxr.o.l);
+ safefree((char *) top.jack.auxr.o.r);
+
+ CloseHandle(top.parm.fp);
+ DisconnectNamedPipe(top.parm.fd);
+ CloseHandle(top.parm.fd);
+
+
+ if (uni.meter.flag) {
+ CloseHandle(top.meas.mtr.fp);
+ DisconnectNamedPipe(top.meas.mtr.fd);
+ CloseHandle(top.meas.mtr.fd);
+ };
+
+ if (uni.spec.flag) {
+ CloseHandle(top.meas.spec.fp);
+ DisconnectNamedPipe(top.meas.spec.fd);
+ CloseHandle(top.meas.spec.fd);
+ };
+ destroy_workspace();
+}
+
+//........................................................................
+
+PRIVATE void
+setup_switching(void)
+{
+ top.swch.fade = (int) (0.1 * uni.buflen + 0.5);
+ top.swch.tail = (top.hold.size.frames - top.swch.fade) * sizeof(float);
+}
+
+PRIVATE void
+setup_local_audio(void)
+{
+ top.hold.size.frames = uni.buflen;
+ top.hold.size.bytes = top.hold.size.frames * sizeof(float);
+ top.hold.buf.l = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer left");
+ top.hold.buf.r = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer right");
+ top.hold.aux.l = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "aux hold buffer left");
+ top.hold.aux.r = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "aux hold buffer right");
+}
+
+#include <lmerr.h>
+
+PRIVATE void
+DisplayErrorText(DWORD dwLastError)
+{
+ HMODULE hModule = NULL; // default to system source
+ LPSTR MessageBuffer;
+ DWORD dwBufferLength;
+
+ DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
+
+ //
+ // If dwLastError is in the network range,
+ // load the message source.
+ //
+
+ if (dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
+ hModule = LoadLibraryEx(TEXT("netmsg.dll"),
+ NULL, LOAD_LIBRARY_AS_DATAFILE);
+
+ if (hModule != NULL)
+ dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
+ }
+ //
+ // Call FormatMessage() to allow for message
+ // text to be acquired from the system
+ // or from the supplied module handle.
+ //
+
+ if (dwBufferLength = FormatMessageA(dwFormatFlags, hModule, // module to get message from (NULL == system)
+ dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
+ (LPSTR) & MessageBuffer, 0, NULL)) {
+ DWORD dwBytesWritten;
+
+ //
+ // Output message string on stderr.
+ //
+ WriteFile(GetStdHandle(STD_ERROR_HANDLE),
+ MessageBuffer, dwBufferLength, &dwBytesWritten, NULL);
+
+ //
+ // Free the buffer allocated by the system.
+ //
+ LocalFree(MessageBuffer);
+ }
+ //
+ // If we loaded a message source, unload it.
+ //
+ if (hModule != NULL)
+ FreeLibrary(hModule);
+}
+
+
+
+PRIVATE sem_t setup_update_sem;
+
+PRIVATE void
+setup_update_server()
+{
+
+ if (INVALID_HANDLE_VALUE == (top.parm.fd = CreateNamedPipe(top.parm.path,
+ PIPE_ACCESS_INBOUND,
+ PIPE_WAIT |
+ PIPE_TYPE_MESSAGE
+ |
+ PIPE_READMODE_MESSAGE,
+ PIPE_UNLIMITED_INSTANCES,
+ 512, 512,
+ INFINITE,
+ NULL))) {
+ fprintf(stderr, "Update server pipe setup failed:\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+// fprintf(stderr,"Update NamedPipe made\n"),fflush(stderr);
+ sem_post(&setup_update_sem);
+ if (ConnectNamedPipe(top.parm.fd, NULL)) {
+// fprintf(stderr,"Connected the server to the Update pipe\n"),fflush(stderr);
+ } else {
+ fprintf(stderr, "Connected the server to the Update pipe failed\n"),
+ fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ pthread_exit(0);
+}
+
+
+PRIVATE void
+setup_update_client()
+{
+// fprintf(stderr,"Looking for the Update server\n"),fflush(stderr);
+ WaitNamedPipe(top.parm.path, INFINITE);
+// fprintf(stderr,"Found the Update server\n"),fflush(stderr);
+ if (INVALID_HANDLE_VALUE == (top.parm.fp = CreateFile(top.parm.path,
+ GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL))) {
+ fprintf(stderr, "The Update Client Open Failed\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ sem_post(&setup_update_sem);
+/* {
+ DWORD numwritten;
+ WriteFile(top.parm.fp,"test",5,&numwritten,NULL);
+ fprintf(stderr,"Number written to server: %lu\n",numwritten),fflush(stderr);
+ }*/
+ pthread_exit(0);
+}
+
+PRIVATE void
+setup_meter_server()
+{
+ top.meas.mtr.fd = CreateNamedPipe(top.meas.mtr.path,
+ PIPE_ACCESS_OUTBOUND,
+ PIPE_WAIT | PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE,
+ PIPE_UNLIMITED_INSTANCES, 512, 512,
+ INFINITE, NULL);
+// fprintf(stderr,"meter handle = %08X\n",(DWORD)top.meas.mtr.fd),fflush(stderr);
+ if (top.meas.mtr.fd == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Meter server pipe setup failed:\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"Meter Pipe Connect succeeded\n"),fflush(stderr);
+ sem_post(&setup_update_sem);
+ if (ConnectNamedPipe(top.meas.mtr.fd, NULL)) {
+// fprintf(stderr,"Connected the Meter Pooch\n"),fflush(stderr);
+ } else {
+ fprintf(stderr, "Meter Pipe Connect failed\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ }
+ pthread_exit(0);
+}
+
+PRIVATE void
+setup_meter_client()
+{
+// fprintf(stderr,"Looking for the meter server\n"),fflush(stderr);
+ if (WaitNamedPipe(top.meas.mtr.path, INFINITE)) {
+// fprintf(stderr,"Found the Meter server\n"),fflush(stderr);
+ if (INVALID_HANDLE_VALUE ==
+ (top.meas.mtr.fp =
+ CreateFile(top.meas.mtr.path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL))) {
+ fprintf(stderr, "The Meter Client Open Failed\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"The Meter Client Open Succeeded\n"),fflush(stderr);
+ }
+ } else {
+ fprintf(stderr, "Wait for meter pipe failed: Error message %d\n",
+ GetLastError()), fflush(stderr);
+ }
+ sem_post(&setup_update_sem);
+ pthread_exit(0);
+}
+
+PRIVATE void
+setup_spec_server()
+{
+
+ if (INVALID_HANDLE_VALUE ==
+ (top.meas.spec.fd =
+ CreateNamedPipe(top.meas.spec.path, PIPE_ACCESS_OUTBOUND,
+ PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
+ PIPE_UNLIMITED_INSTANCES, 32768, 32768, INFINITE,
+ NULL))) {
+ fprintf(stderr, "Spectrum pipe create failed\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"Spectrum Pipe %s Create succeeded\n",top.meas.spec.path),fflush(stderr);
+ sem_post(&setup_update_sem);
+ if (ConnectNamedPipe(top.meas.spec.fd, NULL)) {
+// fprintf(stderr,"Connected to the Spectrum Pipe\n"),fflush(stderr);
+ } else {
+ fprintf(stderr, "Spectrum pipe connect failed\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ }
+ pthread_exit(0);
+}
+
+PRIVATE void
+setup_spec_client()
+{
+// fprintf(stderr,"Looking for the spectrum server\n"),fflush(stderr);
+ if (WaitNamedPipe(top.meas.spec.path, INFINITE)) {
+// fprintf(stderr,"Found the server\n"),fflush(stderr);
+ if (INVALID_HANDLE_VALUE ==
+ (top.meas.spec.fp =
+ CreateFile(top.meas.spec.path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL))) {
+ fprintf(stderr, "The Spectrum Client Open Failed\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"The Spectrum Client Open Succeeded\n");
+// fprintf(stderr,"Spec Read handle = %08X\n",(DWORD)top.meas.spec.fp),fflush(stderr);
+ }
+ } else {
+ fprintf(stderr, "Wait for spec pipe failed\n"), fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ sem_post(&setup_update_sem);
+ pthread_exit(0);
+}
+PRIVATE pthread_t id1, id2, id3, id4, id5, id6;
+PRIVATE void
+setup_updates(void)
+{
+
+ char mesg[16384] = "TEST TEST METER\n";
+// DWORD NumBytes;
+ top.parm.path = loc.path.parm;
+ sem_init(&setup_update_sem, 0, 0);
+
+
+ if (uni.meter.flag) {
+ top.meas.mtr.path = loc.path.meter;
+ }
+ if (uni.spec.flag) {
+ top.meas.spec.path = loc.path.spec;
+ }
+
+ // Do this STUPID stuff to make use of the Named Pipe Mechanism in Windows
+ // For the update server
+
+
+ pthread_create(&id1, NULL, (void *) setup_update_server, NULL);
+ sem_wait(&setup_update_sem);
+ pthread_create(&id2, NULL, (void *) setup_update_client, NULL);
+ sem_wait(&setup_update_sem);
+ if (uni.meter.flag) {
+ pthread_create(&id3, NULL, (void *) setup_meter_server, NULL);
+ sem_wait(&setup_update_sem);
+ pthread_create(&id4, NULL, (void *) setup_meter_client, NULL);
+ sem_wait(&setup_update_sem);
+/* if (WriteFile(top.meas.mtr.fd,mesg,strlen(mesg)+1,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Meter Pipe write succeeded and wrote %lu bytes\n",NumBytes),fflush(stderr);
+ } else {
+ fprintf(stderr,"Meter Pipe write failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ if (ReadFile(top.meas.mtr.fp,mesg,256,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Meter Pipe read succeeded and %lu bytes read\n",NumBytes),fflush(stderr);
+ fprintf(stderr,"Meter message %s",mesg),fflush(stderr);
+ } else {
+ fprintf(stderr,"Meter Pipe read failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }*/
+
+ }
+
+ if (uni.spec.flag) {
+ memset(mesg, 0, 16384);
+ pthread_create(&id5, NULL, (void *) setup_spec_server, NULL);
+ sem_wait(&setup_update_sem);
+ pthread_create(&id6, NULL, (void *) setup_spec_client, NULL);
+ sem_wait(&setup_update_sem);
+ Sleep(0);
+/* if (WriteFile(top.meas.spec.fd,mesg,16384,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Spec Pipe write succeeded and wrote %lu bytes\n",NumBytes),fflush(stderr);
+ } else {
+ fprintf(stderr,"Spec Pipe write failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ fprintf(stderr,"Spec Read handle(2) = %08X\n",(DWORD)top.meas.spec.fp),fflush(stderr);
+ if (ReadFile(top.meas.spec.fp,mesg,16384,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Spec Pipe read succeeded and %lu bytes read\n",NumBytes),fflush(stderr);
+ } else {
+ fprintf(stderr,"Spec Pipe read failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } */
+ }
+ sem_destroy(&setup_update_sem);
+}
+PRIVATE void
+setup_system_audio(void)
+{
+ size_t ringsize;
+ void *usemem;
+ sprintf(top.jack.name, "sdr-%d", top.pid);
+ top.jack.size = uni.buflen;
+ ringsize = top.hold.size.bytes * loc.mult.ring + sizeof(ringb_t);
+ usemem = safealloc(ringsize, 1, "Ring Input Left");
+ top.jack.ring.i.l =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize, 1, "Ring Input Right");
+ top.jack.ring.i.r =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize, 1, "Ring Output Left");
+ top.jack.ring.o.l =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize, 1, "Ring Output Right");
+ top.jack.ring.o.r =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize, 1, "Ring Input Left Auxiliary");
+ top.jack.auxr.i.l =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize, 1, "Ring Input Right Auxiliary");
+ top.jack.auxr.i.r =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize, 1, "Ring Output Left Auxiliary");
+ top.jack.auxr.o.l =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize, 1, "Ring Output Right Auxiliary");
+ top.jack.auxr.o.r =
+ ringb_create(usemem, top.hold.size.bytes * loc.mult.ring);
+
+ ringb_clear(top.jack.ring.o.l, top.jack.size * sizeof(float));
+ ringb_clear(top.jack.ring.o.r, top.jack.size * sizeof(float));
+ ringb_clear(top.jack.auxr.o.l, top.jack.size * sizeof(float));
+ ringb_clear(top.jack.auxr.o.r, top.jack.size * sizeof(float));
+}
+
+PRIVATE void
+setup_threading(void)
+{
+ sem_init(&top.sync.upd.sem, 0, 0);
+ pthread_create(&top.thrd.upd.id, NULL, (void *) process_updates_thread,
+ NULL);
+ sem_init(&top.sync.buf.sem, 0, 0);
+ pthread_create(&top.thrd.trx.id, NULL, (void *) process_samples_thread,
+ NULL);
+ sem_init(&top.sync.mon.sem, 0, 0);
+ pthread_create(&top.thrd.mon.id, NULL, (void *) monitor_thread, NULL);
+ if (uni.meter.flag) {
+ sem_init(&top.sync.mtr.sem, 0, 0);
+ pthread_create(&top.thrd.mtr.id, NULL, (void *) meter_thread, NULL);
+ }
+ if (uni.spec.flag) {
+ sem_init(&top.sync.pws.sem, 0, 0);
+ pthread_create(&top.thrd.pws.id, NULL, (void *) spectrum_thread, NULL);
+ }
+ cs = &csobj;
+ InitializeCriticalSection(cs);
+}
+
+//========================================================================
+// hard defaults, then environment
+
+PRIVATE void
+setup_defaults(void)
+{
+ loc.name[0] = 0; // no default name for jack client
+ strcpy(loc.path.rcfile, RCBASE);
+ strcpy(loc.path.parm, PARMPATH);
+ strcpy(loc.path.meter, METERPATH);
+ strcpy(loc.path.spec, SPECPATH);
+ strcpy(loc.path.wisdom, WISDOMPATH);
+ loc.def.rate = DEFRATE;
+ loc.def.size = DEFSIZE;
+ loc.def.nrx = MAXRX;
+ loc.def.mode = DEFMODE;
+ loc.def.spec = DEFSPEC;
+ loc.mult.ring = RINGMULT;
+}
+
+//========================================================================
+void
+setup()
+{
+
+
+ top.pid = GetCurrentThreadId();
+ top.uid = 0L;
+ top.start_tv = now_tv();
+ top.running = TRUE;
+ top.verbose = FALSE;
+ top.state = RUN_PLAY;
+
+ setup_defaults();
+ top.verbose = FALSE;
+ uni.meter.flag = TRUE;
+ uni.spec.flag = TRUE;
+
+ setup_workspace();
+ setup_updates();
+
+ setup_local_audio();
+ setup_system_audio();
+
+ setup_threading();
+ setup_switching();
+ uni.spec.flag = TRUE;
+ uni.spec.type = SPEC_POST_FILT;
+ uni.spec.scale = SPEC_PWR;
+ uni.spec.rxk = 0;
+
+}
--- /dev/null
+/* main.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004-5 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+/////////////////////////////////////////////////////////////////////////
+
+// Windows SHTUFF
+
+PRIVATE CRITICAL_SECTION csobj;
+PRIVATE CRITICAL_SECTION cs_updobj;
+PRIVATE LPCRITICAL_SECTION cs;
+PRIVATE LPCRITICAL_SECTION cs_upd;
+PRIVATE BOOLEAN IC=FALSE;
+
+// elementary defaults
+struct _loc loc;
+
+/////////////////////////////////////////////////////////////////////////
+// most of what little we know here about the inner loop,
+// functionally speaking
+
+extern void reset_meters(void);
+extern void reset_spectrum(void);
+extern void reset_counters(void);
+extern void process_samples(float *, float *, float *, float *, int);
+extern void setup_workspace(void);
+extern void destroy_workspace(void);
+
+//========================================================================
+
+PRIVATE void
+spectrum_thread(void) {
+ DWORD NumBytesWritten;
+ while (top.running) {
+ sem_wait(&top.sync.pws.sem);
+ compute_spectrum(&uni.spec);
+ WriteFile(top.meas.spec.fd,(LPVOID)&uni.spec.label,
+ sizeof(int),&NumBytesWritten,NULL);
+ WriteFile(top.meas.spec.fd,(LPVOID)uni.spec.output,
+ sizeof(float)*uni.spec.size,&NumBytesWritten,NULL);
+ }
+ pthread_exit(0);
+}
+
+/*PRIVATE void
+scope_thread(void) {
+ DWORD NumBytesWritten;
+ while (top.running) {
+ sem_wait(&top.sync.scope.sem);
+ compute_spectrum(&uni.spec);
+ WriteFile(top.meas.scope.fd,(LPVOID)&uni.spec.label,
+ sizeof(int),&NumBytesWritten,NULL);
+ WriteFile(top.meas.scope.fd,(LPVOID)uni.spec.accum,
+ sizeof(float)*uni.spec.size,&NumBytesWritten,NULL);
+ }
+ pthread_exit(0);
+} */
+
+PRIVATE void
+meter_thread(void) {
+ DWORD NumBytesWritten;
+ while (top.running) {
+ sem_wait(&top.sync.mtr.sem);
+ WriteFile(top.meas.mtr.fd,(LPVOID)&uni.meter.label, sizeof(int),&NumBytesWritten,NULL);
+ WriteFile(top.meas.mtr.fd,(LPVOID)&uni.meter.snap.rx,sizeof(REAL)*MAXRX * RXMETERPTS,&NumBytesWritten,NULL);
+ WriteFile(top.meas.mtr.fd,(LPVOID)&uni.meter.snap.tx,sizeof(REAL)*TXMETERPTS,&NumBytesWritten,NULL);
+ }
+ pthread_exit(0);
+}
+
+//========================================================================
+
+PRIVATE void
+monitor_thread(void) {
+ while (top.running) {
+ sem_wait(&top.sync.mon.sem);
+ /* If there is anything that needs monitoring, do it here */
+ fprintf(stderr,
+ "@@@ mon [%d]: cb = %d rbi = %d rbo = %d xr = %d\n",
+ uni.tick,
+ top.jack.blow.cb,
+ top.jack.blow.rb.i,
+ top.jack.blow.rb.o,
+ top.jack.blow.xr);
+ memset((char *) &top.jack.blow, 0, sizeof(top.jack.blow));
+ }
+ pthread_exit(0);
+
+}
+
+//========================================================================
+
+PRIVATE void
+process_updates_thread(void) {
+
+ while (top.running) {
+ DWORD NumBytesRead;
+ pthread_testcancel();
+ while (ReadFile(top.parm.fd,top.parm.buff,256,&NumBytesRead,NULL))
+ {
+ fprintf(stderr,"Update Bytes:%lu Msg:%s\n",NumBytesRead,top.parm.buff),fflush(stderr);
+ if (NumBytesRead != 0) do_update(top.parm.buff, top.verbose ? stderr : 0);
+ }
+ }
+ pthread_exit(0);
+}
+
+//========================================================================
+
+
+PRIVATE void
+gethold(void) {
+ EnterCriticalSection(cs);
+ if (ringb_write_space(top.jack.ring.o.l)
+ < top.hold.size.bytes) {
+ // pathology
+ ringb_reset(top.jack.ring.o.l);
+ ringb_reset(top.jack.ring.o.r);
+ top.jack.blow.rb.o++;
+ }
+ ringb_write(top.jack.ring.o.l,
+ (char *) top.hold.buf.l,
+ top.hold.size.bytes);
+ ringb_write(top.jack.ring.o.r,
+ (char *) top.hold.buf.r,
+ top.hold.size.bytes);
+ if (ringb_read_space(top.jack.ring.i.l)
+ < top.hold.size.bytes) {
+ // pathology
+ ringb_reset(top.jack.ring.i.l);
+ ringb_reset(top.jack.ring.i.r);
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ ringb_reset(top.jack.auxr.i.l);
+ ringb_reset(top.jack.auxr.i.r);
+ memset((char *) top.hold.aux.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.aux.r, 0, top.hold.size.bytes);
+ top.jack.blow.rb.i++;
+ } else {
+ ringb_read(top.jack.ring.i.l,
+ (char *) top.hold.buf.l,
+ top.hold.size.bytes);
+ ringb_read(top.jack.ring.i.r,
+ (char *) top.hold.buf.r,
+ top.hold.size.bytes);
+ ringb_read(top.jack.auxr.i.l,
+ (char *) top.hold.aux.l,
+ top.hold.size.bytes);
+ ringb_read(top.jack.auxr.i.r,
+ (char *) top.hold.aux.r,
+ top.hold.size.bytes);
+ }
+ LeaveCriticalSection(cs);
+}
+
+PRIVATE BOOLEAN
+canhold(void) {
+ BOOLEAN answer;
+ EnterCriticalSection(cs);
+ answer = (ringb_read_space(top.jack.ring.i.l) >= top.hold.size.bytes);
+ LeaveCriticalSection(cs);
+ return answer;
+}
+
+
+//------------------------------------------------------------------------
+
+PRIVATE void
+run_mute(void) {
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ memset((char *) top.hold.aux.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.aux.r, 0, top.hold.size.bytes);
+ uni.tick++;
+}
+
+PRIVATE void
+run_pass(void) { uni.tick++; }
+
+PRIVATE void
+run_play(void) {
+ process_samples(top.hold.buf.l, top.hold.buf.r,
+ top.hold.aux.l, top.hold.aux.r,
+ top.hold.size.frames);
+}
+
+// NB do not set RUN_SWCH directly via setRunState;
+// use setSWCH instead
+
+PRIVATE void
+run_swch(void) {
+ if (top.swch.bfct.have == 0) {
+ // first time
+ // apply ramp down
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) 1.0 - (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ memset((char *) (top.hold.buf.l + m), 0, n);
+ memset((char *) (top.hold.buf.r + m), 0, n);
+ top.swch.bfct.have++;
+ } else if (top.swch.bfct.have < top.swch.bfct.want) {
+ // in medias res
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ top.swch.bfct.have++;
+ } else {
+ // last time
+ // apply ramp up
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ uni.mode.trx = top.swch.trx.next;
+ switch (uni.mode.trx) {
+ int i;
+ case TX:
+ tx.agc.gen->over = tx.tick + 3;
+ break;
+ case RX:
+ for(i=0;i<uni.multirx.nrx;i++) rx[i].agc.gen->over = rx[i].tick + 3;
+ break;
+ }
+
+ top.state = top.swch.run.last;
+ top.swch.bfct.want = top.swch.bfct.have = 0;
+
+ ringb_reset(top.jack.ring.o.l);
+ ringb_reset(top.jack.ring.o.r);
+ ringb_clear(top.jack.ring.o.l,top.hold.size.bytes);
+ ringb_clear(top.jack.ring.o.r,top.hold.size.bytes);
+
+ reset_meters();
+ reset_spectrum();
+ reset_counters();
+ }
+
+ process_samples(top.hold.buf.l, top.hold.buf.r,
+ top.hold.aux.l, top.hold.aux.r,
+ top.hold.size.frames);
+}
+
+//========================================================================
+
+
+
+DttSP_EXP void
+audio_callback(float *input_l, float *input_r, float *output_l, float *output_r,int nframes) {
+ size_t nbytes = sizeof(float)*nframes;
+
+
+ EnterCriticalSection(cs);
+
+
+ if (ringb_read_space(top.jack.ring.o.l) >= nbytes) {
+ ringb_read(top.jack.ring.o.l, (char *) output_l, nbytes);
+ ringb_read(top.jack.ring.o.r, (char *) output_r, nbytes);
+ } else { // rb pathology
+ memset((char *) output_l, 0, nbytes);
+ memset((char *) output_r, 0, nbytes);
+ ringb_restart(top.jack.ring.o.l, nbytes);
+ ringb_restart(top.jack.ring.o.r, nbytes);
+ top.jack.blow.rb.o++;
+ }
+
+ // input: copy from port to ring
+ if (ringb_write_space(top.jack.ring.i.l) >= nbytes) {
+ ringb_write(top.jack.ring.i.l, (char *) input_l, nbytes);
+ ringb_write(top.jack.ring.i.r, (char *) input_r, nbytes);
+ ringb_write(top.jack.auxr.i.l, (char *) input_l, nbytes);
+ ringb_write(top.jack.auxr.i.r, (char *) input_r, nbytes);
+ } else { // rb pathology
+ ringb_restart(top.jack.ring.i.l, nbytes);
+ ringb_restart(top.jack.ring.i.r, nbytes);
+ ringb_restart(top.jack.auxr.i.l, nbytes);
+ ringb_restart(top.jack.auxr.i.r, nbytes);
+ top.jack.blow.rb.i++;
+ }
+ LeaveCriticalSection(cs);
+ // if enough accumulated in ring, fire dsp
+ if (ringb_read_space(top.jack.ring.i.l) >= top.hold.size.bytes)
+ sem_post(&top.sync.buf.sem);
+
+ // check for blowups
+ if ((top.jack.blow.cb > 0) ||
+ (top.jack.blow.rb.i > 0) ||
+ (top.jack.blow.rb.o > 0))
+ sem_post(&top.sync.mon.sem);
+}
+
+//========================================================================
+
+DttSP_EXP void
+process_samples_thread(void) {
+ while (top.running) {
+ sem_wait(&top.sync.buf.sem);
+ do {
+ gethold();
+ sem_wait(&top.sync.upd.sem);
+ switch (top.state) {
+ case RUN_MUTE: run_mute(); break;
+ case RUN_PASS: run_pass(); break;
+ case RUN_PLAY: run_play(); break;
+ case RUN_SWCH: run_swch(); break;
+ }
+ sem_post(&top.sync.upd.sem);
+ } while (canhold());
+ }
+}
+
+
+void
+closeup(void) {
+ top.running = FALSE;
+ Sleep(50);
+ safefree((char *)top.jack.ring.o.r);
+ safefree((char *)top.jack.ring.o.l);
+ safefree((char *)top.jack.ring.i.r);
+ safefree((char *)top.jack.ring.i.l);
+ safefree((char *)top.jack.auxr.i.l);
+ safefree((char *)top.jack.auxr.i.r);
+ safefree((char *)top.jack.auxr.o.l);
+ safefree((char *)top.jack.auxr.o.r);
+
+ CloseHandle(top.parm.fp);
+ DisconnectNamedPipe(top.parm.fd);
+ CloseHandle(top.parm.fd);
+
+
+ if (uni.meter.flag) {
+ CloseHandle(top.meas.mtr.fp);
+ DisconnectNamedPipe(top.meas.mtr.fd);
+ CloseHandle(top.meas.mtr.fd);
+ };
+
+ if (uni.spec.flag) {
+ CloseHandle(top.meas.spec.fp);
+ DisconnectNamedPipe(top.meas.spec.fd);
+ CloseHandle(top.meas.spec.fd);
+ };
+ destroy_workspace();
+}
+
+//........................................................................
+
+PRIVATE void
+setup_switching(void) {
+ top.swch.fade = (int) (0.1 * uni.buflen + 0.5);
+ top.swch.tail = (top.hold.size.frames - top.swch.fade) * sizeof(float);
+}
+
+PRIVATE void
+setup_local_audio(void) {
+ top.hold.size.frames = uni.buflen;
+ top.hold.size.bytes = top.hold.size.frames * sizeof(float);
+ top.hold.buf.l = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer left");
+ top.hold.buf.r = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer right");
+ top.hold.aux.l = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "aux hold buffer left");
+ top.hold.aux.r = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "aux hold buffer right");
+}
+
+#include <lmerr.h>
+
+PRIVATE void
+DisplayErrorText(DWORD dwLastError)
+{
+ HMODULE hModule = NULL; // default to system source
+ LPSTR MessageBuffer;
+ DWORD dwBufferLength;
+
+ DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_SYSTEM ;
+
+ //
+ // If dwLastError is in the network range,
+ // load the message source.
+ //
+
+ if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
+ hModule = LoadLibraryEx(
+ TEXT("netmsg.dll"),
+ NULL,
+ LOAD_LIBRARY_AS_DATAFILE
+ );
+
+ if(hModule != NULL)
+ dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
+ }
+
+ //
+ // Call FormatMessage() to allow for message
+ // text to be acquired from the system
+ // or from the supplied module handle.
+ //
+
+ if(dwBufferLength = FormatMessageA(
+ dwFormatFlags,
+ hModule, // module to get message from (NULL == system)
+ dwLastError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
+ (LPSTR) &MessageBuffer,
+ 0,
+ NULL
+ ))
+ {
+ DWORD dwBytesWritten;
+
+ //
+ // Output message string on stderr.
+ //
+ WriteFile(
+ GetStdHandle(STD_ERROR_HANDLE),
+ MessageBuffer,
+ dwBufferLength,
+ &dwBytesWritten,
+ NULL
+ );
+
+ //
+ // Free the buffer allocated by the system.
+ //
+ LocalFree(MessageBuffer);
+ }
+
+ //
+ // If we loaded a message source, unload it.
+ //
+ if(hModule != NULL)
+ FreeLibrary(hModule);
+}
+
+
+
+PRIVATE sem_t setup_update_sem;
+
+PRIVATE void setup_update_server()
+{
+
+ if (INVALID_HANDLE_VALUE == (top.parm.fd = CreateNamedPipe(top.parm.path,
+ PIPE_ACCESS_INBOUND,
+ PIPE_WAIT|PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE,
+ PIPE_UNLIMITED_INSTANCES,
+ 512,
+ 512,
+ INFINITE,
+ NULL)))
+ {
+ fprintf(stderr,"Update server pipe setup failed:\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+// fprintf(stderr,"Update NamedPipe made\n"),fflush(stderr);
+ sem_post(&setup_update_sem);
+ if (ConnectNamedPipe(top.parm.fd,NULL))
+ {
+// fprintf(stderr,"Connected the server to the Update pipe\n"),fflush(stderr);
+ } else {
+ fprintf(stderr,"Connected the server to the Update pipe failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ pthread_exit(0);
+}
+
+
+PRIVATE void setup_update_client()
+{
+// fprintf(stderr,"Looking for the Update server\n"),fflush(stderr);
+ WaitNamedPipe(top.parm.path,INFINITE);
+// fprintf(stderr,"Found the Update server\n"),fflush(stderr);
+ if (INVALID_HANDLE_VALUE == (top.parm.fp = CreateFile(top.parm.path,
+ GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)))
+ {
+ fprintf(stderr,"The Update Client Open Failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ sem_post(&setup_update_sem);
+/* {
+ DWORD numwritten;
+ WriteFile(top.parm.fp,"test",5,&numwritten,NULL);
+ fprintf(stderr,"Number written to server: %lu\n",numwritten),fflush(stderr);
+ }*/
+ pthread_exit(0);
+}
+
+PRIVATE void setup_meter_server()
+{
+ top.meas.mtr.fd = CreateNamedPipe(top.meas.mtr.path,
+ PIPE_ACCESS_OUTBOUND,
+ PIPE_WAIT|PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE,
+ PIPE_UNLIMITED_INSTANCES,
+ 512,
+ 512,
+ INFINITE,
+ NULL);
+// fprintf(stderr,"meter handle = %08X\n",(DWORD)top.meas.mtr.fd),fflush(stderr);
+ if (top.meas.mtr.fd == INVALID_HANDLE_VALUE)
+ {
+ fprintf(stderr,"Meter server pipe setup failed:\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"Meter Pipe Connect succeeded\n"),fflush(stderr);
+ sem_post(&setup_update_sem);
+ if (ConnectNamedPipe(top.meas.mtr.fd,NULL)) {
+// fprintf(stderr,"Connected the Meter Pooch\n"),fflush(stderr);
+ } else {
+ fprintf(stderr,"Meter Pipe Connect failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ }
+ pthread_exit(0);
+}
+
+PRIVATE void setup_meter_client()
+{
+// fprintf(stderr,"Looking for the meter server\n"),fflush(stderr);
+ if (WaitNamedPipe(top.meas.mtr.path,INFINITE)) {
+// fprintf(stderr,"Found the Meter server\n"),fflush(stderr);
+ if (INVALID_HANDLE_VALUE == (top.meas.mtr.fp = CreateFile(top.meas.mtr.path,
+ GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)))
+ {
+ fprintf(stderr,"The Meter Client Open Failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"The Meter Client Open Succeeded\n"),fflush(stderr);
+ }
+ } else {
+ fprintf(stderr,"Wait for meter pipe failed: Error message %d\n",GetLastError()),fflush(stderr);
+ }
+ sem_post(&setup_update_sem);
+ pthread_exit(0);
+}
+
+PRIVATE void setup_spec_server()
+{
+
+ if (INVALID_HANDLE_VALUE == (top.meas.spec.fd = CreateNamedPipe(top.meas.spec.path,
+ PIPE_ACCESS_OUTBOUND,
+ PIPE_WAIT|PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE,
+ PIPE_UNLIMITED_INSTANCES,
+ 32768,
+ 32768,
+ INFINITE,
+ NULL)))
+ {
+ fprintf(stderr,"Spectrum pipe create failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"Spectrum Pipe %s Create succeeded\n",top.meas.spec.path),fflush(stderr);
+ sem_post(&setup_update_sem);
+ if (ConnectNamedPipe(top.meas.spec.fd,NULL))
+ {
+// fprintf(stderr,"Connected to the Spectrum Pipe\n"),fflush(stderr);
+ } else {
+ fprintf(stderr,"Spectrum pipe connect failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ }
+ pthread_exit(0);
+}
+
+PRIVATE void setup_spec_client()
+{
+// fprintf(stderr,"Looking for the spectrum server\n"),fflush(stderr);
+ if (WaitNamedPipe(top.meas.spec.path,INFINITE)) {
+// fprintf(stderr,"Found the server\n"),fflush(stderr);
+ if (INVALID_HANDLE_VALUE == (top.meas.spec.fp = CreateFile(top.meas.spec.path,
+ GENERIC_READ, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)))
+ {
+ fprintf(stderr,"The Spectrum Client Open Failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } else {
+// fprintf(stderr,"The Spectrum Client Open Succeeded\n");
+// fprintf(stderr,"Spec Read handle = %08X\n",(DWORD)top.meas.spec.fp),fflush(stderr);
+ }
+ } else {
+ fprintf(stderr,"Wait for spec pipe failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ sem_post(&setup_update_sem);
+ pthread_exit(0);
+}
+PRIVATE pthread_t id1,id2,id3,id4,id5,id6;
+PRIVATE void
+setup_updates(void) {
+
+ char mesg[16384]="TEST TEST METER\n";
+// DWORD NumBytes;
+ top.parm.path = loc.path.parm;
+ sem_init(&setup_update_sem, 0, 0);
+
+
+ if (uni.meter.flag) {
+ top.meas.mtr.path = loc.path.meter;
+ }
+ if (uni.spec.flag) {
+ top.meas.spec.path = loc.path.spec;
+ }
+
+
+ // Do this STUPID stuff to make use of the Named Pipe Mechanism in Windows
+ // For the update server
+
+
+ pthread_create(&id1, NULL, (void *) setup_update_server, NULL);
+ sem_wait(&setup_update_sem);
+ pthread_create(&id2, NULL, (void *) setup_update_client, NULL);
+ sem_wait(&setup_update_sem);
+ if (uni.meter.flag) {
+ pthread_create(&id3, NULL, (void *) setup_meter_server, NULL);
+ sem_wait(&setup_update_sem);
+ pthread_create(&id4, NULL, (void *) setup_meter_client, NULL);
+ sem_wait(&setup_update_sem);
+/* if (WriteFile(top.meas.mtr.fd,mesg,strlen(mesg)+1,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Meter Pipe write succeeded and wrote %lu bytes\n",NumBytes),fflush(stderr);
+ } else {
+ fprintf(stderr,"Meter Pipe write failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ if (ReadFile(top.meas.mtr.fp,mesg,256,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Meter Pipe read succeeded and %lu bytes read\n",NumBytes),fflush(stderr);
+ fprintf(stderr,"Meter message %s",mesg),fflush(stderr);
+ } else {
+ fprintf(stderr,"Meter Pipe read failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }*/
+
+ }
+
+ if (uni.spec.flag) {
+ memset(mesg,0,16384);
+ pthread_create(&id5, NULL, (void *) setup_spec_server, NULL);
+ sem_wait(&setup_update_sem);
+ pthread_create(&id6, NULL, (void *) setup_spec_client, NULL);
+ sem_wait(&setup_update_sem);
+ Sleep(0);
+/* if (WriteFile(top.meas.spec.fd,mesg,16384,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Spec Pipe write succeeded and wrote %lu bytes\n",NumBytes),fflush(stderr);
+ } else {
+ fprintf(stderr,"Spec Pipe write failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ }
+ fprintf(stderr,"Spec Read handle(2) = %08X\n",(DWORD)top.meas.spec.fp),fflush(stderr);
+ if (ReadFile(top.meas.spec.fp,mesg,16384,&NumBytes,NULL))
+ {
+ fprintf(stderr,"Spec Pipe read succeeded and %lu bytes read\n",NumBytes),fflush(stderr);
+ } else {
+ fprintf(stderr,"Spec Pipe read failed\n"),fflush(stderr);
+ DisplayErrorText(GetLastError());
+ } */
+ }
+ sem_destroy(&setup_update_sem);
+}
+PRIVATE void
+setup_system_audio(void) {
+ size_t ringsize;
+ void *usemem;
+ sprintf(top.jack.name, "sdr-%d", top.pid);
+ top.jack.size = uni.buflen;
+ ringsize = top.hold.size.bytes * loc.mult.ring+sizeof(ringb_t);
+ usemem = safealloc(ringsize,1,"Ring Input Left");
+ top.jack.ring.i.l = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize,1,"Ring Input Right");
+ top.jack.ring.i.r = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize,1,"Ring Output Left");
+ top.jack.ring.o.l = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize,1,"Ring Output Right");
+ top.jack.ring.o.r = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize,1,"Ring Input Left Auxiliary");
+ top.jack.auxr.i.l = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize,1,"Ring Input Right Auxiliary");
+ top.jack.auxr.i.r = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize,1,"Ring Output Left Auxiliary");
+ top.jack.auxr.o.l = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ usemem = safealloc(ringsize,1,"Ring Output Right Auxiliary");
+ top.jack.auxr.o.r = ringb_create(usemem,top.hold.size.bytes * loc.mult.ring);
+
+ ringb_clear(top.jack.ring.o.l, top.jack.size * sizeof(float));
+ ringb_clear(top.jack.ring.o.r, top.jack.size * sizeof(float));
+ ringb_clear(top.jack.auxr.o.l, top.jack.size * sizeof(float));
+ ringb_clear(top.jack.auxr.o.r, top.jack.size * sizeof(float));
+}
+
+PRIVATE void
+setup_threading(void) {
+ sem_init(&top.sync.upd.sem, 0, 0);
+ pthread_create(&top.thrd.upd.id, NULL, (void *) process_updates_thread, NULL);
+ sem_init(&top.sync.buf.sem, 0, 0);
+ pthread_create(&top.thrd.trx.id, NULL, (void *) process_samples_thread, NULL);
+ sem_init(&top.sync.mon.sem, 0, 0);
+ pthread_create(&top.thrd.mon.id, NULL, (void *) monitor_thread, NULL);
+ if (uni.meter.flag) {
+ sem_init(&top.sync.mtr.sem, 0, 0);
+ pthread_create(&top.thrd.mtr.id, NULL, (void *) meter_thread, NULL);
+ }
+ if (uni.spec.flag) {
+ sem_init(&top.sync.pws.sem, 0, 0);
+ pthread_create(&top.thrd.pws.id, NULL, (void *) spectrum_thread, NULL);
+ }
+ cs = &csobj;
+ InitializeCriticalSection(cs);
+}
+
+//========================================================================
+// hard defaults, then environment
+
+PRIVATE void
+setup_defaults(void) {
+ loc.name[0] = 0; // no default name for jack client
+ strcpy(loc.path.rcfile, RCBASE);
+ strcpy(loc.path.parm, PARMPATH);
+ strcpy(loc.path.meter, METERPATH);
+ strcpy(loc.path.spec, SPECPATH);
+ strcpy(loc.path.wisdom, WISDOMPATH);
+ loc.def.rate = DEFRATE;
+ loc.def.size = DEFSIZE;
+ loc.def.nrx = MAXRX;
+ loc.def.mode = DEFMODE;
+ loc.def.spec = DEFSPEC;
+ loc.mult.ring = RINGMULT;
+}
+
+//========================================================================
+void
+setup() {
+
+
+ top.pid = GetCurrentThreadId();
+ top.uid = 0L;
+ top.start_tv = now_tv();
+ top.running = TRUE;
+ top.verbose = FALSE;
+ top.state = RUN_PLAY;
+
+ setup_defaults();
+ top.verbose = FALSE;
+ uni.meter.flag = TRUE;
+ uni.spec.flag = TRUE;
+
+ setup_workspace();
+ setup_updates();
+
+ setup_local_audio();
+ setup_system_audio();
+
+ setup_threading();
+ setup_switching();
+ uni.spec.flag = TRUE;
+ uni.spec.type = SPEC_POST_FILT;
+ uni.spec.scale = SPEC_PWR;
+ uni.spec.rxk = 0;
+
+}
+